/rarity-masterwork

Masterwork is a continuation of Rarity Manifested, a d20srd reference implementation codified in solidity https://github.com/andrecronje/rarity

Primary LanguageSolidity

github-full

Masterwork is a new crafting level for Rarity players and builders. Like Rarity's first crafting level, masterwork contains a crafting station and a dungeon. Use the masterwork crafting station to create masterwork weapons, armor, and tools. Defeat monsters in the dungeon for loot that speeds up crafting at the crafting station.

Masterwork is an expansion of the original Rarity core created by Andre Cronje, et al in September 2021. It continues the vision of an open, free-to-mint, d20 implementation in solidity.

masterwork addresses

Name Address
rarity_adventure_2 0xCc60d735bc1cBE877E20212aD3A93F88Ef243c7B
rarity_adventure_2_uri 0x94C0FEe093Bd38e1ed5bf01aE89DBb12826aB9f4
rarity_masterwork_items 0x0aF7EC3f3d17890072771e713F5DBD27D9bBc074
rarity_masterwork_projects 0x969eB1901A205C3B9f299eAeB33861172f2e8165
rarity_masterwork_uri 0x44500332e00E57C1ee98A7BFa3bCa0e87D3273DC
rarity_crafting_materials_2 0x919a172339ffD5915686477e6Da5e0748DCf10ff
rarity_crafting_skills 0xc84275A99C01D0b6C1A63bD94d589e4A44a85DeD
rarity_equipment_2 0xB6Ee6A99d474a30C9C407E7f32a88fF82071FDC0

library addresses

Name Address
Attributes 0x6F222Fd2beC8105D0a843f5e0bbdc5dDD73a82b8
Combat 0xf6bDcA6D83567c3934d45c63Befa7F7A825A3F8f
Crafting 0x61e8FaF08f25C0154F4196D5AaC99e56fAB5Aed5
CraftingSkills 0xd181F8bCb765A4CF7390b87d296d2955F58d101B
Feats 0xED9750904Fee2731a0ad78a084781B56865269Bf
Monster 0xca050C0E5bC83Df0e1D0A5De14d0cEb44B0Dd7C9
Proficiency 0x0b009e55Cbed833E0b29FCdfb0AD85765C1177C1
Random 0x471a666dfcE27cbfa0895694858C3375828Dc35A
Rarity 0x8628684cc1DF8E986f2A3650eb77700b3995Ff79
Roll 0xbb20DEFd74e43667c2637fa39970f932c0d974f7
Skills 0xA749EF13D370F749c49295cD7E97f3aB5F2B024D
Summoner 0xb21f4E0B4E3f6F348eBE662489cE860dd8Fd3986

codex addresses

Name Address
base_random_2 0x165AD01B090BC91352AeA8cEF7513C63852797Ed
crafting_skills 0xa0B2508A25dc28D20C537b8E1798543AC437F669
items_armor_2 0xe2e659caC782EC2A1FF041A79185AAaAcdA336f2
items_armor_masterwork 0x763C2f6B31d0C695F7A6308a50E3f3107e65260c
items_tools 0xC3F59C8b7041285000F21D74485f6c70b21B5E92
items_tools_masterwork 0x291D890a0410Ac98512569330C2Ad4861dC6C822
items_weapons_2 0x48F177ED0B38efab35D6150659eDAeCEE234E802
items_weapons_masterwork 0x8834c3C74026468AE5d151bb77c2097E0184377e

So what?

Masterwork items are exceptional. They are made so well that you get a bonus when using them.

βš” Masterwork weapons make you more accurate, granting a +1 bonus on all attacks. That is, you get a 10% better chance of hitting an Armor Class of 10, 5% better odds against AC 20, and so on.

πŸ›‘ Masterwork armor fits you perfectly, granting a +1 armor check bonus. This gives you better odds whenever your movement is in check, such as sneaking up on an opponent or climbing out of a trap.

πŸ›  Masterwork tools are just what you needed to get the job done. They grant various skill bonuses such as crafting and lock picking.

πŸ§™β€β™‚οΈ Masterwork crafting is the basis for magic weapons and armor. Magic weapons and armor grant even more bonuses such as extra damage and improved armor class. Magic Crafting, coming soon..

πŸ‘·β€β™€οΈ The Rarity Core Library was created to support Masterwork. The core library contains everything you need to create your own on-chain d20 adventures in Solidity.

πŸ‘Ή Nice!!

Now what?

This repo contains all source code and tooling used to build and test Masterwork. Use it as a reference or template for integrating masterwork and other d20 mechanics with your game.

Contents

Get started

git clone git@github.com:murderteeth/rarity-masterwork.git
cd rarity-masterwork
# config local .env file
yarn
yarn hardhat compile
yarn test

Rarity Crafting 2 - Masterwork Weapons, Armor, and Tools

Masterwork items, like common items, are minted to your wallet as standard ERC721 tokens. Create masterwork items like this:

  • Start a masterwork project
  • Make craft checks until the project is complete
  • Claim the masterwork item

Walkthrough

  1. Starting a new masterwork project requires a payment in gold for raw materials. Approve the contract's apprentice to receive the fees like this:
const cost = await masterwork.projects.raw_materials_cost(
  baseType.weapon,
  weaponType.longsword
);
await gold.approve(summoner, await masterwork.projects.APPRENTICE(), cost);

Masterwork crafting also requires artisan's tools. You can use the masterwork crafting station to craft masterwork artisan's tools for a +2 bonus on craft checks. Until then, pay an extra 5gp to "rent" a set of common artisan tools:

let cost = await masterwork.projects.raw_materials_cost(
  baseType.weapon,
  weaponType.longsword
);
cost = cost.add(await masterwork.projects.COMMON_ARTISANS_TOOLS_RENTAL());
await gold.approve(summoner, await masterwork.projects.APPRENTICE(), cost);
  1. Next, start a project:
await masterwork.projects.start(summoner, baseType.weapon, weaponType.longsword, 0);

Or if you have masterwork artisan's tools, like this:

// first, approve masterwork to manage your artisan's tools
await masterwork.items.approve(masterwork.projects.address, toolsToken)
await masterwork.projects.start(summoner, baseType.weapon, weaponType.longsword, toolsToken)

Calling start does this

  • Transfer appropriate project costs, in gold, from summoner to masterwork.APPRENTICE()
  • Transfer your masterwork artisan's tools to the contract (optional)
  • Mints a new masterwork ERC721 token to your wallet representing the project

Get project status like this:

const project = await masterwork.projects.projects(projectToken);

At anytime you can cancel a project and reclaim your masterwork artisan's tools:

await masterwork.projects.cancel(projectToken);
  1. Start crafting:
// first, approve masterwork to spend your summoner's xp
await rarity.approve(masterwork.projects.address, summoner)
await masterwork.projects.craft(projectToken, 0)

To speed up crafting specify bonus materials. You get +1 to your craft score for every 20 mats:

// for a +4 bonus
await masterwork.projects.craft(projectToken, ethers.utils.parseEther('80'))

Calling craft does this

  • Compute a craft check for summoner
    • roll 1 d20
    • add summoner intelligence modifier
    • add summoner specialty crafting ranks appropriate for weapons or armor
    • or if crafting masterwork tools, add summoner base crafting skill ranks (no specialty required)
  • If the score is equal or higher the item's DC (difficulty class), the check succeeds and the score is added to the project's total progress in exchange for summoner's experience points. If your score is high enough to complete the project, summoner pays a prorated amount of XP. The XP cost of making a craft check is otherwise one day's work, or 250 XP.
  • If the craft check score is less than the item's DC, the check fails, no progress is made, and one day's XP is spent
  • Burn bonus mats

Check the progress of a project:

const [progress, masterworkItemCostInSilver] = await masterwork.projects.get_progress(
  projectToken
);
const percentDone = progress.div(masterworkItemCostInSilver);

Estimate a project's remaining XP cost:

const estimate = await masterwork.projects.estimate_remaining_xp_cost(
  projectToken,
  bonusMats
);
console.log("estimate", ethers.utils.formatEther(estimate));

Get a summoner's odds of succeeding the next craft check:

const [average_score, dc] = await masterwork.projects.get_craft_check_odds(
  projectToken,
  bonusMats
);
const odds = average_score / dc;
  1. When crafting is complete,project.complete, claim your masterwork item:
await masterwork.items.claim(projectToken)
  1. Reclaim your artisan's tools:
await masterwork.projects.reclaim_tools(projectToken)

Tracking craft events

Each craft attempt emits a Craft event containing the craft check result, spent mats, spent xp, and crafting progress.

Crafting Specializations

Masterwork weapons and armor require summoner's to take up specialized crafting skills. Specialization ranks are redeemable 1:1 for core skill ranks in crafting. The following specializations are available:

  • Alchemy (for future expansion, spellcasters only)
  • Armorsmithing
  • Bowmaking
  • Trapmaking (for future expansion)
  • Weaponsmithing

Specialized skills are managed with the rarity_crafting_skills contract which works like the existing core skills contract. For example, raise a summoner's weaponsmithing specialization like this:

const craftingSkills = await craftingSkills.get_skills(summoner);
craftingSkills[4] += 1;
await craftingSkills.set_skills(summoner, craftingSkills);

Masterwork Items Codex

You can craft masterwork versions of all the items found in the core weapons and armor codexes.

You can also craft the following masterwork tools, found in the masterwork tools codex:

Masterwork Artisan's Tools - These tools serve the same purpose as artisan's tools, but masterwork artisan's tools are the perfect tools for the job, so you get a +2 circumstance bonus on Craft checks made with them.

Masterwork Musical Instrument - A masterwork instrument grants a +2 circumstance bonus on Perform checks involving its use.

Masterwork Thieves Tools - This kit contains extra tools and tools of better make, which grant a +2 circumstance bonus on Disable Device and Open Lock checks.

Masterwork Multitool - This well-made item is the perfect tool for the job. It grants a +2 circumstance bonus on a related skill check (if any). Bonuses provided by multiple masterwork items used toward the same skill check do not stack.

A codex a common tools, codex-items-tools.sol, is also available for future expansion.

Crafting difficulty class

The initial difficulty of a masterwork project is just the DC of the common version of the item being crafted. This is called the "standard component". Once enough progress has been made at the standard component DC the difficulty increases to the masterwork component DC (which is always 20). When the difficulty goes up so does the amount of progress you make on each check.

Crafting progress

Most projects will require more than one craft check. As you make craft checks each score is aggregated into a total with this formula:

image

  • St = total score
  • Cs = the cost of a common version of the item being crafted, priced in silver
  • score = current craft score
  • DCs = the difficulty class of the item being crafted (aka, the standard component)
  • DCm = the difficulty class of the item's masterwork component (always 20)

Progress is then computed as the ratio of your total score to the cost of the masterwork item priced in silver:

image

Thus, a bonus to your craft skill doesn't just give you better odds on passing a craft check. A bonus also "speeds up" your project by adding more to your progress on each succesful roll.

Masterwork crafting mechanics

Masterwork adapts its crafting mechanics from the d20 rules below while also continuing ideas from the core common crafting contract. The mechanics have been set such that a level 6 crafter with maxed craft skills, and without supplying any bonus crafting mats, can complete a masterwork longsword for about 5 days of XP (one work week).

from d20, under Check

All crafts require artisan's tools to give the best chance of success. If improvised tools are used, the check is made with a -2 circumstance penalty. On the other hand, masterwork artisan's tools provide a +2 circumstance bonus on the check.

To determine how much time and money it takes to make an item, follow these steps.

  • Find the item's price. Put the price in silver pieces (1 gp = 10 sp).
  • Find the DC from the table below.
  • Pay one-third of the item's price for the cost of raw materials.
  • Make an appropriate Craft check representing one week's work. If the check succeeds, multiply your check result by the DC. If the result Γ— the DC equals the price of the item in sp, then you have completed the item. (If the result Γ— the DC equals double or triple the price of the item in silver pieces, then you've completed the task in one-half or one-third of the time. Other multiples of the DC reduce the time in the same manner.) If the result Γ— the DC doesn't equal the price, then it represents the progress you've made this week. Record the result and make a new Craft check for the next week. Each week, you make more progress until your total reaches the price of the item in silver pieces.

from d20, under Creating Masterwork Items

You can make a masterwork itemβ€”a weapon, suit of armor, shield, or tool that conveys a bonus on its use through its exceptional craftsmanship, not through being magical. To create a masterwork item, you create the masterwork component as if it were a separate item in addition to the standard item. The masterwork component has its own price (300 gp for a weapon or 150 gp for a suit of armor or a shield) and a Craft DC of 20. Once both the standard component and the masterwork component are completed, the masterwork item is finished.

Rarity Adventure 2 - Monsters in the Barn

Monsters in the Barn is a single player, turn-based combat encounter. The adventure begins outside a barn where monsters have been hording salvage. Choose a summoner, equip weapons and armor, enter the barn.. If you defeat the monsters, claim their salvage and use it to speed up crafting at the masterwork crafting station. If you loose, try again tomorrow. This adventure is minted to your wallet as a standard ERC721 token.

Challenge Rating

Monsters in the Barn is designed to be challenging for summoners level 1 through 9. Entering the barn initiates combat with up to 3 monsters. Summoners are matched against monsters having a CR (challenge rating) equal to their level or lower.

Walkthrough

  1. These monsters will be tough. Send strong summoners, equip them well. Masterwork includes the rarity_equipment_2 contract for equipping both common and masterwork weapons and armor. Equipment2 was adapted from Rarity Extended's equipment system, but only supports one weapon, armor, and a shield. Use it like this:
// first, approve the equipment contract to transfer your items
await masterwork.approve(equipment2.address, masterworkLongswordId)
await masterwork.approve(equipment2.address, masterworkFullPlateArmorId)
await masterwork.approve(equipment2.address, masterworkShieldId)

// equip each item, 1 = weapon, 2 = armor, 3 = shield
await equipment2.equip(summoner, 1, masterwork.address, masterworkLongswordId)
await equipment2.equip(summoner, 2, masterwork.address, masterworkFullPlateArmorId)
await equipment2.equip(summoner, 3, masterwork.address, masterworkShieldId)

Equipping an item transfers it into the equipment contract. When the item is unequipped, the item is returned to your wallet:

await equipment2.unequip(summoner, 1)
await equipment2.unequip(summoner, 2)
await equipment2.unequip(summoner, 3)

Players may also choose to fight unarmed and/or unarmored. This is only recommended for Monks, however, who receive attack and armor bonuses per d20.

  1. Start a new Monsters in the Barn adventure by calling start:
// first, approve adventure to manage your summoner
await rarity.approve(barnAdventure.address, summoner)
await barnAdventure.start(summoner)

Calling start does this

  • Transfer summoner to the adventure contract
  • Mints a new ERC721 token to your wallet representing the adventure

Get adventure status like this:

const adventure = await barnAdventure.adventures(adventureToken)

At anytime you can end the adventure and reclaim your summoner:

await barnAdventure.end(adventureToken)
  1. Enter the barn..
await barnAdventure.enter_dungeon(adventureToken)

Calling enter_dungeon does this

  • Randomly "mints" up to 3 monsters
  • Rolls initiative for the summoner and each monster
  • Orders the combatants by their initiative scores into a Turn Order
  • Starting at the top of the Turn Order, combatants take their turns until it's the summoner's turn

Enumerate the turn order like this:

const combatants[]
const combatantCount = await barnAdventure.adventures(token).monster_count + 1
for(let i = 0; i < combatantCount; i++) {
  combatants.push(await barnAdventure.turn_orders(adventureToken, i))
}

Get the summoner's turn order index like this:

const summonersTurn = await barnAdventure.summoners_turns(adventureToken)
  1. Attack! When it's your summoner's turn you can attack or flee. To attack, chose a target by their turn order index. For convenience, you can "auto target" monsters using a call to next_able_monster.
const target = await barnAdventure.next_able_monster(adventureToken)
await barnAdventure.attack(adventureToken, target)

Calling attack does this

  • Roll attack for the adventure's summoner
  • If the attack score is equal or higher the target monster's AC (armor class), the attack hits, and a damage roll is made
  • If the attack roll is a natural 20 (or within the equipped weapon's critical range), the attack is critical, and extra damage is rolled according to the weapon's critical multiplier
  • If the attack score is less than the monster's AC, the attack is a miss
  • If the target's hit points (HP) are brought below zero, the monster is dying and considered slain
  • If the summoner has no more attacks for the round, monsters take their turns until it's the summoner's next turn

Some monsters get more than one attack per round. The good news. Barbarians, fighters, paladins, and rangers also get extra attacks per round starting at level 6! The adventure contract keeps track of these attacks for you. To get the current attack number:

const attackCounter = await barnAdventure.attack_counters(adventureToken)

But generally, while combat is ongoing, it will always be the summoner's turn from the perspective of a contract client (as the monsters' moves are played automatically between summoner moves). So you can just call attack until combat is over:

await barnAdventure.is_combat_over(adventureToken)
  1. Ending combat - Combat ends automatically when either the summoner or all the monsters are below 0 hit points. Alternatively, you can also chose to flee:
await barnAdventure.flee(adventureToken)

Fleeing doesn't do anything special beside set the combat to over. But it's provided for narrative flavor and is reflected in the adventure token's URI. You can also simply end the entire adventure whenever you like.

  1. Victory !! To win the dungeon your summoner must defeat all the monsters. If you are victorious, run an optional search check for a loot bonus on the monsters' salvage:
await barnAdventure.search(adventureToken)

The search check goes like this

  • Roll 1 d20
  • Add summoner search skill ranks
  • +2 if the summoner has the investigator feat

If the score is greater or equal the adventure's search DC (20), you get a 15% bonus. If you roll a natural 20, you get a 20% bonus. Nice! Now you can end the adventure and claim your loot:

await barnAdventure.end(adventureToken)
await crafingMaterials2.claim(adventureToken)

Rarity Crafting Materials 2 - Barn salvage

Claim barn salvage mats for victory in the barn. These mats are redeemable at 10:1 against each monster's CR. That is, slaying a monster with CR 4 awards 40 mats. These mats are minted to your wallet as standard ERC20 tokens.

Tracking combat events

Each attack emits an Attack event containing attacker, defender, and attack results.

Combat mechanics

The mechanics of Monsters in the Barn follow d20 combat closely, but only cover the very basics. Future expansions will cover more advanced mechanics like movement, ranged weapons, spells, saving throws, conditions, and buffs. For more, check out d20 Combat.

Tired of killing rats?? Meet the monsters of the barn

An ad hoc monster codex is available in the library.

Rarity Core Library

Masterwork's crafting and dungeon mechanics are complex. For sanity's sake we started a rarity core solidity library to abstract everything a builder needs to create their own d20 adventures.

Consider the library's combat system. The combat system lets any character attack any other character using d20 rules to compute the outcome. It does this by requiring that each fighter be adapted to a standard Combatant struct. This allows the combat system to run d20 combat rules against a common interface and enables summoner vs monster and summoner vs summoner combat.. it also enables monster vs monster and, in theory, any nft vs any nft.

Check out the Combatant stuct:

struct Combatant {
  uint8 initiative_roll;
  int8 initiative_score;
  uint8 armor_class;
  int16 hit_points;
  address origin;
  uint256 token;
  int8[28] attacks;
}
  • initiative_roll/score - Determines turn order
  • armor_class - How difficult it is to hit this combatant
  • hit_points - How much damage can be taken
  • origin - Contract address that issues this combatant's underlying token
  • token - This combatant's underlying nft (eg, a Summoner Id)
  • attacks - An array containing all the combatant's attacks per round

The current attacks array can hold up to 4 attacks. Each attack has these properties:

  • attack_bonus
  • critical_modifier
  • critical_multiplier
  • damage_dice_count
  • damage_dice_sides
  • damage_modifier
  • damage_type

Helper functions for packing and unpacking the attacks array live in the Combat library.

Monsters in the Barn implements summoner vs monster combat. To adapt summoners and monsters to the Combatant struct it uses these two functions:

function summoner_combatant(
  uint256 summoner,
  Equipment.Slot[3] memory loadout
) public view returns (Combat.Combatant memory combatant) {
  (uint8 initiative_roll, int8 initiative_score) = Roll.initiative(
    summoner
  );

  Equipment.Slot memory weapon_slot = loadout[0];
  Equipment.Slot memory armor_slot = loadout[1];
  Equipment.Slot memory shield_slot = loadout[2];

  combatant.mint = address(0xce761D788DF608BD21bdd59d6f4B54b2e27F25Bb);
  combatant.token = summoner;
  combatant.initiative_roll = initiative_roll;
  combatant.initiative_score = initiative_score;
  combatant.hit_points = int16(uint16(hit_points(summoner)));
  combatant.armor_class = armor_class(summoner, armor_slot, shield_slot);
  combatant.attacks = attacks(
    summoner,
    weapon_slot,
    armor_slot,
    shield_slot
  );
}
function monster_combatant(
  uint256 token,
  address mint,
  Monster.MonsterCodex memory monster_codex
) public view returns (Combat.Combatant memory combatant) {
  (uint8 initiative_roll, int8 initiative_score) = Roll.initiative(
    token,
    Attributes.compute_modifier(monster_codex.abilities[1]),
    monster_codex.initiative_bonus
  );

  combatant.mint = mint;
  combatant.token = token;
  combatant.initiative_roll = initiative_roll;
  combatant.initiative_score = initiative_score;
  combatant.hit_points = standard_hit_points(monster_codex);
  combatant.armor_class = monster_codex.armor_class;
  combatant.attacks = monster_codex.attacks;
}

Note the use of the Equipment.Slot stuct and several functions from the Roll, Summoner, and Monster libraries to make adapting the Combatant struct easy. With those adapters in place Monsters in the Barn can run an attack like this:

(bool hit, uint8 roll, int8 score, uint8 critical_confirmation, uint8 damage, uint8 damage_type)
    = Combat.attack_combatant(attacker, defender, attack_number);

How to use masterwork items in your game

The key feature of a masterwork longsword is the +1 attack bonus it grants its wielder. Masterwork introduces a series of extensions to the original Rarity codexes that include these bonuses. In the simplest case, you can query an item's codex directly for a bonus like this:

int8 longsword_attack_bonus = masterwork_weapons_codex.get_attack_bonus(longswordToken);

Another option is to let the core library do it for you by using the Equipment.Slot and Combatant structs. This is how Monsters in the Barn is implemented.

For example, consider the Summoner library's preview function:

function preview(
  uint256 summoner,
  address weapon_mint,
  uint256 weapon_token,
  address armor_mint,
  uint256 armor_token,
  address shield_mint,
  uint256 shield_token
) public view returns (Combat.Combatant memory result) {
  Equipment.Slot memory weapon_slot = Equipment.Slot(
    weapon_mint,
    weapon_token
  );
  Equipment.Slot memory armor_slot = Equipment.Slot(
    armor_mint,
    armor_token
  );
  Equipment.Slot memory shield_slot = Equipment.Slot(
    shield_mint,
    shield_token
  );

  result.token = summoner;
  result.mint = address(Rarity.RARITY);
  result.hit_points = int16(uint16(hit_points(summoner)));
  result.armor_class = armor_class(summoner, armor_slot, shield_slot);
  result.attacks = attacks(
    summoner,
    weapon_slot,
    armor_slot,
    shield_slot
  );
}

The preview function can be used by a client to see the effects of equipping an item before actually equipping it. Clients can call preview like this:

const preview = await summonerLibrary.preview(
  fighter,
  longsword,
  crafting.masterwork.address,
  fullplate,
  crafting.common.address,
  0,
  ethers.constants.AddressZero
);
const fullPrimaryAttackBonus = unpackAttacks(preview.attacks)[0].attack_bonus;

unpackAttacks is a utility provided here.

codex-items-weapons-2 and codex-items-armor-2

Masterwork extends the original weapons and armor codexes to expose bonus effects. Several missing item descriptions were also filled in. And the "axe" in the original codex has been upgraded to the throwing axe described in d20. (That seemed like the original intention)

Testing

Unit tests

There's a few unit tests. Run them like this

yarn test

Acceptance test

The acceptance test is designed to run against a local hardhat network. The Easiest way to run it, start a console and run this

yarn start-fork

Then open another console and run these

yarn hardhat run scripts/deploy.ts --network localhost
yarn hardhat run scripts/acceptance-test/--1-train-your-party.ts --network localhost
yarn hardhat run scripts/acceptance-test/--2-craft-common-equipment.ts --network localhost
yarn hardhat run scripts/acceptance-test/--3-raid-the-barn.ts --network localhost
yarn hardhat run scripts/acceptance-test/--4-craft-masterwork-equipment.ts --network localhost
yarn hardhat run scripts/acceptance-test/--5-raid-the-barn-again.ts --network localhost

Package commands

yarn test
yarn test-fast
yarn report-gas
yarn random-uint256   # handy for generating random seeds
yarn size-contracts   # get compiled size of all the contracts

Hardhat customizations

This project uses hardhat for its solidity dev environment. The following customizations have been made.

Typechain

This project also uses typechain to generate typescript types for all the core contracts and libraries. Unfortunately the current typechain has a known name-colision problem when generating types across nested directories. A future release of typechain promises to fix this. For now, this project overrides hardhat's TASK_COMPILE_SOLIDITY_COMPILE_JOBS compile task and generates the typechain types manually as a workaround.

Interfaces

This project also includes a custom hardhat task that generates full interfaces on all contracts. The results are saved here. This can be run manually with:

yarn hardhat rarity-interfaces

Thank You πŸ‘ΉπŸ™

Please join me and say thanks to these great folks:

Hrunting

Hrunting is a table-top DM guru and has been advising on how to adapt d20 to solidity. Hrunting gave critical input on the design of Monsters in the Barn and was first to point out that Rarity needs a masterwork crafting level.

Homestead wrote the first draft of the masterwork dungeon and core library. This was a challenging task and Homestead delivered, contributing many insights in addition to code.

Patrician reviewed masterwork, challenged all the questionable choices, and provided actionable insights from a DM's perspective. He's also been great at raising awareness of both masterwork and Rarity as a whole.

Masterwork borrows some great ideas from Extended's Rarity Extended Lib. The Extended team also reviewed masterwork and has been providing invaluable guidance since Rarity started last year.

The Shuraba team also gave a review to masterwork. In addtion, they generously granted the project 1300 MST, no strings.