diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json old mode 100644 new mode 100755 index a7561f45..7b8cdbea --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,7 @@ // https://github.com/microsoft/vscode-dev-containers/tree/v0.202.5/containers/python-3 { "name": "Loot", - "image": "ghcr.io/bibliothecaforadventurers/loot:latest", + "image": "ghcr.io/bibliothecadao/loot:latest", // Set *default* container specific settings.json values on container create. "settings": { "python.pythonPath": "/usr/local/bin/python", @@ -32,11 +32,10 @@ // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "pip3 install --user -r requirements.txt", + "postCreateCommand": ". scripts/startup.sh", // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "root", "remoteEnv": { "CAIRO_PATH": "/workspaces/realms-contracts/lib/cairo_graphs/src:/workspaces/realms-contracts/lib/cairo_contracts/src:/workspaces/realms-contracts/lib/cairo_math_64x61/contracts:/workspaces/realms-contracts/lib/guild_contracts:${containerEnv:PATH}" - }, - // "postStartCommand": "bash /workspaces/realms-contracts/scripts/setup_cli_env.sh" + } } \ No newline at end of file diff --git a/.eslintignore b/.eslintignore old mode 100644 new mode 100755 diff --git a/.eslintrc.js b/.eslintrc.js old mode 100644 new mode 100755 diff --git a/.gitattributes b/.gitattributes old mode 100644 new mode 100755 diff --git a/.github/workflows/check-python-setup/action.yaml b/.github/workflows/check-python-setup/action.yaml old mode 100644 new mode 100755 diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml old mode 100644 new mode 100755 diff --git a/.github/workflows/docker_test.yaml b/.github/workflows/docker_test.yaml old mode 100644 new mode 100755 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/protostar-test.yaml b/.github/workflows/protostar-test.yaml old mode 100644 new mode 100755 diff --git a/.github/workflows/pytest-test.yaml b/.github/workflows/pytest-test.yaml old mode 100644 new mode 100755 diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.gitmodules b/.gitmodules old mode 100644 new mode 100755 diff --git a/.prettierignore b/.prettierignore old mode 100644 new mode 100755 diff --git a/.setup.js b/.setup.js old mode 100644 new mode 100755 diff --git a/.solhint.json b/.solhint.json old mode 100644 new mode 100755 diff --git a/.solhintignore b/.solhintignore old mode 100644 new mode 100755 diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 index d43f5f5e..a26b1f03 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,6 @@ ENV CAIRO_PATH=/loot/realms-contracts/lib/cairo_contracts/src WORKDIR /loot/realms-contracts/ RUN pip3 install realms_cli/ -RUN curl -L https://raw.githubusercontent.com/software-mansion/protostar/master/install.sh | bash +RUN curl -L https://raw.githubusercontent.com/software-mansion/protostar/master/install.sh | bash -s -- -v 0.8.1 RUN curl -L https://foundry.paradigm.xyz | bash RUN /root/.foundry/bin/foundryup diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index b6ce08b9..c50c8f3f --- a/README.md +++ b/README.md @@ -11,15 +11,13 @@

-![Realms x Bibliotheca header](/static/realmsxbibliotheca.jpg) # Realmverse Contracts ## Realms is an ever-expanding on-chain permission-less gaming Lootverse built on StarkNet. -### This monorepo contains all of the Contracts (StarkNet/Cairo Ethereum/Solidity) for Bibliotheca DAO, $LORDS, and Realms. +This monorepo contains all of the Contracts (StarkNet/Cairo Ethereum/Solidity) for Bibliotheca DAO, $LORDS, and Realms. ---- # Contracts | Directory | Title | Description | @@ -31,20 +29,20 @@ | [/nft_marketplace](./contracts/nft_marketplace/) | NFT Marketplace | A marketplace for Realms, Dungeons, etc. built on Starknet. | | [/lib/guild_contracts](./lib/guild_contracts/) | Guild Contracts | Contracts pulled from Guildly to allow shared player accounts. More info in [Guildly Repo](https://github.com/Guildly/contracts) | ---- + # Learn more about Realms -## Follow these steps bring a 🔦 +### Follow these steps bring a 🔦 -## 1. Visit the [Bibliotheca DAO Site](https://bibliothecadao.xyz/) for an overview of our ecosystem +1. Visit the [Bibliotheca DAO Site](https://bibliothecadao.xyz/) for an overview of our ecosystem -## 2. The [Master Scroll](https://scroll.bibliothecadao.xyz/). This is our deep dive into everything about the game. The Master Scroll is the source of truth before this readme +2. The [Master Scroll](https://scroll.bibliothecadao.xyz/). This is our deep dive into everything about the game. The Master Scroll is the source of truth before this readme -## 3. Visit [The Atlas](https://atlas.bibliothecadao.xyz/) to see the Settling game in action +3. Visit [The Atlas](https://atlas.bibliothecadao.xyz/) to see the Settling game in action + +4. Get involved at the [Realms x Bibliotheca Discord](https://discord.gg/uQnjZhZPfu) -## 4. Get involved at the [Realms x Bibliotheca Discord](https://discord.gg/uQnjZhZPfu) ---- # Development diff --git a/SECURITY.md b/SECURITY.md old mode 100644 new mode 100755 diff --git a/contracts/bridge/README.md b/contracts/bridge/README.md old mode 100644 new mode 100755 diff --git a/contracts/bridge/lords_l1.sol b/contracts/bridge/lords_l1.sol old mode 100644 new mode 100755 diff --git a/contracts/bridge/lords_l2.cairo b/contracts/bridge/lords_l2.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/01_TowerDefence.cairo b/contracts/desiege/01_TowerDefence.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/02_TowerDefenceStorage.cairo b/contracts/desiege/02_TowerDefenceStorage.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/03_GridMovement.cairo b/contracts/desiege/03_GridMovement.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/04_Elements.cairo b/contracts/desiege/04_Elements.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/DesiegeArbiter.cairo b/contracts/desiege/DesiegeArbiter.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/DesiegeModuleController.cairo b/contracts/desiege/DesiegeModuleController.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/DivineEclipseElements.cairo b/contracts/desiege/DivineEclipseElements.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/desiege.jpg b/contracts/desiege/desiege.jpg old mode 100644 new mode 100755 diff --git a/contracts/desiege/game_utils/game_structs.cairo b/contracts/desiege/game_utils/game_structs.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/game_utils/grid_position.cairo b/contracts/desiege/game_utils/grid_position.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/game_utils/grid_position_test.cairo b/contracts/desiege/game_utils/grid_position_test.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/tokens/ERC1155/ERC1155_Mintable_Ownable.cairo b/contracts/desiege/tokens/ERC1155/ERC1155_Mintable_Ownable.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/tokens/ERC1155/ERC1155_base.cairo b/contracts/desiege/tokens/ERC1155/ERC1155_base.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/tokens/ERC1155/IERC1155_Mintable_Ownable.cairo b/contracts/desiege/tokens/ERC1155/IERC1155_Mintable_Ownable.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/tokens/ERC1155/structs.cairo b/contracts/desiege/tokens/ERC1155/structs.cairo old mode 100644 new mode 100755 diff --git a/contracts/desiege/utils/interfaces.cairo b/contracts/desiege/utils/interfaces.cairo old mode 100644 new mode 100755 diff --git a/contracts/exchange/Exchange_ERC20_1155.cairo b/contracts/exchange/Exchange_ERC20_1155.cairo old mode 100644 new mode 100755 diff --git a/contracts/exchange/README.md b/contracts/exchange/README.md old mode 100644 new mode 100755 diff --git a/contracts/exchange/library.cairo b/contracts/exchange/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/ModuleController.cairo b/contracts/loot/ModuleController.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/adventurer/Adventurer.cairo b/contracts/loot/adventurer/Adventurer.cairo old mode 100644 new mode 100755 index fdc6a8f6..f4fd5614 --- a/contracts/loot/adventurer/Adventurer.cairo +++ b/contracts/loot/adventurer/Adventurer.cairo @@ -12,13 +12,26 @@ from starkware.cairo.common.alloc import alloc from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin -from starkware.cairo.common.uint256 import Uint256, uint256_add -from starkware.cairo.common.math import unsigned_div_rem, assert_not_equal, assert_not_zero +from starkware.cairo.common.uint256 import ( + Uint256, + uint256_add, + uint256_sub, + uint256_eq, + uint256_mul, + uint256_unsigned_div_rem +) +from starkware.cairo.common.math import ( + unsigned_div_rem, + assert_not_equal, + assert_not_zero, + assert_in_range, +) from starkware.cairo.common.math_cmp import is_le, is_not_zero from starkware.starknet.common.syscalls import ( get_caller_address, get_contract_address, get_block_timestamp, + get_block_number, ) from openzeppelin.access.ownable.library import Ownable @@ -35,22 +48,24 @@ from contracts.loot.adventurer.library import AdventurerLib from contracts.loot.adventurer.metadata import AdventurerUri from contracts.loot.constants.adventurer import ( Adventurer, + AdventurerSlotIds, AdventurerState, AdventurerStatic, AdventurerDynamic, PackedAdventurerState, AdventurerStatus, DiscoveryType, + ItemDiscoveryType, + KingState ) from contracts.loot.constants.beast import Beast +from contracts.loot.constants.obstacle import ObstacleUtils, ObstacleConstants from contracts.loot.interfaces.imodules import IModuleController from contracts.loot.loot.stats.combat import CombatStats from contracts.loot.utils.general import _uint_to_felt from contracts.loot.beast.interface import IBeast from contracts.loot.loot.ILoot import ILoot -from contracts.loot.utils.constants import ModuleIds, ExternalContractIds - -const MINT_COST = 50000000000000000000; +from contracts.loot.utils.constants import ModuleIds, ExternalContractIds, MINT_COST, STARTING_GOLD, KING_TRIBUTE_PERCENT // ----------------------------------- // Events @@ -86,13 +101,14 @@ func treasury_address() -> (address: felt) { } @storage_var -func adventurer(tokenId: Uint256) -> (adventurer: PackedAdventurerState) { +func adventurer_image(tokenId: Uint256) -> (image: felt) { } @storage_var -func adventurer_image(tokenId: Uint256) -> (image: felt) { +func king() -> (king: KingState) { } + // ----------------------------------- // Initialize & upgrade // ----------------------------------- @@ -147,7 +163,7 @@ func mint{ order: felt, image_hash_1: felt, image_hash_2: felt, -) { +) -> (adventurer_token_id: Uint256) { alloc_locals; let (controller) = Module.controller_address(); @@ -182,9 +198,45 @@ func mint{ // send to this contract and set Balance of Adventurer let (this) = get_contract_address(); IERC20.transferFrom(lords_address, caller, this, Uint256(MINT_COST, 0)); + // @distracteddev: this is now redundant, we can't take away balance every time tribute is distributed adventurer_balance.write(next_adventurer_id, Uint256(MINT_COST, 0)); - return (); + return (next_adventurer_id,); +} + +@external +func mint_with_starting_weapon{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}( + to: felt, + race: felt, + home_realm: felt, + name: felt, + order: felt, + image_hash_1: felt, + image_hash_2: felt, + weapon_id: felt, +) -> (adventurer_token_id: Uint256, item_token_id: Uint256) { + alloc_locals; + + // Mint new adventurer + let (adventurer_token_id) = mint(to, race, home_realm, name, order, image_hash_1, image_hash_2); + + // Mint starting weapon for the adventurer (book, wand, club, short sword) + let (loot_address) = Module.get_module_address(ModuleIds.Loot); + let (item_token_id) = ILoot.mint_starter_weapon( + loot_address, to, weapon_id, adventurer_token_id + ); + + // Equip the selected item to the adventurer + equip_item(adventurer_token_id, item_token_id); + + // add STARTING_GOLD to balance + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + IBeast.add_to_balance(beast_address, adventurer_token_id, STARTING_GOLD); + + // Return adventurer token id and item token id + return (adventurer_token_id, item_token_id); } // @notice Equip loot item to adventurer @@ -207,11 +259,14 @@ func equip_item{ let (loot_address) = Module.get_module_address(ModuleIds.Loot); // Get Item from Loot contract - let (item) = ILoot.getItemByTokenId(loot_address, item_token_id); + let (item) = ILoot.get_item_by_token_id(loot_address, item_token_id); assert item.Adventurer = 0; assert item.Bag = 0; + // Check item owned by Adventurer + assert_adventurer_is_owner(adventurer_token_id, item_token_id); + // Check item is owned by caller let (owner) = IERC721.ownerOf(loot_address, item_token_id); let (caller) = get_caller_address(); @@ -230,7 +285,7 @@ func equip_item{ let (adventurer_to_felt) = _uint_to_felt(adventurer_token_id); // Update item - ILoot.updateAdventurer(loot_address, item_token_id, adventurer_to_felt); + ILoot.update_adventurer(loot_address, item_token_id, adventurer_to_felt); emit_adventurer_state(adventurer_token_id); @@ -266,7 +321,7 @@ func unequip_item{ // Get Item from Loot contract let (loot_address) = Module.get_module_address(ModuleIds.Loot); - let (item) = ILoot.getItemByTokenId(loot_address, item_token_id); + let (item) = ILoot.get_item_by_token_id(loot_address, item_token_id); assert item.Adventurer = adventurer_token_id.low; @@ -286,7 +341,7 @@ func unequip_item{ adventurer_dynamic.write(adventurer_token_id, packed_new_adventurer); // Update item - ILoot.updateAdventurer(loot_address, item_token_id, 0); + ILoot.update_adventurer(loot_address, item_token_id, 0); emit_adventurer_state(adventurer_token_id); @@ -362,36 +417,72 @@ func deduct_health{ alloc_locals; Module.only_approved(); + _deduct_health(adventurer_token_id, amount); + return (TRUE,); +} + +// @notice Add health to adventurer +// @param adventurer_token_id: Id of adventurer +// @param amount: Health amount to add +// @return success: Value indicating success +@external +func add_health{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, amount: felt) -> (success: felt) { + alloc_locals; + + Module.only_approved(); + _add_health(adventurer_token_id, amount); + return (TRUE,); +} + +// @notice Increase xp of adventurer +// @param adventurer_token_id: Id of adventurer +// @param amount: Amount of xp to increase +// @return success: Value indicating success +@external +func increase_xp{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, amount: felt) -> (success: felt) { + alloc_locals; + + Module.only_approved(); + _increase_xp(adventurer_token_id, amount); + + return (TRUE,); +} + +// @notice Upgrade stat of adventurer +// @param adventurer_token_id: Id of adventurer +// @param amount: Amount of xp to increase +// @return success: Value indicating success +@external +func upgrade_stat{ + syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, stat: felt) -> (success: felt) { + alloc_locals; + // only adventurer owner can upgrade stat + ERC721.assert_only_token_owner(adventurer_token_id); // unpack adventurer let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data(unpacked_adventurer); + with_attr error_message("Adventurer: Adventurer must be upgradable") { + assert adventurer_dynamic_.Upgrading = TRUE; + } - // deduct health - let (new_adventurer) = AdventurerLib.deduct_health(amount, adventurer_dynamic_); + // check stat is upgradeable + assert_in_range(stat, AdventurerSlotIds.Strength, AdventurerSlotIds.Luck); - // if the adventurer is dead - if (new_adventurer.Health == 0) { - // transfer all their LORDS to the beast address - // TODO MILESTONE2: Figure out how to assign the LORDS tokens to the beast that killed the adventurer - let (lords_address) = Module.get_external_contract_address(ExternalContractIds.Lords); - let (beast_address) = Module.get_module_address(ModuleIds.Beast); - let (adventurer_balance_) = adventurer_balance.read(adventurer_token_id); - IERC20.transfer(lords_address, beast_address, adventurer_balance_); - adventurer_balance.write(adventurer_token_id, Uint256(0, 0)); + // upgrade stat + let (updated_stat_adventurer) = AdventurerLib.update_statistics(stat, adventurer_dynamic_); - tempvar syscall_ptr: felt* = syscall_ptr; - tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; - } else { - tempvar syscall_ptr: felt* = syscall_ptr; - tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; - } + // reset upgrading param + let (updated_upgrade_adventurer) = AdventurerLib.set_upgrading(FALSE, updated_stat_adventurer); - let (packed_new_adventurer: PackedAdventurerState) = AdventurerLib.pack(new_adventurer); + let (packed_new_adventurer: PackedAdventurerState) = AdventurerLib.pack( + updated_upgrade_adventurer + ); adventurer_dynamic.write(adventurer_token_id, packed_new_adventurer); emit_adventurer_state(adventurer_token_id); @@ -399,50 +490,37 @@ func deduct_health{ return (TRUE,); } -// @notice Increase xp of adventurer +// @notice Purchase health for gold // @param adventurer_token_id: Id of adventurer -// @param amount: Amount of xp to increase +// @param number: number of health potions to purchase // @return success: Value indicating success @external -func increase_xp{ - pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}(adventurer_token_id: Uint256, amount: felt) -> (success: felt) { +func purchase_health{ + syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, number: felt) -> (success: felt) { alloc_locals; - Module.only_approved(); + let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); + // only adventurer owner can purchase health + ERC721.assert_only_token_owner(adventurer_token_id); - // unpack adventurer + // check the adventurer can purchase health let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data(unpacked_adventurer); - // increase xp - let (updated_xp_adventurer) = AdventurerLib.increase_xp(amount, adventurer_dynamic_); + with_attr error_message("Adventurer: Must be idle") { + assert adventurer_dynamic_.Status = AdventurerStatus.Idle; + } - // check if the adventurer reached the next level - let (leveled_up) = CombatStats.check_for_level_increase( - updated_xp_adventurer.XP, updated_xp_adventurer.Level - ); + let (beast_address) = Module.get_module_address(ModuleIds.Beast); - // if it did - if (leveled_up == TRUE) { - // increase level - let (updated_level_adventurer) = AdventurerLib.update_level( - updated_xp_adventurer.Level + 1, updated_xp_adventurer - ); - let (packed_updated_adventurer: PackedAdventurerState) = AdventurerLib.pack( - updated_level_adventurer - ); - adventurer_dynamic.write(adventurer_token_id, packed_updated_adventurer); - emit_adventurer_leveled_up(adventurer_token_id); - return (TRUE,); - } else { - let (packed_updated_adventurer: PackedAdventurerState) = AdventurerLib.pack( - updated_xp_adventurer - ); - adventurer_dynamic.write(adventurer_token_id, packed_updated_adventurer); - emit_adventurer_state(adventurer_token_id); - return (TRUE,); - } + // health potion costs 5 gold + IBeast.subtract_from_balance(beast_address, adventurer_token_id, 5 * number); + + // health potion adds 10 health + _add_health(adventurer_token_id, 10 * number); + + return (TRUE,); } // @notice Explore for discoveries @@ -451,7 +529,7 @@ func increase_xp{ @external func explore{ pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}(token_id: Uint256) -> (success: felt) { +}(token_id: Uint256) -> (type: felt, id: felt) { alloc_locals; // only adventurer owner can explore @@ -473,17 +551,49 @@ func explore{ assert unpacked_adventurer.Beast = 0; } + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + + // If this is a newbie adventurer + if (unpacked_adventurer.Level == 1) { + // we set their status to battle + let (new_unpacked_adventurer) = AdventurerLib.update_status( + AdventurerStatus.Battle, adventurer_dynamic_ + ); + + // get weapon + let (item_address) = Module.get_module_address(ModuleIds.Loot); + let (weapon) = ILoot.get_item_by_token_id( + item_address, Uint256(unpacked_adventurer.WeaponId, 0) + ); + + // We give them an easy starting beast (will also have weak armor for their weapon) + let (starting_beast_id) = AdventurerLib.get_starting_beast_from_weapon(weapon.Id); + + // create beast according to the weapon the player has + let (beast_id: Uint256) = IBeast.create_starting_beast( + beast_address, token_id, starting_beast_id + ); + let (updated_adventurer) = AdventurerLib.assign_beast( + beast_id.low, new_unpacked_adventurer + ); + let (packed_adventurer) = AdventurerLib.pack(updated_adventurer); + + adventurer_dynamic.write(token_id, packed_adventurer); + + emit_adventurer_state(token_id); + + return (DiscoveryType.Beast, beast_id.low); + } + let (rnd) = get_random_number(); let (discovery) = AdventurerLib.get_random_discovery(rnd); - // If the adventurer encounter a beast if (discovery == DiscoveryType.Beast) { // we set their status to battle let (new_unpacked_adventurer) = AdventurerLib.update_status( AdventurerStatus.Battle, adventurer_dynamic_ ); // create beast - let (beast_address) = Module.get_module_address(ModuleIds.Beast); let (beast_id: Uint256) = IBeast.create(beast_address, token_id); let (updated_adventurer) = AdventurerLib.assign_beast( beast_id.low, new_unpacked_adventurer @@ -494,11 +604,155 @@ func explore{ emit_adventurer_state(token_id); - return (TRUE,); + return (DiscoveryType.Beast, beast_id.low); + } + + if (discovery == DiscoveryType.Obstacle) { + // TODO: Obstacle prefixes and greatness + // @distracteddev: Picked + let (rnd) = get_random_number(); + let (obstacle) = ObstacleUtils.generate_random_obstacle(unpacked_adventurer, rnd); + let (item_address) = Module.get_module_address(ModuleIds.Loot); + // @distracteddev: Should be get equipped item by slot not get item by Id + let (item_id) = AdventurerLib.get_item_id_at_slot(obstacle.DamageLocation, adventurer_dynamic_); + let (armor) = ILoot.get_item_by_token_id(item_address, Uint256(item_id, 0)); + let (obstacle_damage) = CombatStats.calculate_damage_from_obstacle(obstacle, armor); + _deduct_health(token_id, obstacle_damage); + return (DiscoveryType.Obstacle, obstacle.Id); + } + if (discovery == DiscoveryType.Item) { + // generate another random 4 numbers + // this could probably be better + let (rnd) = get_random_number(); + let (discovery) = AdventurerLib.get_random_discovery(rnd); + + if (discovery == ItemDiscoveryType.Gold) { + // add GOLD + // @distracteddev: formula - 1 + (rnd % 4) + let (rnd) = get_random_number(); + let (gold_discovery) = AdventurerLib.calculate_gold_discovery(rnd); + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + IBeast.add_to_balance(beast_address, token_id, gold_discovery); + emit_adventurer_state(token_id); + return (DiscoveryType.Item, ItemDiscoveryType.Gold); + } + if (discovery == ItemDiscoveryType.XP) { + // add XP + // @distracteddev: formula - 10 + (5 * (rnd % 4)) + let (rnd) = get_random_number(); + let (xp_discovery) = AdventurerLib.calculate_xp_discovery(rnd); + _increase_xp(token_id, xp_discovery); + return (DiscoveryType.Item, ItemDiscoveryType.XP); + } + if (discovery == ItemDiscoveryType.Loot) { + // mint loot items + let (loot_address) = Module.get_module_address(ModuleIds.Loot); + let (owner) = owner_of(token_id); + ILoot.mint(loot_address, owner, token_id); + emit_adventurer_state(token_id); + return (DiscoveryType.Item, ItemDiscoveryType.Loot); + } + if (discovery == ItemDiscoveryType.Health) { + // add health + // @distracteddev: formula - 10 + (5 * (rnd % 4)) + let (rnd) = get_random_number(); + let (health_discovery) = AdventurerLib.calculate_health_discovery(rnd); + _add_health(token_id, health_discovery); + return (DiscoveryType.Item, ItemDiscoveryType.Health); + } + + // send item + return (DiscoveryType.Item, 0); + } + + return (FALSE, 0); +} + +// @notice Become the king +// @param adventurer_token_id: Id of adventurer +// @return success: Value indicating success +@external +func become_king{ + syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256) -> (success: felt) { + alloc_locals; + + // only adventurer owner can explore + ERC721.assert_only_token_owner(adventurer_token_id); + + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + + // unpack adventurer + let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); + + let (gold_balance) = IBeast.balance_of(beast_address, adventurer_token_id); + + let (king_state) = king.read(); + + let (king_balance) = IBeast.balance_of(beast_address, king_state.AdventurerId); + + // same as less than + let over_king_check = is_le(king_balance + 1, gold_balance); + + with_attr error_message("Adventurer: Gold balance is not the highest.") { + assert over_king_check = TRUE; } + let (current_time) = get_block_timestamp(); + + let new_king = KingState(adventurer_token_id, current_time); + + king.write(new_king); + return (TRUE,); } + +// @notice Pay tribute to the king +// @return success: Value indicating success +@external +func pay_king_tribute{ + syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> (success: felt){ + alloc_locals; + // Anyone can call this function to check king payout (potential for keepers) + let (king_state) = king.read(); + + let (current_time) = get_block_timestamp(); + + let time_duration = current_time - king_state.StartTime; + + // 12 hours = 60 * 60 * 12 = 43200 seconds + + let check_over_duration = is_le(43200, time_duration); + + with_attr error_message("Adventurer: King not active for 12 hours.") { + assert check_over_duration = TRUE; + } + + // lords + let (lords_address) = Module.get_external_contract_address(ExternalContractIds.Lords); + let (this) = get_contract_address(); + + // calculate tribute + let (total_lords) = IERC20.balanceOf(lords_address, this); + let (pre_tribute, _) = uint256_mul(Uint256(KING_TRIBUTE_PERCENT,0), total_lords); + let (king_tribute, _) = uint256_unsigned_div_rem(pre_tribute, Uint256(100, 0)); + + // send to king adventurer owner + let (owner: felt) = ERC721.owner_of(king_state.AdventurerId); + IERC20.transfer(lords_address, owner, king_tribute); + + // Reset king timer + let new_king_state = KingState( + king_state.AdventurerId, + current_time + ); + + king.write(new_king_state); + + return (TRUE,); +} + // ----------------------------- // Internal Adventurer Specific // ----------------------------- @@ -517,6 +771,21 @@ func assert_not_dead{ return (); } +// @notice Revert if adventurer is not item owner +// @param adventurer_token_id: Id of adventurer +// @param itemId: Id of the item +func assert_adventurer_is_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + adventurer_token_id: Uint256, itemId: Uint256 +) { + alloc_locals; + let (loot_address) = Module.get_module_address(ModuleIds.Loot); + let (owner) = ILoot.item_owner(loot_address, itemId, adventurer_token_id); + with_attr error_message("Adventurer: Adventurer is not item owner") { + assert owner = TRUE; + } + return (); +} + // @notice Get xoroshiro random number // @return dice_roll: Xoroshiro random number func get_random_number{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}() -> ( @@ -524,10 +793,12 @@ func get_random_number{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBu ) { alloc_locals; + let (block) = get_block_number(); + let (controller) = Module.controller_address(); let (xoroshiro_address_) = IModuleController.get_xoroshiro(controller); let (rnd) = IXoroshiro.next(xoroshiro_address_); - return (rnd,); + return (rnd * block,); } // @notice Emit state of adventurer @@ -578,6 +849,14 @@ func get_adventurer_by_id{ return (adventurer,); } +// @notice Get king state +// @return king: State of the king +@view +func get_king{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}() -> (king_state: KingState) { + let (king_state) = king.read(); + return (king_state,); +} + // -------------------- // Base ERC721 Functions // -------------------- @@ -599,7 +878,7 @@ func tokenByIndex{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_pt } @view -func tokenOfOwnerByIndex{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( +func token_of_owner_by_index{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( owner: felt, index: Uint256 ) -> (adventurer_token_id: Uint256) { let (adventurer_token_id: Uint256) = ERC721Enumerable.token_of_owner_by_index(owner, index); @@ -627,7 +906,7 @@ func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() - } @view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( +func balance_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( balance: Uint256 ) { let (balance: Uint256) = ERC721.balance_of(owner); @@ -635,7 +914,7 @@ func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( } @view -func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( +func owner_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( adventurer_token_id: Uint256 ) -> (owner: felt) { let (owner: felt) = ERC721.owner_of(adventurer_token_id); @@ -724,3 +1003,139 @@ func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_che Ownable.renounce_ownership(); return (); } + +// +// INTERNAL +// + +func _deduct_health{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, amount: felt) -> (success: felt) { + alloc_locals; + + // unpack adventurer + let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); + let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data(unpacked_adventurer); + + // deduct health + let (new_adventurer) = AdventurerLib.deduct_health(amount, adventurer_dynamic_); + + // if the adventurer is dead + if (new_adventurer.Health == 0) { + // transfer all their LORDS to the beast address + // TODO MILESTONE2: Figure out how to assign the LORDS tokens to the beast that killed the adventurer + let (lords_address) = Module.get_external_contract_address(ExternalContractIds.Lords); + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + let (adventurer_balance_) = adventurer_balance.read(adventurer_token_id); + // IERC20.transfer(lords_address, beast_address, adventurer_balance_); + adventurer_balance.write(adventurer_token_id, Uint256(0, 0)); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; + } + + let (packed_new_adventurer: PackedAdventurerState) = AdventurerLib.pack(new_adventurer); + adventurer_dynamic.write(adventurer_token_id, packed_new_adventurer); + + emit_adventurer_state(adventurer_token_id); + + return (TRUE,); +} + +func _increase_xp{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, amount: felt) -> (success: felt) { + alloc_locals; + + // unpack adventurer + let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); + let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data(unpacked_adventurer); + + // increase xp + let (updated_xp_adventurer) = AdventurerLib.increase_xp(amount, adventurer_dynamic_); + + // check if the adventurer reached the next level + let (leveled_up) = CombatStats.check_for_level_increase( + updated_xp_adventurer.XP, updated_xp_adventurer.Level + ); + + // if it did + if (leveled_up == TRUE) { + // increase level + let (updated_level_adventurer) = AdventurerLib.update_level( + updated_xp_adventurer.Level + 1, updated_xp_adventurer + ); + // allow adventurer to choose a stat to upgrade + let (updated_upgrading_adventurer) = AdventurerLib.set_upgrading( + TRUE, updated_level_adventurer + ); + let (packed_updated_adventurer: PackedAdventurerState) = AdventurerLib.pack( + updated_upgrading_adventurer + ); + adventurer_dynamic.write(adventurer_token_id, packed_updated_adventurer); + emit_adventurer_leveled_up(adventurer_token_id); + return (TRUE,); + } else { + let (packed_updated_adventurer: PackedAdventurerState) = AdventurerLib.pack( + updated_xp_adventurer + ); + adventurer_dynamic.write(adventurer_token_id, packed_updated_adventurer); + emit_adventurer_state(adventurer_token_id); + return (TRUE,); + } +} + +func _add_health{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, amount: felt) -> (success: felt) { + alloc_locals; + + // unpack adventurer + let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); + let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data(unpacked_adventurer); + + let check_health_over_100 = is_le(100, adventurer_dynamic_.Health + amount); + + // cap health at 100 + if (check_health_over_100 == TRUE) { + let add_amount = 100 - adventurer_dynamic_.Health; + let (new_adventurer) = AdventurerLib.add_health(add_amount, adventurer_dynamic_); + let (packed_new_adventurer: PackedAdventurerState) = AdventurerLib.pack(new_adventurer); + adventurer_dynamic.write(adventurer_token_id, packed_new_adventurer); + emit_adventurer_state(adventurer_token_id); + return (TRUE,); + } else { + let (new_adventurer) = AdventurerLib.add_health(amount, adventurer_dynamic_); + let (packed_new_adventurer: PackedAdventurerState) = AdventurerLib.pack(new_adventurer); + adventurer_dynamic.write(adventurer_token_id, packed_new_adventurer); + emit_adventurer_state(adventurer_token_id); + return (TRUE,); + } +} + +func _set_upgradable{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_token_id: Uint256, upgradable: felt) { + alloc_locals; + + // unpack adventurer + let (unpacked_adventurer) = get_adventurer_by_id(adventurer_token_id); + let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data(unpacked_adventurer); + + // set upgrading + let (updated_adventurer) = AdventurerLib.set_upgrading(upgradable, adventurer_dynamic_); + + let (packed_new_adventurer: PackedAdventurerState) = AdventurerLib.pack(updated_adventurer); + adventurer_dynamic.write(adventurer_token_id, packed_new_adventurer); + + emit_adventurer_state(adventurer_token_id); + + return (); +} diff --git a/contracts/loot/adventurer/interface.cairo b/contracts/loot/adventurer/interface.cairo old mode 100644 new mode 100755 index 02394bbb..3a8f75bb --- a/contracts/loot/adventurer/interface.cairo +++ b/contracts/loot/adventurer/interface.cairo @@ -6,7 +6,7 @@ from contracts.loot.constants.adventurer import AdventurerState @contract_interface namespace IAdventurer { - func ownerOf(tokenId: Uint256) -> (owner: felt) { + func owner_of(tokenId: Uint256) -> (owner: felt) { } func get_adventurer_by_id(tokenId: Uint256) -> (adventurer: AdventurerState) { } diff --git a/contracts/loot/adventurer/library.cairo b/contracts/loot/adventurer/library.cairo old mode 100644 new mode 100755 index c8d56367..40992947 --- a/contracts/loot/adventurer/library.cairo +++ b/contracts/loot/adventurer/library.cairo @@ -8,10 +8,10 @@ from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.math import unsigned_div_rem, assert_not_zero, assert_le, assert_nn from starkware.starknet.common.syscalls import get_block_timestamp -from starkware.cairo.common.uint256 import Uint256 -from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.uint256 import Uint256, uint256_mul, uint256_unsigned_div_rem from starkware.cairo.common.math_cmp import is_le, is_not_zero from starkware.cairo.common.registers import get_label_location from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc @@ -35,12 +35,14 @@ from contracts.loot.constants.adventurer import ( DiscoveryType, ) -from contracts.loot.constants.item import Item +from contracts.loot.constants.obstacle import ObstacleUtils +from contracts.loot.constants.item import Item, ItemIds, Slot from contracts.settling_game.utils.general import unpack_data from contracts.settling_game.utils.constants import SHIFT_41 -from contracts.loot.constants.beast import Beast +from contracts.loot.constants.beast import Beast, BeastIds from contracts.loot.loot.stats.combat import CombatStats + namespace AdventurerLib { func birth{syscall_ptr: felt*, range_check_ptr}( race: felt, @@ -88,6 +90,7 @@ namespace AdventurerLib { let Status = AdventurerStatus.Idle; let Beast = 0; + let Upgrading = 0; return ( AdventurerStatic( @@ -120,6 +123,7 @@ namespace AdventurerLib { RingId=RingId, Status=Status, Beast=Beast, + Upgrading=Upgrading, ), ); } @@ -155,6 +159,7 @@ namespace AdventurerLib { adventurer_dynamic.RingId, adventurer_dynamic.Status, adventurer_dynamic.Beast, + adventurer_dynamic.Upgrading, ); return (adventurer,); @@ -194,6 +199,7 @@ namespace AdventurerLib { adventurer.RingId, adventurer.Status, adventurer.Beast, + adventurer.Upgrading, ); return (adventurer_static, adventurer_dynamic); @@ -236,6 +242,7 @@ namespace AdventurerLib { let Status = unpacked_adventurer_state.Status * SHIFT_P_4._1; let Beast = unpacked_adventurer_state.Beast * SHIFT_P_4._2; + let Upgrading = unpacked_adventurer_state.Upgrading * SHIFT_P_4._3; // packing // let p1 = XP + Luck + Charisma + Wisdom + Intelligence + Vitality + Dexterity + Strength + Level + Health; @@ -245,7 +252,7 @@ namespace AdventurerLib { let p2 = Weapon + Chest + Head + Waist; // let p3 = Ring + Neck + Hands + Feet; let p3 = Feet + Hands + Neck + Ring; - let p4 = Status + Beast; + let p4 = Status + Beast + Upgrading; let packedAdventurer = PackedAdventurerState(p1, p2, p3, p4); @@ -295,6 +302,7 @@ namespace AdventurerLib { // ---------- p4 ---------# let (Status) = unpack_data(packed_adventurer.p4, 0, 7); // 3 let (Beast) = unpack_data(packed_adventurer.p4, 3, 2199023255551); // 41 + let (Upgrading) = unpack_data(packed_adventurer.p4, 44, 1); // 1 return ( AdventurerDynamic( @@ -318,6 +326,7 @@ namespace AdventurerLib { RingId=RingId, Status=Status, Beast=Beast, + Upgrading=Upgrading, ), ); } @@ -368,6 +377,39 @@ namespace AdventurerLib { return (updated_adventurer,); } + func get_item_id_at_slot{syscall_ptr: felt*, range_check_ptr}( + slot: felt, unpacked_adventurer: AdventurerDynamic + ) -> (item_token_id: felt) { + alloc_locals; + + if (slot == Slot.Weapon) { + return (unpacked_adventurer.WeaponId,); + } + if (slot == Slot.Chest) { + return (unpacked_adventurer.ChestId,); + } + if (slot == Slot.Head) { + return (unpacked_adventurer.HeadId,); + } + if (slot == Slot.Waist) { + return (unpacked_adventurer.WaistId,); + } + if (slot == Slot.Foot) { + return (unpacked_adventurer.FeetId,); + } + if (slot == Slot.Hand) { + return (unpacked_adventurer.HandsId,); + } + if (slot == Slot.Neck) { + return (unpacked_adventurer.NeckId,); + } + if (slot == Slot.Ring) { + return (unpacked_adventurer.RingId,); + } + + return (0,); + } + func deduct_health{syscall_ptr: felt*, range_check_ptr}( damage: felt, unpacked_adventurer: AdventurerDynamic ) -> (new_unpacked_adventurer: AdventurerDynamic) { @@ -392,6 +434,20 @@ namespace AdventurerLib { return (updated_adventurer,); } + // loaf + func add_health{syscall_ptr: felt*, range_check_ptr}( + health: felt, unpacked_adventurer: AdventurerDynamic + ) -> (new_unpacked_adventurer: AdventurerDynamic) { + alloc_locals; + + // set new health to previous health - damage dealt + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Health, unpacked_adventurer.Health + health, unpacked_adventurer + ); + + return (updated_adventurer,); + } + func increase_xp{syscall_ptr: felt*, range_check_ptr}( xp: felt, unpacked_adventurer: AdventurerDynamic ) -> (new_unpacked_adventurer: AdventurerDynamic) { @@ -475,14 +531,117 @@ namespace AdventurerLib { } func update_statistics{syscall_ptr: felt*, range_check_ptr}( - item_token_id: felt, item: Item, unpacked_adventurer: AdventurerDynamic + stat: felt, unpacked_adventurer: AdventurerDynamic ) -> (new_unpacked_adventurer: AdventurerDynamic) { alloc_locals; - // cast state into felt array - // make adjustment to felt at index - // cast back into adventuerState + if (stat == AdventurerSlotIds.Strength) { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Strength, unpacked_adventurer.Strength + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } + if (stat == AdventurerSlotIds.Dexterity) { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Dexterity, unpacked_adventurer.Dexterity + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } + if (stat == AdventurerSlotIds.Vitality) { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Vitality, unpacked_adventurer.Vitality + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } + if (stat == AdventurerSlotIds.Intelligence) { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Intelligence, unpacked_adventurer.Intelligence + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } + if (stat == AdventurerSlotIds.Wisdom) { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Wisdom, unpacked_adventurer.Wisdom + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } + if (stat == AdventurerSlotIds.Charisma) { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Charisma, unpacked_adventurer.Charisma + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } else { + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Luck, unpacked_adventurer.Luck + 1, unpacked_adventurer + ); + return (updated_adventurer,); + } + } + + func set_upgrading{syscall_ptr: felt*, range_check_ptr}( + upgrading: felt, unpacked_adventurer: AdventurerDynamic + ) -> (new_unpacked_adventurer: AdventurerDynamic) { + + // set upgrade status + let (updated_adventurer: AdventurerDynamic) = cast_state( + AdventurerSlotIds.Upgrading, upgrading, unpacked_adventurer + ); + + return (updated_adventurer,); + } + + func calculate_gold_discovery{syscall_ptr: felt*, range_check_ptr}( + rnd: felt + ) -> (gold_discovery: felt) { + + let (_, discover_multi) = unsigned_div_rem(rnd, 4); + + let gold_discovery = 1 + discover_multi; + + return (gold_discovery,); + } + + func calculate_health_discovery{syscall_ptr: felt*, range_check_ptr}( + rnd: felt + ) -> (health_discovery: felt) { + let (_, discover_multi) = unsigned_div_rem(rnd, 4); + + let health_discovery = 10 + (5 * discover_multi); + + return (health_discovery,); + } + + func calculate_xp_discovery{syscall_ptr: felt*, range_check_ptr}( + rnd: felt + ) -> (xp_discovery: felt) { + let (_, discover_multi) = unsigned_div_rem(rnd, 4); + + let xp_discovery = 10 + (5 * discover_multi); + return (xp_discovery,); + } + + func get_starting_beast_from_weapon{syscall_ptr: felt*, range_check_ptr}( + weapon_id: felt + ) -> (beast_id: felt) { + + if (weapon_id == ItemIds.ShortSword) { + return(BeastIds.Golem,); + } + if (weapon_id == ItemIds.Book) { + return(BeastIds.Ogre,); + } + if (weapon_id == ItemIds.Wand) { + return(BeastIds.Ogre,); + } + if (weapon_id == ItemIds.Club) { + return(BeastIds.Rat,); + } return (0,); } + + func calculate_king_tribute{syscall_ptr: felt*, range_check_ptr}( + tribute_percent: felt, total_balance: Uint256 + ) -> (king_tribute: Uint256) { + } } diff --git a/contracts/loot/adventurer/metadata.cairo b/contracts/loot/adventurer/metadata.cairo old mode 100644 new mode 100755 index ef8e546a..6110246e --- a/contracts/loot/adventurer/metadata.cairo +++ b/contracts/loot/adventurer/metadata.cairo @@ -116,10 +116,12 @@ namespace AdventurerUriUtils { const Griffin = 'Griffin'; const Minotaur = 'Minotaur'; const Basilisk = 'Basilisk'; + const Gnome = 'Gnome'; const Wraith = 'Wraith'; const Ghoul = 'Ghoul'; const Goblin = 'Goblin'; const Skeleton = 'Skeleton'; + const Golem = 'Golem'; const Giant = 'Giant'; const Yeti = 'Yeti'; const Orc = 'Orc'; @@ -147,28 +149,28 @@ namespace AdventurerUri { ) -> (encoded_len: felt, encoded: felt*) { alloc_locals; - let (weapon_item: Item) = ILoot.getItemByTokenId( + let (weapon_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.WeaponId, 0) ); - let (chest_item: Item) = ILoot.getItemByTokenId( + let (chest_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.ChestId, 0) ); - let (head_item: Item) = ILoot.getItemByTokenId( + let (head_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.HeadId, 0) ); - let (waist_item: Item) = ILoot.getItemByTokenId( + let (waist_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.WaistId, 0) ); - let (feet_item: Item) = ILoot.getItemByTokenId( + let (feet_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.FeetId, 0) ); - let (hands_item: Item) = ILoot.getItemByTokenId( + let (hands_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.HandsId, 0) ); - let (neck_item: Item) = ILoot.getItemByTokenId( + let (neck_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.NeckId, 0) ); - let (ring_item: Item) = ILoot.getItemByTokenId( + let (ring_item: Item) = ILoot.get_item_by_token_id( item_address, Uint256(adventurer_data.RingId, 0) ); @@ -976,6 +978,9 @@ namespace AdventurerUri { if (beast == BeastIds.Basilisk) { assert values[values_index + 2] = AdventurerUriUtils.Beast.Basilisk; } + if (beast == BeastIds.Gnome) { + assert values[values_index + 2] = AdventurerUriUtils.Beast.Gnome; + } if (beast == BeastIds.Wraith) { assert values[values_index + 2] = AdventurerUriUtils.Beast.Wraith; } @@ -988,6 +993,9 @@ namespace AdventurerUri { if (beast == BeastIds.Skeleton) { assert values[values_index + 2] = AdventurerUriUtils.Beast.Skeleton; } + if (beast == BeastIds.Golem) { + assert values[values_index + 2] = AdventurerUriUtils.Beast.Golem; + } if (beast == BeastIds.Giant) { assert values[values_index + 2] = AdventurerUriUtils.Beast.Giant; } diff --git a/contracts/loot/beast/Beast.cairo b/contracts/loot/beast/Beast.cairo old mode 100644 new mode 100755 index abdedf29..cdccd7a7 --- a/contracts/loot/beast/Beast.cairo +++ b/contracts/loot/beast/Beast.cairo @@ -9,10 +9,19 @@ %lang starknet from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin -from starkware.cairo.common.math import unsigned_div_rem, assert_not_zero, assert_not_equal +from starkware.cairo.common.math import ( + unsigned_div_rem, + assert_not_zero, + assert_not_equal, + assert_nn, +) from starkware.cairo.common.math_cmp import is_le, is_not_zero from starkware.cairo.common.uint256 import Uint256, uint256_add, uint256_eq -from starkware.starknet.common.syscalls import get_caller_address, get_block_timestamp +from starkware.starknet.common.syscalls import ( + get_caller_address, + get_block_number, + get_block_timestamp, +) from openzeppelin.upgrades.library import Proxy from openzeppelin.token.erc721.enumerable.library import ERC721Enumerable @@ -29,7 +38,7 @@ from contracts.loot.constants.adventurer import ( AdventurerStatus, AdventurerSlotIds, ) -from contracts.loot.constants.beast import Beast, BeastStatic, BeastDynamic +from contracts.loot.constants.beast import Beast, BeastStatic, BeastDynamic, BeastIds from contracts.loot.interfaces.imodules import IModuleController from contracts.loot.loot.ILoot import ILoot from contracts.loot.loot.stats.combat import CombatStats @@ -103,15 +112,58 @@ func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( func create{ pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* }(adventurer_id: Uint256) -> (beast_token_id: Uint256) { + alloc_locals; Module.only_approved(); - let (rnd) = get_random_number(); - let (beast_static_, beast_dynamic_) = BeastLib.create(rnd, adventurer_id.low); + + let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); + let (adventurer_state) = IAdventurer.get_adventurer_by_id(adventurer_address, adventurer_id); + + let (random) = get_random_number(); + let (_, beast_level_boost) = unsigned_div_rem(random, 6); + let (_, beast_health_boost) = unsigned_div_rem(random, 30); + let (_, beast_id) = unsigned_div_rem(random, BeastIds.MAX_ID); + + let (beast_static_, beast_dynamic_) = BeastLib.create( + beast_id, adventurer_id.low, adventurer_state, beast_level_boost, beast_health_boost + ); + + return _create(beast_static_, beast_dynamic_); +} + +@external +func create_starting_beast{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(adventurer_id: Uint256, beast_id: felt) -> (beast_token_id: Uint256) { + alloc_locals; + Module.only_approved(); + + let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); + let (adventurer_state) = IAdventurer.get_adventurer_by_id(adventurer_address, adventurer_id); + + let (beast_static_, beast_dynamic_) = BeastLib.create_start_beast( + beast_id, adventurer_id.low, adventurer_state + ); + + return _create(beast_static_, beast_dynamic_); +} + +func _create{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(beast_static_: BeastStatic, beast_dynamic_: BeastDynamic) -> (beast_token_id: Uint256) { + alloc_locals; + let (packed_beast) = BeastLib.pack(beast_dynamic_); + let (current_id) = total_supply.read(); + let (next_id, _) = uint256_add(current_id, Uint256(1, 0)); + beast_static.write(next_id, beast_static_); + beast_dynamic.write(next_id, packed_beast); + total_supply.write(next_id); + return (next_id,); } @@ -142,8 +194,13 @@ func attack{ // calculate damage let (item_address) = Module.get_module_address(ModuleIds.Loot); - let (weapon) = ILoot.getItemByTokenId(item_address, Uint256(unpacked_adventurer.WeaponId, 0)); - let (damage_dealt) = CombatStats.calculate_damage_to_beast(beast, weapon); + let (weapon) = ILoot.get_item_by_token_id( + item_address, Uint256(unpacked_adventurer.WeaponId, 0) + ); + let (rnd) = get_random_number(); + let (damage_dealt) = CombatStats.calculate_damage_to_beast( + beast, weapon, unpacked_adventurer, rnd + ); // deduct health from beast let (beast_static_, beast_dynamic_) = BeastLib.split_data(beast); let (updated_health_beast) = BeastLib.deduct_health(damage_dealt, beast_dynamic_); @@ -154,11 +211,24 @@ func attack{ // check if beast is still alive after the attack let beast_is_alive = is_not_zero(updated_health_beast.Health); - // if the beast is alive + // if the beast is alive, it automatically counter attacks if (beast_is_alive == TRUE) { - // having been attacked, it automatically attacks back - let (chest) = ILoot.getItemByTokenId(item_address, Uint256(unpacked_adventurer.ChestId, 0)); - let (damage_taken) = CombatStats.calculate_damage_from_beast(beast, chest); + // get the location the beast attacks + let (beast_attack_location) = BeastStats.get_attack_location_from_id(beast.Id); + + let (rnd) = get_random_number(); + + // get the armor the adventurer is wearing at the location the beast attacks + // @distracteddev: Should be get equipped item by slot not get item by Id + let (adventurer_static_, adventurer_dynamic_) = AdventurerLib.split_data( + unpacked_adventurer + ); + let (item_id) = AdventurerLib.get_item_id_at_slot( + beast_attack_location, adventurer_dynamic_ + ); + let (armor) = ILoot.get_item_by_token_id(item_address, Uint256(item_id, 0)); + let (damage_taken) = CombatStats.calculate_damage_from_beast(beast, armor, rnd); + IAdventurer.deduct_health(adventurer_address, adventurer_id, damage_taken); // check if beast counter attack killed adventurer @@ -168,7 +238,7 @@ func attack{ // calculate xp earned from killing adventurer (adventurers are rank 1) let (xp_gained) = CombatStats.calculate_xp_earned(1, updated_adventurer.Level); // increase beast xp and writes - increase_xp(beast_token_id, updated_health_beast, xp_gained); + _increase_xp(beast_token_id, updated_health_beast, xp_gained); tempvar syscall_ptr: felt* = syscall_ptr; tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; tempvar range_check_ptr = range_check_ptr; @@ -186,12 +256,51 @@ func attack{ let (current_time) = get_block_timestamp(); let (slain_updated_beast) = BeastLib.slay(current_time, updated_health_beast); - // grant adventurer xp + // calculate earned XP let (beast_level) = BeastLib.calculate_greatness(slain_updated_beast.Level); let (beast_rank) = BeastStats.get_rank_from_id(beast.Id); - let (xp_gained) = CombatStats.calculate_xp_earned(beast_rank, beast_level); + // if the adventurer is level 1 we give them 10 XP to get them to level 2 after defeating their first beast + if (unpacked_adventurer.Level == 1) { + tempvar xp_gained = 10; + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; + // after level 1 XP earned is based on beast rank and level + } else { + let (xp_gained) = CombatStats.calculate_xp_earned(beast_rank, beast_level); + tempvar xp_gained = xp_gained; + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; + } + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; + + tempvar xp_gained = xp_gained; + // give xp to adventurer IAdventurer.increase_xp(adventurer_address, adventurer_id, xp_gained); + + // and to items + _allocate_xp_to_items(item_address, unpacked_adventurer, xp_gained); + + // drop gold + // @distracteddev: add randomness to reward + // formula: (xp_gained - (xp_gained / 4)) + ((xp_gained / 4) * (rand % 4)) + let (rnd) = get_random_number(); + let (gold_reward) = BeastLib.calculate_gold_reward(rnd, xp_gained); + _add_to_balance(adventurer_id, gold_reward); + + IAdventurer.update_status( + adventurer_address, Uint256(beast.Adventurer, 0), AdventurerStatus.Idle + ); + IAdventurer.assign_beast(adventurer_address, Uint256(beast.Adventurer, 0), 0); + return (damage_dealt, 0); } } @@ -220,6 +329,9 @@ func counter_attack{ // get beast from token id let (beast) = get_beast_by_id(beast_token_id); + // get the location this beast attacks + let (beast_attack_location) = BeastStats.get_attack_location_from_id(beast.Id); + // get the adventurer token id associated with the beast let adventurer_token_id = Uint256(beast.Adventurer, 0); @@ -231,10 +343,15 @@ func counter_attack{ // retreive unpacked adventurer let (unpacked_adventurer) = get_adventurer_from_beast(beast_token_id); - let (chest) = ILoot.getItemByTokenId(item_address, Uint256(unpacked_adventurer.ChestId, 0)); - let (damage_taken) = CombatStats.calculate_damage_from_beast(beast, chest); + // get the armor the adventurer has at the armor slot the beast is attacking + let (armor) = ILoot.get_item_by_token_id(item_address, Uint256(beast_attack_location, 0)); + let (rnd) = get_random_number(); + let (damage_taken) = CombatStats.calculate_damage_from_beast(beast, armor, rnd); + + // deduct heatlh from adventurer IAdventurer.deduct_health(adventurer_address, adventurer_token_id, damage_taken); + // check if beast counter attack killed adventurer let (updated_adventurer) = get_adventurer_from_beast(beast_token_id); // if the adventurer is dead @@ -243,7 +360,7 @@ func counter_attack{ let (xp_gained) = CombatStats.calculate_xp_earned(1, updated_adventurer.Level); // increase beast xp and writes let (_, beast_dynamic_) = BeastLib.split_data(beast); - increase_xp(beast_token_id, beast_dynamic_, xp_gained); + _increase_xp(beast_token_id, beast_dynamic_, xp_gained); tempvar syscall_ptr: felt* = syscall_ptr; tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; @@ -261,11 +378,10 @@ func counter_attack{ // @notice Flee adventurer from beast // @param beast_token_id: Id of beast -// TODO: return boolean to indicate if user was able to flee @external func flee{ pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}(beast_token_id: Uint256) { +}(beast_token_id: Uint256) -> (fled: felt) { alloc_locals; let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); @@ -286,19 +402,20 @@ func flee{ // TODO: We need a function to calculate the weight of all the adventurer equipment let weight_of_equipment = 0; - // TODO: Wrap this with overflow protection let adventurer_speed = unpacked_adventurer.Dexterity - weight_of_equipment; - - // Adventurer ambush resistance is based on wisdom plus luck - let ambush_resistance = unpacked_adventurer.Wisdom + unpacked_adventurer.Luck; + assert_nn(adventurer_speed); let (rnd) = get_random_number(); - let (ambush_chance) = BeastLib.get_random_ambush(rnd); // TODO Milestone2: Factor in beast health for the ambush chance and for flee chance // Short-term (while we are using rng) would be to base rng on beast health. The // lower the beast health, the lower the chance it will ambush and the easier // it will be to flee. + // @distracteddev: simple calculation, random: (0,1) * (health/50): (0, 1, 2) + let (ambush_chance) = BeastLib.calculate_ambush_chance(rnd, beast.Health); + + // Adventurer ambush resistance is based on wisdom plus luck + let ambush_resistance = unpacked_adventurer.Wisdom + unpacked_adventurer.Luck; // adventurer is ambushed if their ambush resistance is less than random number let is_ambushed = is_le(ambush_chance, ambush_resistance); @@ -307,19 +424,30 @@ func flee{ // unless ambush occurs if (is_ambushed == TRUE) { - let (chest) = ILoot.getItemByTokenId(item_address, Uint256(unpacked_adventurer.ChestId, 0)); - // then calculate damage based on beast - let (damage_taken) = CombatStats.calculate_damage_from_beast(beast, chest); + // get the location the beast attacks + let (beast_attack_location) = BeastStats.get_attack_location_from_id(beast.Id); + + // get the armor the adventurer is wearing at the location the beast attacks + let (armor) = ILoot.get_item_by_token_id(item_address, Uint256(beast_attack_location, 0)); + + let (damage_rnd) = get_random_number(); + + // calculate damage taken from beast + let (damage_taken) = CombatStats.calculate_damage_from_beast(beast, armor, damage_rnd); + + // update adventurer health IAdventurer.deduct_health(adventurer_address, Uint256(beast.Adventurer, 0), damage_taken); + // check if beast counter attack killed adventurer let (updated_adventurer) = get_adventurer_from_beast(beast_token_id); + // if the adventurer is dead if (updated_adventurer.Health == 0) { // calculate xp earned from killing adventurer (adventurers are rank 1) let (xp_gained) = CombatStats.calculate_xp_earned(1, updated_adventurer.Level); // increase beast xp and writes let (_, beast_dynamic_) = BeastLib.split_data(beast); - increase_xp(beast_token_id, beast_dynamic_, xp_gained); + _increase_xp(beast_token_id, beast_dynamic_, xp_gained); tempvar syscall_ptr: felt* = syscall_ptr; tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; @@ -342,20 +470,20 @@ func flee{ tempvar range_check_ptr = range_check_ptr; tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; } + tempvar bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; // TODO: MILESTONE2 Use Beast Speed Stats - let (flee_chance) = BeastLib.get_random_flee(rnd); + let (flee_rnd) = get_random_number(); + let (flee_chance) = BeastLib.get_random_flee(flee_rnd); let can_flee = is_le(adventurer_speed + 1, flee_chance); if (can_flee == TRUE) { IAdventurer.update_status( adventurer_address, Uint256(beast.Adventurer, 0), AdventurerStatus.Idle ); IAdventurer.assign_beast(adventurer_address, Uint256(beast.Adventurer, 0), 0); - // adventurer was able to flee - return (); + return (TRUE,); } else { - // adventurer was not able to flee - return (); + return (FALSE,); } } @@ -396,6 +524,16 @@ func increase_xp{ Module.only_approved(); + return _increase_xp(beast_token_id, beast_dynamic_, amount); +} + +func _increase_xp{ + pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}(beast_token_id: Uint256, beast_dynamic_: BeastDynamic, amount: felt) -> ( + returned_beast_dynamic: BeastDynamic +) { + alloc_locals; + // increase beast xp let (updated_xp_beast) = BeastLib.increase_xp(amount, beast_dynamic_); @@ -435,10 +573,12 @@ func get_random_number{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBu ) { alloc_locals; + let (block) = get_block_number(); + let (controller) = Module.controller_address(); let (xoroshiro_address_) = IModuleController.get_xoroshiro(controller); let (rnd) = IXoroshiro.next(xoroshiro_address_); - return (rnd,); + return (rnd * block,); } // @notice Revert if caller is not adventurer owner @@ -449,7 +589,7 @@ func assert_adventurer_owner{ let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); let (caller) = get_caller_address(); - let (owner) = IAdventurer.ownerOf(adventurer_address, adventurer_id); + let (owner) = IAdventurer.owner_of(adventurer_address, adventurer_id); with_attr error_message("Beast: Only adventurer owner can attack") { assert caller = owner; @@ -526,3 +666,223 @@ func get_total_supply{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_chec let (total_supply: Uint256) = ERC721Enumerable.total_supply(); return (total_supply,); } + +// gold functions + +@storage_var +func goldBalance(tokenId: Uint256) -> (balance: felt) { +} + +@storage_var +func worldSupply() -> (balance: felt) { +} + +@external +func add_to_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + adventurer_token_id: Uint256, addition: felt +) { + Module.only_approved(); + + _add_to_balance(adventurer_token_id, addition); + return (); +} + +func _add_to_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + adventurer_token_id: Uint256, addition: felt +) { + let (current_balance) = balance_of(adventurer_token_id); + + goldBalance.write(adventurer_token_id, current_balance + addition); + + let (supply) = worldSupply.read(); + worldSupply.write(supply + addition); + + return (); +} + +@external +func subtract_from_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + adventurer_token_id: Uint256, subtraction: felt +) { + Module.only_approved(); + + _subtract_from_balance(adventurer_token_id, subtraction); + + return (); +} + +func _subtract_from_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + adventurer_token_id: Uint256, subtraction: felt +) { + let (current_balance) = balance_of(adventurer_token_id); + + let negative = is_le(current_balance - subtraction, 0); + + // add in overflow assert so you can't spend more than what you have. + with_attr error_message("Beast: Not enough gold in balance.") { + assert negative = FALSE; + } + + goldBalance.write(adventurer_token_id, current_balance - subtraction); + + let (supply) = worldSupply.read(); + let new_supply = supply - subtraction; + assert_nn(new_supply); + worldSupply.write(supply - subtraction); + + return (); +} + +@view +func balance_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + adventurer_token_id: Uint256 +) -> (balance: felt) { + let (gold_balance) = goldBalance.read(adventurer_token_id); + return (gold_balance,); +} + +@view +func get_world_supply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( + balance: felt +) { + return worldSupply.read(); +} + +// @notice Grants XP to the items equipped by the given adventurer. +// @dev This function grants XP to the equipped weapon and armor items of the adventurer. +// If the adventurer has a weapon, head armor, chest armor, hand armor, foot armor, waist armor, ring, or necklace equipped, +// the corresponding equipped item will receive the XP. +// @param item_address The address of the item contract. +// @param unpacked_adventurer The AdventurerState struct representing the adventurer. +// @param xp The amount of XP to be granted to the equipped items. +func _allocate_xp_to_items{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + item_address: felt, unpacked_adventurer: AdventurerState, xp: felt +) { + alloc_locals; + + // If adventurer has a weapon + let weapon_equipped = is_not_zero(unpacked_adventurer.WeaponId); + if (weapon_equipped == TRUE) { + let (weapon_result) = ILoot.increase_xp( + item_address, Uint256(unpacked_adventurer.WeaponId, 0), xp + ); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing head armor + let head_armor_equipped = is_not_zero(unpacked_adventurer.HeadId); + if (head_armor_equipped == TRUE) { + // grant it xp + + let (head_armor_result) = ILoot.increase_xp( + item_address, Uint256(unpacked_adventurer.HeadId, 0), xp + ); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing chest armor + let chest_armor_equipped = is_not_zero(unpacked_adventurer.ChestId); + if (chest_armor_equipped == TRUE) { + // grant it xp + ILoot.increase_xp(item_address, Uint256(unpacked_adventurer.ChestId, 0), xp); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing hand armor + let hand_armor_equipped = is_not_zero(unpacked_adventurer.HandsId); + if (hand_armor_equipped == TRUE) { + // grant it xp + ILoot.increase_xp(item_address, Uint256(unpacked_adventurer.HandsId, 0), xp); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing foot armor + let foot_armor_equipped = is_not_zero(unpacked_adventurer.FeetId); + if (foot_armor_equipped == TRUE) { + // grant it xp + ILoot.increase_xp(item_address, Uint256(unpacked_adventurer.FeetId, 0), xp); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing waist armor + let waist_armor_equipped = is_not_zero(unpacked_adventurer.WaistId); + if (waist_armor_equipped == TRUE) { + // grant it xp + ILoot.increase_xp(item_address, Uint256(unpacked_adventurer.WaistId, 0), xp); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing a ring + let ring_equipped = is_not_zero(unpacked_adventurer.RingId); + if (ring_equipped == TRUE) { + // grant it xp + ILoot.increase_xp(item_address, Uint256(unpacked_adventurer.RingId, 0), xp); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + // if adventurer is wearing a necklace + let necklace_equipped = is_not_zero(unpacked_adventurer.NeckId); + if (necklace_equipped == TRUE) { + // grant it xp + ILoot.increase_xp(item_address, Uint256(unpacked_adventurer.NeckId, 0), xp); + + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + return (); +} diff --git a/contracts/loot/beast/interface.cairo b/contracts/loot/beast/interface.cairo old mode 100644 new mode 100755 index e54c1922..a4a86a7e --- a/contracts/loot/beast/interface.cairo +++ b/contracts/loot/beast/interface.cairo @@ -8,6 +8,8 @@ from contracts.loot.constants.beast import Beast, BeastDynamic namespace IBeast { func create(adventurer_token_id: Uint256) -> (beast_token_id: Uint256) { } + func create_starting_beast(adventurer_token_id: Uint256, beast_id: felt) -> (beast_token_id: Uint256) { + } func attack(beast_token_id: Uint256) { } func counter_attack(beast_token_id: Uint256) -> (damage: felt) { @@ -24,4 +26,13 @@ namespace IBeast { } func get_adventurer_from_beast(beast_token_id: Uint256) -> () { } + + func balance_of(adventurer_token_id: Uint256) -> (balance: felt) { + } + func subtract_from_balance(adventurer_token_id: Uint256, subtraction: felt) -> () { + } + func add_to_balance(adventurer_token_id: Uint256, addition: felt) -> () { + } + func get_world_supply() -> (balance: felt) { + } } diff --git a/contracts/loot/beast/library.cairo b/contracts/loot/beast/library.cairo old mode 100644 new mode 100755 index e5b6dca5..911dd0f7 --- a/contracts/loot/beast/library.cairo +++ b/contracts/loot/beast/library.cairo @@ -13,20 +13,58 @@ from starkware.cairo.common.pow import pow from contracts.settling_game.utils.general import unpack_data -from contracts.loot.constants.adventurer import Adventurer +from contracts.loot.constants.adventurer import Adventurer, AdventurerState from contracts.loot.constants.beast import Beast, BeastStatic, BeastDynamic, SHIFT_P, BeastSlotIds from contracts.loot.beast.stats.beast import BeastStats from contracts.loot.loot.stats.item import ItemStats +const BASE_BEAST_LEVEL = 3; +const BASE_BEAST_HEALTH = 10; namespace BeastLib { func create{syscall_ptr: felt*, range_check_ptr}( - xoroshiro_random: felt, adventurer_id: felt + beast_id: felt, + adventurer_id: felt, + adventurer_state: AdventurerState, + rnd_level_boost: felt, + rnd_health_boost: felt, ) -> (beast_static: BeastStatic, beast_dynamic: BeastDynamic) { - let (_, r) = unsigned_div_rem(xoroshiro_random, 17); // number of beast ids - let beast_id = r + 1; + alloc_locals; + + // If the adventurer is less than the beast base level (currently 3) + let is_less_than_base_level = is_le(adventurer_state.Level, BASE_BEAST_LEVEL); + // Set the beast level to the adventurer level + if (is_less_than_base_level == TRUE) { + tempvar beast_level = adventurer_state.Level; + } else { + // once the adventurer exceeds base level, beast level will be random but centered around adventurers level + tempvar beast_level = rnd_level_boost + (adventurer_state.Level - BASE_BEAST_LEVEL); + } + let Level = beast_level; + + // Beast health is base + the provided rnd health boost + let Health = BASE_BEAST_HEALTH + (rnd_health_boost + adventurer_state.Level); + let BeastId = beast_id + 1; + let (Prefix_1) = ItemStats.item_name_prefix(1); + let (Prefix_2) = ItemStats.item_name_suffix(1); + let Adventurer = adventurer_id; + let XP = 0; + let SlainOnDate = 0; + + return ( + BeastStatic(Id=BeastId, Prefix_1=Prefix_1, Prefix_2=Prefix_2), + BeastDynamic( + Health=Health, Adventurer=Adventurer, XP=XP, Level=Level, SlainOnDate=SlainOnDate + ), + ); + } + + func create_start_beast{syscall_ptr: felt*, range_check_ptr}( + beast_id: felt, adventurer_id: felt, adventurer_state: AdventurerState + ) -> (beast_static: BeastStatic, beast_dynamic: BeastDynamic) { + alloc_locals; let BeastId = beast_id; - let Health = 100; + let Health = 10; let (Prefix_1) = ItemStats.item_name_prefix(1); let (Prefix_2) = ItemStats.item_name_suffix(1); let Adventurer = adventurer_id; @@ -175,15 +213,6 @@ namespace BeastLib { return (updated_slain_on_beast,); } - func get_random_ambush{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( - xoroshiro_random: felt - ) -> (discovery: felt) { - alloc_locals; - - let (_, r) = unsigned_div_rem(xoroshiro_random, 2); - return (r,); // values from 0 to 1 inclusive - } - func get_random_flee{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( xoroshiro_random: felt ) -> (discovery: felt) { @@ -224,4 +253,26 @@ namespace BeastLib { // return updated adventurer return (updated_beast,); } + + func calculate_ambush_chance{syscall_ptr: felt*, range_check_ptr}( + rnd: felt, beast_health: felt + ) -> (ambush_chance: felt) { + let (_, r) = unsigned_div_rem(rnd, 2); + let (beast_health_multi, _) = unsigned_div_rem(beast_health, 50); + let ambush_chance = r * (1 + beast_health_multi); + + return (ambush_chance,); + } + + func calculate_gold_reward{syscall_ptr: felt*, range_check_ptr}(rnd: felt, xp_gained: felt) -> ( + gold_reward: felt + ) { + let (_, reward_multi) = unsigned_div_rem(rnd, 4); + let (xp_correction, xp_factor) = unsigned_div_rem(xp_gained, 4); + let xp_start = xp_gained - xp_correction; + + let gold_reward = xp_start + (xp_correction * reward_multi); + + return (gold_reward,); + } } diff --git a/contracts/loot/beast/stats/beast.cairo b/contracts/loot/beast/stats/beast.cairo old mode 100644 new mode 100755 index 7647e6de..d6e8a29e --- a/contracts/loot/beast/stats/beast.cairo +++ b/contracts/loot/beast/stats/beast.cairo @@ -12,7 +12,7 @@ from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.math_cmp import is_le, is_not_zero from starkware.cairo.common.registers import get_label_location -from contracts.loot.constants.beast import BeastAttackType, BeastArmorType, BeastRank +from contracts.loot.constants.beast import BeastAttackType, BeastArmorType, BeastRank, BeastAttackLocation from contracts.loot.constants.rankings import ItemRank from contracts.loot.constants.physics import MaterialDensity @@ -30,10 +30,12 @@ namespace BeastStats { dw BeastAttackType.Griffin; dw BeastAttackType.Minotaur; dw BeastAttackType.Basilisk; + dw BeastAttackType.Gnome; dw BeastAttackType.Wraith; dw BeastAttackType.Ghoul; dw BeastAttackType.Goblin; dw BeastAttackType.Skeleton; + dw BeastAttackType.Golem; dw BeastAttackType.Giant; dw BeastAttackType.Yeti; dw BeastAttackType.Orc; @@ -59,10 +61,12 @@ namespace BeastStats { dw BeastArmorType.Griffin; dw BeastArmorType.Minotaur; dw BeastArmorType.Basilisk; + dw BeastArmorType.Gnome; dw BeastArmorType.Wraith; dw BeastArmorType.Ghoul; dw BeastArmorType.Goblin; dw BeastArmorType.Skeleton; + dw BeastArmorType.Golem; dw BeastArmorType.Giant; dw BeastArmorType.Yeti; dw BeastArmorType.Orc; @@ -86,10 +90,12 @@ namespace BeastStats { dw BeastRank.Griffin; dw BeastRank.Minotaur; dw BeastRank.Basilisk; + dw BeastRank.Gnome; dw BeastRank.Wraith; dw BeastRank.Ghoul; dw BeastRank.Goblin; dw BeastRank.Skeleton; + dw BeastRank.Golem; dw BeastRank.Giant; dw BeastRank.Yeti; dw BeastRank.Orc; @@ -101,4 +107,35 @@ namespace BeastStats { dw BeastRank.Spider; dw BeastRank.Rat; } + + func get_attack_location_from_id{syscall_ptr: felt*, range_check_ptr}(beast_id: felt) -> ( + location: felt + ) { + alloc_locals; + + let (label_location) = get_label_location(labels); + return ([label_location + beast_id - 1],); + + labels: + dw BeastAttackLocation.Phoenix; + dw BeastAttackLocation.Griffin; + dw BeastAttackLocation.Minotaur; + dw BeastAttackLocation.Basilisk; + dw BeastAttackLocation.Gnome; + dw BeastAttackLocation.Wraith; + dw BeastAttackLocation.Ghoul; + dw BeastAttackLocation.Goblin; + dw BeastAttackLocation.Skeleton; + dw BeastAttackLocation.Golem; + dw BeastAttackLocation.Giant; + dw BeastAttackLocation.Yeti; + dw BeastAttackLocation.Orc; + dw BeastAttackLocation.Beserker; + dw BeastAttackLocation.Ogre; + dw BeastAttackLocation.Dragon; + dw BeastAttackLocation.Vampire; + dw BeastAttackLocation.Werewolf; + dw BeastAttackLocation.Spider; + dw BeastAttackLocation.Rat; + } } diff --git a/contracts/loot/constants/adventurer.cairo b/contracts/loot/constants/adventurer.cairo old mode 100644 new mode 100755 index 54db1b55..b5a4d042 --- a/contracts/loot/constants/adventurer.cairo +++ b/contracts/loot/constants/adventurer.cairo @@ -9,6 +9,8 @@ from contracts.loot.constants.item import Item from contracts.loot.constants.bag import Bag from contracts.loot.constants.beast import Beast +from starkware.cairo.common.uint256 import Uint256 + // @notice This is viewable information of the Adventurer. We DO NOT store this on-chain. // This is the object that is returned when requesting the Adventurer by ID. struct Adventurer { @@ -50,9 +52,9 @@ struct Adventurer { Level: felt, // 1- 100 Order: felt, // 1 - 16 - // TODO: Update adventurer pack/unpack to include this new attribute Status: felt, // {Idle, Battling, Traveling, Questing, Dead} Beast: felt, // tokenId of the beast the adventurer is battling + Upgrading: felt, // TODO: Consider storing adventurer location information } @@ -104,6 +106,7 @@ struct AdventurerState { Status: felt, Beast: felt, + Upgrading: felt, } // @notice This is immutable information stored on-chain @@ -158,6 +161,12 @@ struct AdventurerDynamic { Status: felt, Beast: felt, + Upgrading: felt, +} + +struct KingState { + AdventurerId: Uint256, + StartTime: felt, } struct PackedAdventurerState { @@ -183,6 +192,7 @@ namespace SHIFT_P_1 { namespace SHIFT_P_4 { const _1 = 2 ** 0; const _2 = 2 ** 3; + const _3 = 2 ** 44; } namespace AdventurerSlotIds { @@ -222,6 +232,7 @@ namespace AdventurerSlotIds { // Packed Stats p4 const Status = 18; const Beast = 19; + const Upgrading = 20; } namespace AdventurerStatus { @@ -236,8 +247,15 @@ namespace DiscoveryType { const Nothing = 0; const Beast = 1; const Obstacle = 2; - const Adventurer = 3; - const Item = 4; + const Item = 3; + const Adventurer = 4; +} + +namespace ItemDiscoveryType { + const Gold = 0; + const XP = 1; + const Loot = 2; + const Health = 3; } // index for items - used in cast function to set values diff --git a/contracts/loot/constants/bag.cairo b/contracts/loot/constants/bag.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/constants/beast.cairo b/contracts/loot/constants/beast.cairo old mode 100644 new mode 100755 index d791d7e9..6ea63263 --- a/contracts/loot/constants/beast.cairo +++ b/contracts/loot/constants/beast.cairo @@ -8,7 +8,7 @@ %lang starknet from starkware.cairo.common.registers import get_label_location -from contracts.loot.constants.item import Type +from contracts.loot.constants.item import Type, Slot from starkware.cairo.common.cairo_builtins import HashBuiltin struct Beast { @@ -53,23 +53,28 @@ namespace BeastIds { const Griffin = 2; const Minotaur = 3; const Basilisk = 4; - - const Wraith = 5; - const Ghoul = 6; - const Goblin = 7; - const Skeleton = 8; - - const Giant = 9; - const Yeti = 10; - const Orc = 11; - const Beserker = 12; - const Ogre = 13; - - const Dragon = 14; - const Vampire = 15; - const Werewolf = 16; - const Spider = 17; - const Rat = 18; + const Gnome = 5; + + const Wraith = 6; + const Ghoul = 7; + const Goblin = 8; + const Skeleton = 9; + const Golem = 10; + + const Giant = 11; + const Yeti = 12; + const Orc = 13; + const Beserker = 14; + const Ogre = 15; + + const Dragon = 16; + const Vampire = 17; + const Werewolf = 18; + const Spider = 19; + const Rat = 20; + + // If you add beasts, make sure to update MAX_ID below + const MAX_ID = 20; } namespace BeastRank { @@ -77,11 +82,13 @@ namespace BeastRank { const Griffin = 2; const Minotaur = 3; const Basilisk = 4; + const Gnome = 5; const Wraith = 1; const Ghoul = 2; const Goblin = 3; const Skeleton = 4; + const Golem = 5; const Giant = 1; const Yeti = 2; @@ -101,11 +108,13 @@ namespace BeastAttackType { const Griffin = Type.Weapon.magic; const Minotaur = Type.Weapon.magic; const Basilisk = Type.Weapon.magic; + const Gnome = Type.Weapon.magic; const Wraith = Type.Weapon.magic; const Ghoul = Type.Weapon.magic; const Goblin = Type.Weapon.magic; const Skeleton = Type.Weapon.magic; + const Golem = Type.Weapon.magic; const Giant = Type.Weapon.bludgeon; const Yeti = Type.Weapon.bludgeon; @@ -125,11 +134,13 @@ namespace BeastArmorType { const Griffin = Type.Armor.cloth; const Minotaur = Type.Armor.cloth; const Basilisk = Type.Armor.cloth; + const Gnome = Type.Armor.cloth; const Wraith = Type.Armor.cloth; const Ghoul = Type.Armor.cloth; const Goblin = Type.Armor.cloth; const Skeleton = Type.Armor.cloth; + const Golem = Type.Armor.cloth; const Giant = Type.Armor.metal; const Yeti = Type.Armor.metal; @@ -151,3 +162,29 @@ namespace BeastSlotIds { const Level = 3; const SlainOnDate = 4; } + +namespace BeastAttackLocation { + const Phoenix = Slot.Head; + const Griffin = Slot.Chest; + const Minotaur = Slot.Hand; + const Basilisk = Slot.Waist; + const Gnome = Slot.Foot; + + const Wraith = Slot.Chest; + const Ghoul = Slot.Hand; + const Goblin = Slot.Waist; + const Skeleton = Slot.Foot; + const Golem = Slot.Head; + + const Giant = Slot.Hand; + const Yeti = Slot.Waist; + const Orc = Slot.Foot; + const Beserker = Slot.Head; + const Ogre = Slot.Chest; + + const Dragon = Slot.Waist; + const Vampire = Slot.Foot; + const Werewolf = Slot.Head; + const Spider = Slot.Chest; + const Rat = Slot.Hand; +} diff --git a/contracts/loot/constants/combat.cairo b/contracts/loot/constants/combat.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/constants/item.cairo b/contracts/loot/constants/item.cairo old mode 100644 new mode 100755 index 93120f61..98806db9 --- a/contracts/loot/constants/item.cairo +++ b/contracts/loot/constants/item.cairo @@ -29,6 +29,14 @@ struct Item { Bag: felt, // Bag ID IF bagged } +struct Bid { + price: felt, + expiry: felt, + bidder: felt, + status: felt, + item_id: felt, +} + // To provide cleaner numbering with the expectation we'll add more materials // we give each material type it's own number space namespace Material { @@ -403,14 +411,14 @@ namespace ItemSlot { const PlatedBelt = Slot.Waist; const MeshBelt = Slot.Waist; const HeavyBelt = Slot.Waist; - const HolyGreaves = Slot.Hand; - const OrnateGreaves = Slot.Hand; - const Greaves = Slot.Hand; + const HolyGreaves = Slot.Foot; + const OrnateGreaves = Slot.Foot; + const Greaves = Slot.Foot; const ChainBoots = Slot.Foot; const HeavyBoots = Slot.Foot; - const HolyGauntlets = Slot.Foot; - const OrnateGauntlets = Slot.Foot; - const Gauntlets = Slot.Foot; + const HolyGauntlets = Slot.Hand; + const OrnateGauntlets = Slot.Hand; + const Gauntlets = Slot.Hand; const ChainGloves = Slot.Hand; const HeavyGloves = Slot.Hand; } diff --git a/contracts/loot/constants/obstacle.cairo b/contracts/loot/constants/obstacle.cairo old mode 100644 new mode 100755 index 8d527ff5..2b4319b4 --- a/contracts/loot/constants/obstacle.cairo +++ b/contracts/loot/constants/obstacle.cairo @@ -8,7 +8,12 @@ %lang starknet from starkware.cairo.common.registers import get_label_location -from contracts.loot.constants.item import Type +from starkware.cairo.common.math import unsigned_div_rem +from contracts.loot.constants.adventurer import AdventurerState +from starkware.cairo.common.math_cmp import is_le +from starkware.cairo.common.bool import TRUE, FALSE + +from contracts.loot.constants.item import Type, Slot // Structure for the adventurer Obstacle primitive struct Obstacle { @@ -18,6 +23,7 @@ struct Obstacle { Prefix_1: felt, // First part of the name prefix (i.e Tear) Prefix_2: felt, // Second part of the name prefix (i.e Bearer) Greatness: felt, // same as Loot weapons 0-20 + DamageLocation: felt, // slot id of the damaged armor } namespace ObstacleConstants { @@ -39,6 +45,9 @@ namespace ObstacleConstants { const PoisonDart = 13; const SpikedPit = 14; const HiddenArrow = 15; + + // update this if you increase the amount + const MAX = 15; } namespace ObstacleRank { @@ -80,9 +89,69 @@ namespace ObstacleConstants { const SpikedPit = Type.Weapon.blade; const HiddenArrow = Type.Weapon.blade; } + + namespace ObstacleDamageLocation { + const DemonicAlter = Slot.Head; + const Curse = Slot.Head; + const Hex = Slot.Hand; + const MagicLock = Slot.Hand; + const DarkMist = Slot.Chest; + + const CollapsingCeiling = Slot.Head; + const CrushingWalls = Slot.Waist; + const Rockslide = Slot.Foot; + const TumblingBoulders = Slot.Foot; + const SwingingLogs = Slot.Chest; + + const PendulumBlades = Slot.Hand; + const FlameJet = Slot.Waist; + const PoisonDart = Slot.Chest; + const SpikedPit = Slot.Foot; + const HiddenArrow = Slot.Waist; + } } namespace ObstacleUtils { + const BASE_OBSTACLE_LEVEL = 3; + func generate_random_obstacle{syscall_ptr: felt*, range_check_ptr}( + adventurer_state: AdventurerState, rnd: felt + ) -> (obstacle: Obstacle) { + alloc_locals; + + // Given the provided random number, we scope it to range of our ObstacleIds + let (_, r) = unsigned_div_rem(rnd, ObstacleConstants.ObstacleIds.MAX); + let obstacle_id = r + 1; + + // We then determine the greatness/level of the obstacle + let is_less_than_base_level = is_le(adventurer_state.Level, BASE_OBSTACLE_LEVEL); + + let (_, obstacle_level_base) = unsigned_div_rem(rnd, 6); + // If the adventurer is less than the obstacle base level + if (is_less_than_base_level == TRUE) { + // the obstacle level is always equal to the adventurer level + tempvar obstacle_level = adventurer_state.Level; + } else { + // if the adventurer's level is higher than the obstacle base level + // the level will be plus or minus 3 levels from their level (based on current base obstacle level of 3) + tempvar obstacle_level = obstacle_level_base + ( + adventurer_state.Level - BASE_OBSTACLE_LEVEL + ); + } + let level = obstacle_level; + + // obstacle rank is static, based on id + let (obstacle_rank) = get_rank_from_id(obstacle_id); + // obstacle type is static, based on id + let (obstacle_type) = get_type_from_id(obstacle_id); + // obstacle damage location is static, based on id + let (obstacle_damage_location) = get_damage_location_from_id(obstacle_id); + + // TODO: add prefixes and greatness + let obstacle = Obstacle( + obstacle_id, obstacle_type, obstacle_rank, 1, 1, level, obstacle_damage_location + ); + return (obstacle,); + } func get_rank_from_id{syscall_ptr: felt*, range_check_ptr}(obstacle_id: felt) -> (rank: felt) { alloc_locals; @@ -130,4 +199,30 @@ namespace ObstacleUtils { dw ObstacleConstants.ObstacleType.SpikedPit; dw ObstacleConstants.ObstacleType.HiddenArrow; } + + func get_damage_location_from_id{syscall_ptr: felt*, range_check_ptr}(obstacle_id: felt) -> ( + damage_location: felt + ) { + alloc_locals; + + let (label_location) = get_label_location(labels); + return ([label_location + obstacle_id - 1],); + + labels: + dw ObstacleConstants.ObstacleDamageLocation.DemonicAlter; + dw ObstacleConstants.ObstacleDamageLocation.Curse; + dw ObstacleConstants.ObstacleDamageLocation.Hex; + dw ObstacleConstants.ObstacleDamageLocation.MagicLock; + dw ObstacleConstants.ObstacleDamageLocation.DarkMist; + dw ObstacleConstants.ObstacleDamageLocation.CollapsingCeiling; + dw ObstacleConstants.ObstacleDamageLocation.CrushingWalls; + dw ObstacleConstants.ObstacleDamageLocation.Rockslide; + dw ObstacleConstants.ObstacleDamageLocation.TumblingBoulders; + dw ObstacleConstants.ObstacleDamageLocation.SwingingLogs; + dw ObstacleConstants.ObstacleDamageLocation.PendulumBlades; + dw ObstacleConstants.ObstacleDamageLocation.FlameJet; + dw ObstacleConstants.ObstacleDamageLocation.PoisonDart; + dw ObstacleConstants.ObstacleDamageLocation.SpikedPit; + dw ObstacleConstants.ObstacleDamageLocation.HiddenArrow; + } } diff --git a/contracts/loot/constants/physics.cairo b/contracts/loot/constants/physics.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/constants/rankings.cairo b/contracts/loot/constants/rankings.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/interfaces/imodules.cairo b/contracts/loot/interfaces/imodules.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/loot/ILoot.cairo b/contracts/loot/loot/ILoot.cairo old mode 100644 new mode 100755 index d5f78aed..bf0c925a --- a/contracts/loot/loot/ILoot.cairo +++ b/contracts/loot/loot/ILoot.cairo @@ -5,8 +5,22 @@ from contracts.loot.constants.item import Item @contract_interface namespace ILoot { - func getItemByTokenId(tokenId: Uint256) -> (item: Item) { + func get_item_by_token_id(tokenId: Uint256) -> (item: Item) { } - func updateAdventurer(tokenId: Uint256, adventurer: felt) { + func update_adventurer(tokenId: Uint256, adventurer: felt) { + } + func mint_starter_weapon(to: felt, weapon_id: felt, adventurer_token_id: Uint256) -> ( + item_token_id: Uint256 + ) { + } + func mint_from_mart(to: felt, weapon_id: felt, adventurer_token_id: Uint256){ + } + func mint(to: felt, adventurer_token_id: Uint256) -> (item_token_id: Uint256) { + } + func item_owner(tokenId: Uint256, adventurer_token_id: Uint256) -> (owner: felt) { + } + func get_adventurer_owner(tokenId: Uint256) -> (adventuer_token_id: Uint256) { + } + func increase_xp(tokenId: Uint256, amount: felt) -> (success: felt) { } } diff --git a/contracts/loot/loot/Loot.cairo b/contracts/loot/loot/Loot.cairo old mode 100644 new mode 100755 index 0b05f314..320d8b55 --- a/contracts/loot/loot/Loot.cairo +++ b/contracts/loot/loot/Loot.cairo @@ -3,6 +3,7 @@ %lang starknet from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.cairo_builtins import HashBuiltin from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.math import unsigned_div_rem @@ -13,12 +14,13 @@ from openzeppelin.token.erc721.library import ERC721 from openzeppelin.token.erc721.enumerable.library import ERC721Enumerable from openzeppelin.upgrades.library import Proxy -from contracts.loot.constants.item import Item +from contracts.loot.constants.item import Item, ItemIds from contracts.loot.interfaces.imodules import IModuleController from contracts.loot.loot.library import ItemLib from contracts.loot.loot.metadata import LootUri from contracts.settling_game.interfaces.ixoroshiro import IXoroshiro from contracts.settling_game.library.library_module import Module +from contracts.loot.loot.stats.combat import CombatStats from starkware.starknet.common.syscalls import ( get_block_timestamp, @@ -30,6 +32,18 @@ from starkware.starknet.common.syscalls import ( from contracts.loot.loot.stats.item import ItemStats from contracts.loot.utils.constants import ModuleIds, ExternalContractIds +// ----------------------------------- +// Events +// ----------------------------------- + +@event +func ItemXPIncrease(item_token_id: Uint256, item: Item) { +} + +@event +func ItemGreatnessIncrease(item_token_id: Uint256, item: Item) { +} + // ----------------------------------- // Storage // ----------------------------------- @@ -155,7 +169,7 @@ func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( alloc_locals; let (controller) = Module.controller_address(); let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); - let (item_data) = getItemByTokenId(tokenId); + let (item_data) = get_item_by_token_id(tokenId); let (tokenURI_len, tokenURI: felt*) = LootUri.build(tokenId, item_data, adventurer_address); return (tokenURI_len, tokenURI); } @@ -227,6 +241,10 @@ func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_che func item(tokenId: Uint256) -> (item: Item) { } +@storage_var +func adventurer_owner(tokenId: Uint256) -> (adventurer_token_id: Uint256) { +} + // ----------------------------- // External Loot Specific // ----------------------------- @@ -234,9 +252,14 @@ func item(tokenId: Uint256) -> (item: Item) { // @notice Mint random item // @param to: Address to mint the item to @external -func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(to: felt) { +func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, adventurer_token_id: Uint256 +) { alloc_locals; + // // Only LootMarketArcade and Adventurer + // Module.only_approved(); + // fetch new item with random Id let (rnd) = get_random_number(); let (new_item: Item) = ItemLib.generate_random_item(rnd); @@ -245,17 +268,49 @@ func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(to: f item.write(Uint256(next_id + 1, 0), new_item); + adventurer_owner.write(Uint256(next_id + 1, 0), adventurer_token_id); + ERC721Enumerable._mint(to, Uint256(next_id + 1, 0)); counter.write(next_id + 1); return (); } +// @notice Mint adventurer starting weapon +// @param to: Address to mint the item to +// @param weapon_id: Weapon ID to mint +// @return item_token_id: The token id of the minted item +@external +func mint_starter_weapon{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, weapon_id: felt, adventurer_token_id: Uint256 +) -> (item_token_id: Uint256) { + alloc_locals; + + Module.only_approved(); + + assert_starter_weapon(weapon_id); + + // fetch new item with random Id + let (new_item: Item) = ItemLib.generate_starter_weapon(weapon_id); + + let (next_id) = counter.read(); + + item.write(Uint256(next_id + 1, 0), new_item); + + adventurer_owner.write(Uint256(next_id + 1, 0), adventurer_token_id); + + ERC721Enumerable._mint(to, Uint256(next_id + 1, 0)); + + counter.write(next_id + 1); + + return (Uint256(next_id + 1, 0),); +} + // @notice Update item adventurer // @param tokenId: Id of loot item // @param adventurerId: Id of adventurer @external -func updateAdventurer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( +func update_adventurer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( tokenId: Uint256, adventurerId: felt ) { Module.only_approved(); @@ -271,7 +326,7 @@ func updateAdventurer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec // @param tokenId: Id of loot item // @param xp: Amount of xp to update @external -func updateXP{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( +func update_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( tokenId: Uint256, xp: felt ) { Module.only_approved(); @@ -287,7 +342,7 @@ func updateXP{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( // @param tokenId: Id of loot item // @param item_: Data of loot item @external -func setItemById{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( +func set_item_by_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( tokenId: Uint256, item_id: felt, greatness: felt, xp: felt, adventurer: felt, bag_id: felt ) { alloc_locals; @@ -297,10 +352,54 @@ func setItemById{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr return (); } +// @notice Increase xp of an item +// @param item_token_id: Id of the item +// @param amount: Amount of xp to increase +// @return success: Value indicating success +@external +func increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + item_token_id: Uint256, amount: felt +) -> (success: felt) { + alloc_locals; + + // Only approved modules can increase and items xp + Module.only_approved(); + + // call internal function for updating xp + let (result) = _increase_xp(item_token_id, amount); + + // return result + return (result,); +} + // ----------------------------- // Internal Loot Specific // ----------------------------- +// @notice Asserts that the weapon is a starter weapon +// @param weapon_id: Id of loot weapon +func assert_starter_weapon{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + weapon_id: felt +) { + // book, wand, club, or short sword + if (weapon_id == ItemIds.Book) { + return (); + } + if (weapon_id == ItemIds.Wand) { + return (); + } + if (weapon_id == ItemIds.Club) { + return (); + } + if (weapon_id == ItemIds.ShortSword) { + return (); + } + with_attr error_message("Loot: Item is not a starter weapon") { + assert TRUE = FALSE; + } + return (); +} + // @notice Get xiroshiro random number // @return dice_roll: Random number @view @@ -323,10 +422,112 @@ func get_random_number{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBu // @param tokenId: Id of the item token // @return item: Item data @view -func getItemByTokenId{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( +func get_item_by_token_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( tokenId: Uint256 ) -> (item: Item) { let (item_: Item) = item.read(tokenId); return (item_,); } + +// @notice Get adventurer owner +// @param tokenId: Id of the item token +// @return adventurer_token_id: Id of the adventurer +@view +func get_adventurer_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256 +) -> (adventurer_token_id: Uint256) { + let (adventurer_token_id) = adventurer_owner.read(tokenId); + + return (adventurer_token_id,); +} + +// @notice Increases the "XP" attribute of an item, represented by its unique token ID, by a specified amount. +// @dev This function updates the XP of the specified item and writes the updated item to the blockchain. +// If the XP increase results in a level increase (i.e. the item's "greatness" attribute is increased), +// the function also increases the item's greatness attribute and writes the updated item to the blockchain. +// @param item_token_id Unique token ID of the item to be updated. +// @param amount The amount by which to increase the item's "XP" attribute. +// @return success Boolean value indicating whether the function succeeded. +func _increase_xp{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256, amount: felt +) -> (success: felt) { + alloc_locals; + + // get item + let (_item) = get_item_by_token_id(item_token_id); + + // increase xp + let item_updated_xp = ItemLib.update_xp(_item, amount); + + // check if item received a greatness increase + let (greatness_increased) = CombatStats.check_for_level_increase( + item_updated_xp.XP, item_updated_xp.Greatness + ); + + // if greatness increased + if (greatness_increased == TRUE) { + // increase greatness + let (result) = _increase_greatness(item_token_id, item_updated_xp.Greatness + 1); + return (result,); + } else { + // if greatness did not increase, we we still update XP + item.write(item_token_id, item_updated_xp); + + // and emit an XP increase event + emit_item_xp_increase(item_token_id); + + // return success + return (TRUE,); + } +} + +// @notice Increases the "greatness" attribute of an item, represented by its unique token ID, by a specified amount. +// @dev This function updates the greatness of the specified item and writes the updated item to the blockchain. +// @param item_token_id Unique token ID of the item to be updated. +// @param greatness The amount by which to increase the item's "greatness" attribute. +// @return success Boolean value indicating whether the function succeeded. +func _increase_greatness{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256, greatness: felt +) -> (success: felt) { + alloc_locals; + + // get item + let (_item) = get_item_by_token_id(item_token_id); + + // update greatness + let item_updated_greatness = ItemLib.update_greatness(_item, greatness); + + // write to blockchain + item.write(item_token_id, item_updated_greatness); + + // emit greatness increase event + emit_item_greatness_increase(item_token_id); + + // return success + return (TRUE,); +} + +// @notice Emits a greatness increase event for an item +// @param item_token_id: the token id of the item that increased in greatness +func emit_item_greatness_increase{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256 +) { + // Get item from token id + let (item) = get_item_by_token_id(item_token_id); + // emit leveled up event + ItemGreatnessIncrease.emit(item_token_id, item); + return (); +} + +// @notice Emits an xp increase event for an item +// @param item_token_id: the token id of the item whose xp increased +func emit_item_xp_increase{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256 +) { + // Get item from token id + let (item) = get_item_by_token_id(item_token_id); + // emit leveled up event + ItemXPIncrease.emit(item_token_id, item); + return (); +} diff --git a/contracts/loot/loot/LootMarketArcade.cairo b/contracts/loot/loot/LootMarketArcade.cairo new file mode 100755 index 00000000..a207da21 --- /dev/null +++ b/contracts/loot/loot/LootMarketArcade.cairo @@ -0,0 +1,891 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.3.2 (token/erc721/enumerable/presets/ERC721EnumerableMintableBurnable.cairo) + +%lang starknet +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.uint256 import Uint256, uint256_add, uint256_eq +from starkware.cairo.common.math import unsigned_div_rem, assert_not_zero +from starkware.cairo.common.math_cmp import is_le_felt, is_le, is_not_zero +from openzeppelin.access.ownable.library import Ownable +from openzeppelin.introspection.erc165.library import ERC165 +from openzeppelin.token.erc721.library import ERC721 +from openzeppelin.token.erc721.enumerable.library import ERC721Enumerable +from openzeppelin.upgrades.library import Proxy +from starkware.cairo.common.bool import TRUE, FALSE +from contracts.loot.constants.adventurer import AdventurerState +from contracts.loot.constants.item import Item, ItemIds +from contracts.loot.interfaces.imodules import IModuleController +from contracts.loot.loot.library import ItemLib +from contracts.loot.loot.metadata import LootUri +from contracts.settling_game.interfaces.ixoroshiro import IXoroshiro +from contracts.settling_game.library.library_module import Module +from contracts.loot.beast.interface import IBeast +from contracts.loot.loot.stats.combat import CombatStats + +from starkware.starknet.common.syscalls import ( + get_block_timestamp, + get_caller_address, + get_tx_info, + get_contract_address, +) + +from contracts.loot.loot.stats.item import ItemStats +from contracts.loot.utils.constants import ModuleIds, ExternalContractIds, STARTING_GOLD +from contracts.loot.adventurer.interface import IAdventurer +from openzeppelin.token.erc721.IERC721 import IERC721 + +// ----------------------------------- +// Events +// ----------------------------------- + +@event +func ItemXPIncrease(item_token_id: Uint256, item: Item) { +} + +@event +func ItemGreatnessIncrease(item_token_id: Uint256, item: Item) { +} + +// ----------------------------------- +// Storage +// ----------------------------------- + +@storage_var +func counter() -> (count: felt) { +} +// ----------------------------------- +// Initialize & upgrade +// ----------------------------------- + +// @notice Module initializer +// @param address_of_controller: Controller/arbiter address +// @return proxy_admin: Proxy admin address +@external +func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + name: felt, symbol: felt, address_of_controller: felt, proxy_admin: felt +) { + Module.initializer(address_of_controller); + ERC721.initializer(name, symbol); + ERC721Enumerable.initializer(); + Ownable.initializer(proxy_admin); + Proxy.initializer(proxy_admin); + return (); +} + +// @notice Set new proxy implementation +// @dev Can only be set by the arbiter +// @param new_implementation: New implementation contract address +@external +func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + new_implementation: felt +) { + Proxy.assert_only_admin(); + Proxy._set_implementation_hash(new_implementation); + return (); +} + +// +// Getters +// + +@view +func totalSupply{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}() -> ( + totalSupply: Uint256 +) { + let (totalSupply: Uint256) = ERC721Enumerable.total_supply(); + return (totalSupply,); +} + +@view +func tokenByIndex{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + index: Uint256 +) -> (tokenId: Uint256) { + let (tokenId: Uint256) = ERC721Enumerable.token_by_index(index); + return (tokenId,); +} + +@view +func tokenOfOwnerByIndex{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + owner: felt, index: Uint256 +) -> (tokenId: Uint256) { + let (tokenId: Uint256) = ERC721Enumerable.token_of_owner_by_index(owner, index); + return (tokenId,); +} + +@view +func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + interfaceId: felt +) -> (success: felt) { + let (success) = ERC165.supports_interface(interfaceId); + return (success,); +} + +@view +func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { + let (name) = ERC721.name(); + return (name,); +} + +@view +func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { + let (symbol) = ERC721.symbol(); + return (symbol,); +} + +@view +func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( + balance: Uint256 +) { + let (balance: Uint256) = ERC721.balance_of(owner); + return (balance,); +} + +@view +func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(tokenId: Uint256) -> ( + owner: felt +) { + let (owner: felt) = ERC721.owner_of(tokenId); + return (owner,); +} + +@view +func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256 +) -> (approved: felt) { + let (approved: felt) = ERC721.get_approved(tokenId); + return (approved,); +} + +@view +func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + owner: felt, operator: felt +) -> (isApproved: felt) { + let (isApproved: felt) = ERC721.is_approved_for_all(owner, operator); + return (isApproved,); +} + +@view +func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256 +) -> (tokenURI_len: felt, tokenURI: felt*) { + alloc_locals; + let (controller) = Module.controller_address(); + let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); + let (item_data) = get_item_by_token_id(tokenId); + let (tokenURI_len, tokenURI: felt*) = LootUri.build(tokenId, item_data, adventurer_address); + return (tokenURI_len, tokenURI); +} + +@view +func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { + let (owner: felt) = Ownable.owner(); + return (owner,); +} + +// +// Externals +// + +@external +func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, tokenId: Uint256 +) { + ERC721.approve(to, tokenId); + return (); +} + +@external +func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + operator: felt, approved: felt +) { + ERC721.set_approval_for_all(operator, approved); + return (); +} + +@external +func transferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + from_: felt, to: felt, tokenId: Uint256 +) { + // can only be called by ItemContract/AdventurerContract/BeastContract + Module.only_approved(); + ERC721Enumerable.transfer_from(from_, to, tokenId); + return (); +} + +@external +func safeTransferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt* +) { + // can only be called by ItemContract/AdventurerContract/BeastContract + Module.only_approved(); + ERC721Enumerable.safe_transfer_from(from_, to, tokenId, data_len, data); + return (); +} + +@external +func burn{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(tokenId: Uint256) { + // can only be called by ItemContract/AdventurerContract/BeastContract + Module.only_approved(); + ERC721Enumerable._burn(tokenId); + return (); +} + +@external +func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + newOwner: felt +) { + Ownable.transfer_ownership(newOwner); + return (); +} + +@external +func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + Ownable.renounce_ownership(); + return (); +} + +@storage_var +func item(tokenId: Uint256) -> (item: Item) { +} + +// Adventurers OWN the Loot items - they cannot transfer them. +@storage_var +func item_adventurer_owner(tokenId: Uint256, adventurerId: Uint256) -> (owner: felt) { +} + +// ----------------------------- +// External Loot Specific +// ----------------------------- + +// @notice Mint random item +// @param to: Address to mint the item to +@external +func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, adventurer_token_id: Uint256 +) { + alloc_locals; + Module.only_approved(); + + // fetch new item with random Id + let (rnd) = get_random_number(); + let (ts) = get_block_timestamp(); + let (new_item: Item) = ItemLib.generate_random_item(rnd * ts); + + let (id) = _mint(to, new_item, adventurer_token_id); + + return (); +} + +@external +func mint_from_mart{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, item_id: felt, adventurer_token_id: Uint256 +) { + alloc_locals; + + let (new_item: Item) = ItemLib.generate_item_by_id(item_id); + + let (id) = _mint(to, new_item, adventurer_token_id); + + return (); +} + +// @notice Mint adventurer starting weapon +// @param to: Address to mint the item to +// @param weapon_id: Weapon ID to mint +// @return item_token_id: The token id of the minted item +@external +func mint_starter_weapon{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, weapon_id: felt, adventurer_token_id: Uint256 +) -> (item_token_id: Uint256) { + alloc_locals; + + assert_starter_weapon(weapon_id); + + // fetch new item with random Id + let (new_item: Item) = ItemLib.generate_starter_weapon(weapon_id); + + return _mint(to, new_item, adventurer_token_id); +} + +func _mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( + to: felt, _item: Item, adventurer_token_id: Uint256 +) -> (item_token_id: Uint256) { + alloc_locals; + + let (current_id: Uint256) = totalSupply(); + let (next_item_id, _) = uint256_add(current_id, Uint256(1, 0)); + + item.write(next_item_id, _item); + + ERC721Enumerable._mint(to, next_item_id); + + item_adventurer_owner.write(next_item_id, adventurer_token_id, TRUE); + + return (next_item_id,); +} + + +// @notice Update item adventurer +// @param tokenId: Id of loot item +// @param adventurerId: Id of adventurer +@external +func update_adventurer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256, adventurerId: felt +) { + Module.only_approved(); + let (item_: Item) = item.read(tokenId); + + let updated_item = ItemLib.update_adventurer(item_, adventurerId); + + item.write(tokenId, updated_item); + return (); +} + +// @notice Update item xp +// @param tokenId: Id of loot item +// @param xp: Amount of xp to update +@external +func update_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256, xp: felt +) { + Module.only_approved(); + let (item_: Item) = item.read(tokenId); + + let updated_item = ItemLib.update_xp(item_, xp); + + item.write(tokenId, updated_item); + return (); +} + +// @notice Set loot item data by id +// @param tokenId: Id of loot item +// @param item_: Data of loot item +@external +func set_item_by_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256, item_id: felt, greatness: felt, xp: felt, adventurer: felt, bag_id: felt +) { + alloc_locals; + Ownable.assert_only_owner(); + let (item_) = ItemLib.set_item(item_id, greatness, xp, adventurer, bag_id); + item.write(tokenId, item_); + return (); +} + +// @notice Increase xp of an item +// @param item_token_id: Id of the item +// @param amount: Amount of xp to increase +// @return success: Value indicating success +@external +func increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + item_token_id: Uint256, amount: felt +) -> (success: felt) { + alloc_locals; + + // Only approved modules can increase and items xp + Module.only_approved(); + + // call internal function for updating xp + let (result) = _increase_xp(item_token_id, amount); + + // return result + return (result,); +} + +// ----------------------------- +// Internal Loot Specific +// ----------------------------- + +// @notice Get xiroshiro random number +// @return dice_roll: Random number +@view +func get_random_number{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}() -> ( + dice_roll: felt +) { + alloc_locals; + + let (controller) = Module.controller_address(); + let (xoroshiro_address_) = IModuleController.get_xoroshiro(controller); + let (rnd) = IXoroshiro.next(xoroshiro_address_); + return (rnd,); // values from 1 to 101 inclusive +} + +// @notice Asserts that the weapon is a starter weapon +// @param weapon_id: Id of loot weapon +func assert_starter_weapon{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + weapon_id: felt +) { + // book, wand, club, or short sword + if (weapon_id == ItemIds.Book) { + return (); + } + if (weapon_id == ItemIds.Wand) { + return (); + } + if (weapon_id == ItemIds.Club) { + return (); + } + if (weapon_id == ItemIds.ShortSword) { + return (); + } + with_attr error_message("Loot: Item is not a starter weapon") { + assert TRUE = FALSE; + } + return (); +} + +// @notice Increases the "XP" attribute of an item, represented by its unique token ID, by a specified amount. +// @dev This function updates the XP of the specified item and writes the updated item to the blockchain. +// If the XP increase results in a level increase (i.e. the item's "greatness" attribute is increased), +// the function also increases the item's greatness attribute and writes the updated item to the blockchain. +// @param item_token_id Unique token ID of the item to be updated. +// @param amount The amount by which to increase the item's "XP" attribute. +// @return success Boolean value indicating whether the function succeeded. +func _increase_xp{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256, amount: felt +) -> (success: felt) { + alloc_locals; + + // get item + let (_item) = get_item_by_token_id(item_token_id); + + // increase xp + let item_updated_xp = ItemLib.update_xp(_item, amount); + + // check if item received a greatness increase + let (greatness_increased) = CombatStats.check_for_level_increase( + item_updated_xp.XP, item_updated_xp.Greatness + ); + + // if greatness increased + if (greatness_increased == TRUE) { + // increase greatness + let (result) = _increase_greatness(item_token_id, item_updated_xp.Greatness + 1); + return (result,); + } else { + // if greatness did not increase, we we still update XP + item.write(item_token_id, item_updated_xp); + + // and emit an XP increase event + emit_item_xp_increase(item_token_id); + + // return success + return (TRUE,); + } +} + +// @notice Increases the "greatness" attribute of an item, represented by its unique token ID, by a specified amount. +// @dev This function updates the greatness of the specified item and writes the updated item to the blockchain. +// @param item_token_id Unique token ID of the item to be updated. +// @param greatness The amount by which to increase the item's "greatness" attribute. +// @return success Boolean value indicating whether the function succeeded. +func _increase_greatness{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256, greatness: felt +) -> (success: felt) { + alloc_locals; + + // get item + let (_item) = get_item_by_token_id(item_token_id); + + // update greatness + let item_updated_greatness = ItemLib.update_greatness(_item, greatness); + + // write to blockchain + item.write(item_token_id, item_updated_greatness); + + // emit greatness increase event + emit_item_greatness_increase(item_token_id); + + // return success + return (TRUE,); +} + +// -------------------- +// Getters +// -------------------- + +// @notice Get item data by the token id +// @param tokenId: Id of the item token +// @return item: Item data +@view +func get_item_by_token_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256 +) -> (item: Item) { + let (item_: Item) = item.read(tokenId); + + return (item_,); +} + +// -------------------- +// Market +// -------------------- + + +// This uses a Seed which is created every 12hrs. From this seed X number of items can be purchased +// after they have been bidded on. + +// tokenId = ERC721 TokenId +// market_item_id = Market item id - these only exist in the Market listings - they are not actual item ids or token ids. + +namespace BidStatus { + const closed = 0; + const open = 1; +} + +struct Bid { + price: felt, + expiry: felt, + bidder: felt, + status: felt, + item_id: felt, +} + +@storage_var +func bid(market_item_id: Uint256) -> (bid: Bid) { +} + +@storage_var +func last_seed_time() -> (number: felt) { +} + +@storage_var +func mint_seed() -> (number: felt) { +} + +// index +@storage_var +func mint_index() -> (number: felt) { +} + +@storage_var +func new_items() -> (number: felt) { +} + +const HOUR = 3600; +const BID_TIME = HOUR / 2; // 2 hours +const SHUFFLE_TIME = 3600 * 6; +const BASE_PRICE = 3; +const SEED_MULTI = 5846975; // for psudeo randomness now +const NUMBER_LOOT_ITEMS = 101; +const MINIMUM_ITEMS_EMITTED = 20; +const ITEMS_PER_EPOCH_PER_ADVENTUER = 3; + +@event +func ItemMerchantUpdate(item: Item, market_item_id: felt, bid: Bid) { +} + +// returns TRUE if item is owned +@view +func item_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + tokenId: Uint256, adventurer_token_id: Uint256 +) -> (owner: felt) { + return item_adventurer_owner.read(tokenId, adventurer_token_id); +} + +@view +func get_mint_index{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (number: felt) { + return mint_index.read(); +} + +@view +func get_new_items{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (number: felt) { + return new_items.read(); +} + +@external +func mint_daily_items{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + // check 12hrs has passed + let (current_time) = get_block_timestamp(); + let (_lastSeedTime) = last_seed_time.read(); + let is_past_tick = is_le(_lastSeedTime + SHUFFLE_TIME, current_time); + with_attr error_message("Item Market: You cannot mint daily items yet...") { + assert is_past_tick = TRUE; + } + + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + let (world_gold_supply) = IBeast.get_world_supply(beast_address); + + let (relative_adventurers_in_world,_) = unsigned_div_rem(world_gold_supply, STARTING_GOLD); + + let less_than_minimum = is_le(relative_adventurers_in_world, MINIMUM_ITEMS_EMITTED); + if (less_than_minimum == TRUE) { + tempvar _new_items = 20; + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar _new_items = relative_adventurers_in_world; + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + tempvar _new_items = _new_items; + + + // get current index + let (current_index) = mint_index.read(); + + let new_index = current_index + _new_items; + + let (random) = get_random_number(); + mint_seed.write(random * current_time); + + last_seed_time.write(current_time); + + emit_new_items_loop(random, _new_items, current_index); + + // set new index + mint_index.write(new_index); + + // set number of items in this batch - this allows us to force people to only mint within the new item scope + // eg: mint items only > mintIndex - new_items && < mintIndex + // TODO: might be better way than this. + new_items.write(_new_items); + + // TODO: send 2 gold to the adventurer whoever calls this + // let (caller) = get_caller_address(); + // IBeast.add_to_balance(beast_address, Uint256(2, 0), 2); + + return (); +} + +func emit_new_items_loop{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + daily_seed: felt, item_start_index_len: felt, item_start_index: felt +) -> (item_start_index_len: felt, item_start_index: felt) { + // we loop over all new items + if (item_start_index_len == 0) { + return (0, 0); + } + + let (new_item: Item) = _get_random_item_from_seed(item_start_index, daily_seed); + + ItemMerchantUpdate.emit(new_item, item_start_index, Bid(BASE_PRICE, 0, 0, 0, new_item.Id)); + + return emit_new_items_loop(daily_seed, item_start_index_len - 1, item_start_index + 1); +} + +@view +func get_random_item_from_seed{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: felt +) -> (item: Item) { + let (seed) = mint_seed.read(); + + return _get_random_item_from_seed(market_item_id, seed); +} + +func _get_random_item_from_seed{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: felt, daily_seed: felt +) -> (item: Item) { + let (_, r) = unsigned_div_rem(daily_seed * market_item_id * SEED_MULTI, NUMBER_LOOT_ITEMS); + + + return ItemLib.generate_random_item(r); +} + +@view +func random_item_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: felt, daily_seed: felt +) -> (item: felt) { + let (_, r) = unsigned_div_rem(daily_seed * market_item_id * SEED_MULTI, NUMBER_LOOT_ITEMS); + + return (r,); +} + +@view +func view_bid{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(market_item_id: Uint256) -> ( + bid: Bid +) { + return bid.read(market_item_id); +} + +@view +func view_unminted_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: Uint256 +) -> (item: Item, bid: Bid) { + let (item) = get_random_item_from_seed(market_item_id.low); + + let (bid) = view_bid(market_item_id); + return (item, bid); +} + +// loop items by index + +// @notice Allows a bidder to place a bid on an item. If no previous bids have been placed, the bid time will start from the current block timestamp plus the bid time duration. If a previous bid has been placed, the bidder must submit a higher bid within the bid time window of the previous bid. +// @param tokenId The ID of the item being bid on. +// @param price The amount of the bid. +// @param expiry The expiration time of the bid, after which the bidder will no longer be able to claim the item. +// @param bidder The address of the bidder. +// @dev Requires the item to be owned by the market contract and for the bid to be higher than the base price. The function will update the bid price and expiry time for the item. +@external +func bid_on_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: Uint256, adventurer_token_id: Uint256, price: felt +) { + alloc_locals; + + let (caller) = get_caller_address(); + let (current_time) = get_block_timestamp(); + let (this) = get_contract_address(); + + // store the id not the Unit in the struct + let adventurer_id_as_felt = adventurer_token_id.low; + + let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); + let (owner) = IAdventurer.owner_of(adventurer_address, adventurer_token_id); + with_attr error_message("Item Market: You do not own this Adventurer") { + assert caller = owner; + } + // check adventurer is alive + let (adventurer: AdventurerState) = IAdventurer.get_adventurer_by_id(adventurer_address, adventurer_token_id); + + with_attr error_message("Adventurer: Adventurer is dead") { + assert_not_zero(adventurer.Health); + } + + // check higher than the base price that is set + let higer_than_base_price = is_le(BASE_PRICE, price); + with_attr error_message("Item Market: Your bid is not high enough") { + assert higer_than_base_price = TRUE; + } + + let (item) = get_random_item_from_seed(market_item_id.low); + + // read current bid + let (current_bid) = bid.read(market_item_id); + + // if current expiry = 0 means unbidded = set base time from now + BID_TIME + if (current_bid.expiry == FALSE) { + bid.write(market_item_id, Bid(price, current_time + BID_TIME, adventurer_id_as_felt, BidStatus.open, item.Id)); + return (); + } + + // check higher than the last bid price + let higher_price = is_le(price, current_bid.price); + with_attr error_message("Item Market: Your bid is not high enough") { + assert higher_price = TRUE; + } + + // check bid time not expired + let not_expired = is_le(current_bid.expiry, current_time); + with_attr error_message("Item Market: Bid has expired") { + assert not_expired = TRUE; + } + + assert_can_purchase(market_item_id.low); + + // update bid state + bid.write(market_item_id, Bid(price, current_bid.expiry, adventurer_id_as_felt, BidStatus.open, item.Id)); + + let (beast_address) = Module.get_module_address(ModuleIds.Beast); + + // subtract gold balance from buyer + + IBeast.subtract_from_balance(beast_address, adventurer_token_id, price); + + let has_bid = is_not_zero(current_bid.bidder); + + if (has_bid == TRUE) { + IBeast.add_to_balance(beast_address, Uint256(current_bid.bidder, 0), current_bid.price); + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar syscall_ptr: felt* = syscall_ptr; + tempvar pedersen_ptr: HashBuiltin* = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + } + + + ItemMerchantUpdate.emit( + item, market_item_id.low, Bid(price, current_bid.expiry, adventurer_id_as_felt, BidStatus.open, item.Id) + ); + + return (); +} +// @notice Allows a bidder to claim a previously placed bid on an item, provided the bid has expired and the item is still available. +// @param item_id The ID of the item being claimed. +// @dev Requires the caller to be the bidder who previously placed the bid. The function will also mint a token representing the claimed item for the caller and update the bid status to "closed". +@external +func claim_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: Uint256, adventurer_token_id: Uint256 +) { + alloc_locals; + + let (caller) = get_caller_address(); + // ownly owner of Adventurer can call + // TODO: we could open this to anyone to call so bids can be cleared by helper accounts... + let (adventurer_address) = Module.get_module_address(ModuleIds.Adventurer); + let (owner) = IAdventurer.owner_of(adventurer_address, adventurer_token_id); + with_attr error_message("Item Market: You do not own this Adventurer") { + assert caller = owner; + } + + let (current_time) = get_block_timestamp(); + + let (current_bid) = bid.read(market_item_id); + + // check bid has expired + item is still available + let expired = is_le(current_bid.expiry, current_time); + with_attr error_message("Item Market: Item not available") { + assert current_bid.status = BidStatus.open; + assert expired = TRUE; + } + + with_attr error_message("Item Market: Caller not bidder!") { + assert current_bid.bidder = adventurer_token_id.low; + } + + // we pass in the current_bid.item_id + mint_from_mart(caller, current_bid.item_id, adventurer_token_id); + + // this could be optimised + bid.write(market_item_id, Bid(current_bid.price, 0, adventurer_token_id.low, BidStatus.closed, current_bid.item_id)); + + return (); +} + +func assert_can_purchase{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + market_item_id: felt +) { + + let (start_index) = mint_index.read(); + + let (current_items) = new_items.read(); + + let above_start_index = is_le(start_index, market_item_id); + + let below_end_index = is_le(market_item_id, start_index + current_items); + + with_attr error_message("Item Market: Item not available anymore") { + assert above_start_index = TRUE; + assert below_end_index = TRUE; + } + + return (); +} + +// @notice Emits a greatness increase event for an item +// @param item_token_id: the token id of the item that increased in greatness +func emit_item_greatness_increase{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256 +) { + // Get item from token id + let (item) = get_item_by_token_id(item_token_id); + // emit leveled up event + ItemGreatnessIncrease.emit(item_token_id, item); + return (); +} + +// @notice Emits an xp increase event for an item +// @param item_token_id: the token id of the item whose xp increased +func emit_item_xp_increase{range_check_ptr, syscall_ptr: felt*, pedersen_ptr: HashBuiltin*}( + item_token_id: Uint256 +) { + // Get item from token id + let (item) = get_item_by_token_id(item_token_id); + // emit leveled up event + ItemXPIncrease.emit(item_token_id, item); + return (); +} \ No newline at end of file diff --git a/contracts/loot/loot/LootPhysics.cairo b/contracts/loot/loot/LootPhysics.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/loot/library.cairo b/contracts/loot/loot/library.cairo old mode 100644 new mode 100755 index e92a0b54..d26372a9 --- a/contracts/loot/loot/library.cairo +++ b/contracts/loot/loot/library.cairo @@ -4,6 +4,7 @@ from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.math import unsigned_div_rem from starkware.cairo.common.math_cmp import is_le from starkware.starknet.common.syscalls import get_block_timestamp +from starkware.cairo.common.cairo_builtins import HashBuiltin from contracts.loot.constants.item import Item, NamePrefixLength, NameSuffixLength, ItemSuffixLength from contracts.loot.loot.stats.item import ItemStats @@ -52,11 +53,35 @@ namespace ItemLib { return updated_item; } - func generate_random_item{syscall_ptr: felt*, range_check_ptr}(rnd: felt) -> (item: Item) { - let (_, r) = unsigned_div_rem(rnd, 101); + func update_greatness{syscall_ptr: felt*, range_check_ptr}( + item: Item, new_greatness: felt + ) -> Item { + let updated_item = Item( + Id=item.Id, + Slot=item.Slot, + Type=item.Type, + Material=item.Material, + Rank=item.Rank, + Prefix_1=item.Prefix_1, + Prefix_2=item.Prefix_2, + Suffix=item.Suffix, + Greatness=new_greatness, + CreatedBlock=item.CreatedBlock, + XP=item.XP, + Adventurer=item.Adventurer, + Bag=item.Bag, + ); + + return updated_item; + } + + func generate_random_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + rnd: felt + ) -> (item: Item) { + let (_, r) = unsigned_div_rem(rnd, 100); // set blank item - let Id = r; + let Id = rnd + 1; let (Slot) = ItemStats.item_slot(Id); // determined by Id let (Type) = ItemStats.item_type(Id); // determined by Id let (Material) = ItemStats.item_material(Id); // determined by Id @@ -64,7 +89,7 @@ namespace ItemLib { let Prefix_1 = 0; // name prefix blank let Prefix_2 = 0; // name suffix blank let Suffix = 0; // suffix blank - let Greatness = 0; // greatness blank, random? + let Greatness = 1; // greatness blank, random? let (CreatedBlock) = get_block_timestamp(); // timestamp let XP = 0; // xp blank let Adventurer = 0; // adventurer blank @@ -89,6 +114,77 @@ namespace ItemLib { ); } + func generate_item_by_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + Id: felt + ) -> (item: Item) { + let (Slot) = ItemStats.item_slot(Id); // determined by Id + let (Type) = ItemStats.item_type(Id); // determined by Id + let (Material) = ItemStats.item_material(Id); // determined by Id + let (Rank) = ItemStats.item_rank(Id); // determined by Id + let Prefix_1 = 0; // name prefix blank + let Prefix_2 = 0; // name suffix blank + let Suffix = 0; // suffix blank + let Greatness = 1; // greatness blank, random? + let (CreatedBlock) = get_block_timestamp(); // timestamp + let XP = 0; // xp blank + let Adventurer = 0; // adventurer blank + let Bag = 0; // bag blank + + return ( + Item( + Id=Id, + Slot=Slot, + Type=Type, + Material=Material, + Rank=Rank, + Prefix_1=Prefix_1, + Prefix_2=Prefix_2, + Suffix=Suffix, + Greatness=Greatness, + CreatedBlock=CreatedBlock, + XP=XP, + Adventurer=Adventurer, + Bag=Bag, + ), + ); + } + + func generate_starter_weapon{syscall_ptr: felt*, range_check_ptr}(item_id: felt) -> ( + item: Item + ) { + // set blank item + let (_Slot) = ItemStats.item_slot(item_id); // determined by Id + let (Type) = ItemStats.item_type(item_id); // determined by Id + let (Material) = ItemStats.item_material(item_id); // determined by Id + let (Rank) = ItemStats.item_rank(item_id); // determined by Id + let Prefix_1 = 0; // name prefix blank + let Prefix_2 = 0; // name suffix blank + let Suffix = 0; // suffix blank + let Greatness = 1; // greatness blank, random? + let (CreatedBlock) = get_block_timestamp(); // timestamp + let XP = 0; // xp blank + let Adventurer = 0; // adventurer blank + let Bag = 0; // bag blank + + return ( + Item( + Id=item_id, + Slot=_Slot, + Type=Type, + Material=Material, + Rank=Rank, + Prefix_1=Prefix_1, + Prefix_2=Prefix_2, + Suffix=Suffix, + Greatness=Greatness, + CreatedBlock=CreatedBlock, + XP=XP, + Adventurer=Adventurer, + Bag=Bag, + ), + ); + } + func set_item{syscall_ptr: felt*, range_check_ptr}( id: felt, greatness: felt, xp: felt, adventurer_id: felt, bag_id: felt ) -> (item: Item) { diff --git a/contracts/loot/loot/metadata.cairo b/contracts/loot/loot/metadata.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/loot/stats/combat.cairo b/contracts/loot/loot/stats/combat.cairo old mode 100644 new mode 100755 index e18018ca..749ab1ac --- a/contracts/loot/loot/stats/combat.cairo +++ b/contracts/loot/loot/stats/combat.cairo @@ -18,6 +18,7 @@ from contracts.loot.constants.combat import WeaponEfficacy, WeaponEfficiacyDamag from contracts.loot.beast.stats.beast import BeastStats from contracts.loot.beast.library import BeastLib from contracts.loot.loot.stats.item import ItemStats +from contracts.loot.constants.adventurer import AdventurerState from contracts.loot.constants.beast import Beast, BeastStatic, BeastDynamic from contracts.loot.constants.obstacle import Obstacle, ObstacleUtils @@ -103,29 +104,41 @@ namespace CombatStats { armor_type: felt, armor_rank: felt, armor_greatness: felt, + entity_level: felt, + rnd: felt ) -> (damage: felt) { alloc_locals; const rank_ceiling = 6; // use weapon rank and greatness to give every item a damage rating of 0-100 + // TODO: add item weight into damage calculation let base_weapon_damage = (rank_ceiling - attack_rank) * attack_greatness; // Get effectiveness of weapon vs armor let (attack_effectiveness) = weapon_vs_armor_efficacy(attack_type, armor_type); - let (total_weapon_damage) = get_attack_effectiveness( - attack_effectiveness, base_weapon_damage - ); // use armor rank and greatness to give armor a defense rating of 0-100 + // TODO: add item weight into strength calculation let armor_strength = (rank_ceiling - armor_rank) * armor_greatness; + let weapon_damage = base_weapon_damage - armor_strength; + + let (total_weapon_damage) = get_attack_effectiveness( + attack_effectiveness, weapon_damage + ); + // check if armor strength is less than or equal to weapon damage - let dealt_damage = is_le_felt(armor_strength, total_weapon_damage); + let dealt_damage = is_le_felt(armor_strength, base_weapon_damage); if (dealt_damage == 1) { // if it is, damage dealt will be positive so return it - let damage_dealt = total_weapon_damage - armor_strength; - return (damage_dealt,); + // @distracteddev: calculate whether hit is critical, formula = damage * (1.5)^critical + let (_, critical_hit_chance) = unsigned_div_rem(rnd, 4); + let critical_hit = is_le(critical_hit_chance, 0); + // @distracteddev: provide some multi here with adventurer level: e.g. damage + (1 + ((1 - level) * 0.1)) + let (adventurer_level_damage) = calculate_entity_level_boost(total_weapon_damage, entity_level); + let (critical_damage_dealt) = calculate_critical_damage(adventurer_level_damage, critical_hit); + return (critical_damage_dealt,); } else { // otherwise damage dealt will be negative so we return 0 return (0,); @@ -136,7 +149,7 @@ namespace CombatStats { // parameters: Item weapon, Item armor // returns: damage func calculate_damage_from_weapon{syscall_ptr: felt*, range_check_ptr}( - weapon: Item, armor: Item + weapon: Item, armor: Item, unpacked_adventurer: AdventurerState, rnd: felt ) -> (damage: felt) { alloc_locals; @@ -148,7 +161,7 @@ namespace CombatStats { // pass details of attack and armor to core damage calculation function let (damage_dealt) = calculate_damage( - attack_type, weapon.Rank, weapon.Greatness, armor_type, armor.Rank, armor.Greatness + attack_type, weapon.Rank, weapon.Greatness, armor_type, armor.Rank, armor.Greatness, unpacked_adventurer.Level, rnd ); // return damage @@ -157,7 +170,7 @@ namespace CombatStats { // Calculates damage dealt from a beast by converting beast into a Loot weapon and calling calculate_damage_from_weapon func calculate_damage_from_beast{syscall_ptr: felt*, range_check_ptr}( - beast: Beast, armor: Item + beast: Beast, armor: Item, rnd: felt ) -> (damage: felt) { alloc_locals; @@ -167,29 +180,24 @@ namespace CombatStats { // Get armor type // NOTE: @loothero if no armor then armor type is generic if (armor.Id == 0) { - let armor_type = Type.Armor.generic; - tempvar syscall_ptr: felt* = syscall_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar armor_type = armor_type; + // force armor_type generic + return calculate_damage( + attack_type, beast.Rank, beast.Level, Type.Armor.generic, armor.Rank, armor.Greatness, 1, rnd + ); } else { let (armor_type) = ItemStats.item_type(armor.Id); - tempvar syscall_ptr: felt* = syscall_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar armor_type = armor_type; + // pass details of attack and armor to core damage calculation function + // @distracteddev: added param to change based on adventurer level + // return damage + return calculate_damage( + attack_type, beast.Rank, beast.Level, armor_type, armor.Rank, armor.Greatness, 1, rnd + ); } - - // pass details of attack and armor to core damage calculation function - let (damage_dealt) = calculate_damage( - attack_type, beast.Rank, beast.Level, armor_type, armor.Rank, armor.Greatness - ); - - // return damage - return (damage_dealt,); } // Calculates damage dealt from a beast by converting beast into a Loot weapon and calling calculate_damage_from_weapon func calculate_damage_to_beast{syscall_ptr: felt*, range_check_ptr}( - beast: Beast, weapon: Item + beast: Beast, weapon: Item, unpacked_adventurer: AdventurerState, rnd: felt ) -> (damage: felt) { alloc_locals; @@ -198,29 +206,16 @@ namespace CombatStats { // If adventurer has no weapon, they get get generic (melee) if (weapon.Id == 0) { - // Generic will have low effectiveness - let weapon_type = Type.Weapon.generic; - // and low greatness - let weapon_greatness = 1; - tempvar syscall_ptr: felt* = syscall_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar weapon_type = weapon_type; - tempvar weapon_greatness = weapon_greatness; + // force generic type and greatness 1 + return calculate_damage( + Type.Weapon.generic, weapon.Rank, 1, armor_type, beast.Rank, beast.Level, unpacked_adventurer.Level, rnd + ); } else { - let weapon_type = weapon.Type; - let weapon_greatness = weapon.Greatness; - tempvar syscall_ptr: felt* = syscall_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar weapon_type = weapon_type; - tempvar weapon_greatness = weapon_greatness; + // return damage + return calculate_damage( + weapon.Type, weapon.Rank, weapon.Greatness, armor_type, beast.Rank, beast.Level, unpacked_adventurer.Level, rnd + ); } - - let (damage_dealt) = calculate_damage( - weapon_type, weapon.Rank, weapon_greatness, armor_type, beast.Rank, beast.Level - ); - - // return damage - return (damage_dealt,); } // Calculate damage from an obstacle @@ -229,19 +224,20 @@ namespace CombatStats { ) -> (damage: felt) { alloc_locals; - // Get beast type - let (attack_type) = ObstacleUtils.get_type_from_id(obstacle.Id); - // Get armor type let (armor_type) = ItemStats.item_type(armor.Id); - // pass details of attack and armor to core damage calculation function - let (damage_dealt) = calculate_damage( - attack_type, obstacle.Rank, obstacle.Greatness, armor_type, armor.Rank, armor.Greatness - ); - - // return damage dealt - return (damage_dealt,); + if (armor.Id == 0) { + // force armor type generic + return calculate_damage( + obstacle.Type, obstacle.Rank, obstacle.Greatness, Type.Armor.generic, armor.Rank, armor.Greatness, 1, 1 + ); + } else { + // return damage dealt + return calculate_damage( + obstacle.Type, obstacle.Rank, obstacle.Greatness, armor_type, armor.Rank, armor.Greatness, 1, 1 + ); + } } func calculate_xp_earned{syscall_ptr: felt*, range_check_ptr}(rank: felt, level: felt) -> ( @@ -294,4 +290,24 @@ namespace CombatStats { return (FALSE,); } } + + func calculate_entity_level_boost{syscall_ptr: felt*, range_check_ptr}(damage: felt, entity_level: felt) -> ( + entity_level_damage: felt + ) { + let format_level_boost = damage * (90 + (entity_level * 10)); + let (entity_level_damage,_) = unsigned_div_rem(format_level_boost, 100); + return (entity_level_damage,); + } + + func calculate_critical_damage{syscall_ptr: felt*, range_check_ptr}(damage: felt, critical: felt) -> ( + crtical_damage: felt + ) { + if (critical == TRUE) { + let format_critical_damage = damage * 150; + let (critical_damage,_) = unsigned_div_rem(format_critical_damage, 100); + return (critical_damage,); + } else { + return (damage,); + } + } } diff --git a/contracts/loot/loot/stats/item.cairo b/contracts/loot/loot/stats/item.cairo old mode 100644 new mode 100755 diff --git a/contracts/loot/readme.md b/contracts/loot/readme.md new file mode 100755 index 00000000..65aaeaba --- /dev/null +++ b/contracts/loot/readme.md @@ -0,0 +1,108 @@ +# Loot Survivor + +This is a fork of the OG Loot physics to show how a minigame can be created. + +This is experimental. Put a Fork in it. + +#### TODO High priority: +- ADD Statistics Points +-- At XP level - spend points onto a Stat level +-- Health Shop - Bid style + + +#### TODO Low priority: +- Multipler damage for adventurer Level. The Adventurer should both, deal more damange and receive more damage. + +### Objective + +Get the highest gold balance without dying.... Do you dare? You can always stop on top + + +### How to play + +First mint an Adventurer + +``` +nile mint_adventurer_with_item +``` + +You now have an adventurer - see them with: + +``` +nile get_adventurer 7 + +_____________________*+ loaf +*______________________ +_____________________________________________________ + +| Race : 1 | HomeRealm : 1 +| Birthdate : 1676262189 | Name : 1819238758 +| Order : 1 | ImageHash1 : 123 +| ImageHash2 : 123 | Health : 100 +| Level : 1 | Strength : 0 +| Dexterity : 0 | Vitality : 0 +| Intelligence : 0 | Wisdom : 0 +| Charisma : 0 | Luck : 0 +| XP : 0 | WeaponId : 0 +| ChestId : 0 | HeadId : 0 +| WaistId : 0 | FeetId : 0 +| HandsId : 0 | NeckId : 6 +| RingId : 0 | Status : +| Beast : 0 +``` + + + +You can do three things, choose wisely + +### Explore + +This is like searching the long grass in pokemon... You might discover a Beast... You might discover gold... You might discover a trap + +Once you have discovered - you can flee or fight. If you flee you might get hurt. + +``` +nile explore + +🤔 You discovered nothing + +try again.... +``` + +### Fight + + + +### Buy + +There is a native dynamic loot market. However there are some rules. + +- Items are not tradable from an Adventurer. They are soul bound to that Character. +- Items can be rerolled every 6hrs by anyone. It is an open function and the Adventurer who rolls it gets 3 gold. +- When rerolled the past Items that have not been purchased are no longer purchasable. +- You must bid on an Item above the minimum bid, currently (3) +- You must claim your item after you have won the bid + + +# LORDS + + +### Statistics + +| Type | Metal | Hide | Cloth | +| :------: | :-----: | :----: | :---: | +| Blade | Low | Medium | Strong| +| Bludgeon | Medium | Strong | Low | +| Magic | High | Low |Medium | + +### Blade: + low vs metal + medium vs hide + strong vs cloth +### Bludgeon: + medium vs metal + strong vs hide + low vs cloth +### Magic: + High vs metal + Low vs hide + Medium vs cloth \ No newline at end of file diff --git a/contracts/loot/utils/constants.cairo b/contracts/loot/utils/constants.cairo old mode 100644 new mode 100755 index 152ec32d..a6a90363 --- a/contracts/loot/utils/constants.cairo +++ b/contracts/loot/utils/constants.cairo @@ -9,3 +9,9 @@ namespace ExternalContractIds { const Lords = 2; const Treasury = 3; } + +const MINT_COST = 50000000000000000000; + +const STARTING_GOLD = 20; + +const KING_TRIBUTE_PERCENT = 10; \ No newline at end of file diff --git a/contracts/loot/utils/general.cairo b/contracts/loot/utils/general.cairo old mode 100644 new mode 100755 index b592d2dd..d37a8dcd --- a/contracts/loot/utils/general.cairo +++ b/contracts/loot/utils/general.cairo @@ -1,6 +1,9 @@ from starkware.cairo.common.cairo_builtins import HashBuiltin from starkware.cairo.common.math import assert_lt_felt from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.math import unsigned_div_rem +from starkware.cairo.common.math_cmp import is_le +from starkware.cairo.common.bool import TRUE, FALSE func _uint_to_felt{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( value: Uint256 @@ -8,3 +11,41 @@ func _uint_to_felt{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_p assert_lt_felt(value.high, 2 ** 123); return (value.high * (2 ** 128) + value.low,); } + +namespace Rarity { + const common = 595; + const uncommmon = 300; + const rare = 90; + const legendary = 10; + const mythic = 5; +} + +namespace RarityId { + const common = 1; + const uncommmon = 2; + const rare = 3; + const legendary = 4; + const mythic = 5; +} + +func rare_number_generator{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + number: felt +) -> (rarity: felt) { + let (_, r) = unsigned_div_rem(number, 1000); + + let legendary = is_le(r, Rarity.legendary); + if (legendary == TRUE) { + return (RarityId.legendary,); + } + + let rare = is_le(r, Rarity.rare); + if (rare == TRUE) { + return (RarityId.rare,); + } + + let uncommmon = is_le(r, Rarity.uncommmon); + if (uncommmon == TRUE) { + return (RarityId.uncommmon,); + } + return (RarityId.common,); +} diff --git a/contracts/metadata/metadata.cairo b/contracts/metadata/metadata.cairo old mode 100644 new mode 100755 diff --git a/contracts/nft_marketplace/bibliotheca_marketplace.cairo b/contracts/nft_marketplace/bibliotheca_marketplace.cairo old mode 100644 new mode 100755 diff --git a/contracts/poaps/crowns/LisbonCrown.cairo b/contracts/poaps/crowns/LisbonCrown.cairo old mode 100644 new mode 100755 diff --git a/contracts/poaps/crowns/metadata.cairo b/contracts/poaps/crowns/metadata.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/Arbiter.cairo b/contracts/settling_game/Arbiter.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/ModuleController.cairo b/contracts/settling_game/ModuleController.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/interfaces/ICrypts.cairo b/contracts/settling_game/interfaces/ICrypts.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/interfaces/IERC1155.cairo b/contracts/settling_game/interfaces/IERC1155.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/interfaces/IMintable.cairo b/contracts/settling_game/interfaces/IMintable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/interfaces/IRealms.cairo b/contracts/settling_game/interfaces/IRealms.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/interfaces/imodules.cairo b/contracts/settling_game/interfaces/imodules.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/interfaces/ixoroshiro.cairo b/contracts/settling_game/interfaces/ixoroshiro.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/library/IUtils.cairo b/contracts/settling_game/library/IUtils.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/library/library_module.cairo b/contracts/settling_game/library/library_module.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/buildings/Buildings.cairo b/contracts/settling_game/modules/buildings/Buildings.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/buildings/interface.cairo b/contracts/settling_game/modules/buildings/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/buildings/library.cairo b/contracts/settling_game/modules/buildings/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/calculator/Calculator.cairo b/contracts/settling_game/modules/calculator/Calculator.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/calculator/interface.cairo b/contracts/settling_game/modules/calculator/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/calculator/library.cairo b/contracts/settling_game/modules/calculator/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/combat/Combat.cairo b/contracts/settling_game/modules/combat/Combat.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/combat/constants.cairo b/contracts/settling_game/modules/combat/constants.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/combat/interface.cairo b/contracts/settling_game/modules/combat/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/combat/library.cairo b/contracts/settling_game/modules/combat/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/crypts/CryptRun.cairo b/contracts/settling_game/modules/crypts/CryptRun.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/crypts/L07_Crypts.cairo b/contracts/settling_game/modules/crypts/L07_Crypts.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/crypts/L08_Crypts_Resources.cairo b/contracts/settling_game/modules/crypts/L08_Crypts_Resources.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/crypts/constants.cairo b/contracts/settling_game/modules/crypts/constants.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/crypts/interface.cairo b/contracts/settling_game/modules/crypts/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/crypts/library.cairo b/contracts/settling_game/modules/crypts/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/example/Core.cairo b/contracts/settling_game/modules/example/Core.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/example/constants.cairo b/contracts/settling_game/modules/example/constants.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/example/interface.cairo b/contracts/settling_game/modules/example/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/example/library.cairo b/contracts/settling_game/modules/example/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/food/Food.cairo b/contracts/settling_game/modules/food/Food.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/food/interface.cairo b/contracts/settling_game/modules/food/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/food/library.cairo b/contracts/settling_game/modules/food/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/goblintown/GoblinTown.cairo b/contracts/settling_game/modules/goblintown/GoblinTown.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/goblintown/interface.cairo b/contracts/settling_game/modules/goblintown/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/goblintown/library.cairo b/contracts/settling_game/modules/goblintown/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/labor/Labor.cairo b/contracts/settling_game/modules/labor/Labor.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/labor/interface.cairo b/contracts/settling_game/modules/labor/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/labor/library.cairo b/contracts/settling_game/modules/labor/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/relics/Relics.cairo b/contracts/settling_game/modules/relics/Relics.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/relics/interface.cairo b/contracts/settling_game/modules/relics/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/relics/library.cairo b/contracts/settling_game/modules/relics/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/resources/Resources.cairo b/contracts/settling_game/modules/resources/Resources.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/resources/interface.cairo b/contracts/settling_game/modules/resources/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/resources/library.cairo b/contracts/settling_game/modules/resources/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/settling/Settling.cairo b/contracts/settling_game/modules/settling/Settling.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/settling/interface.cairo b/contracts/settling_game/modules/settling/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/travel/Travel.cairo b/contracts/settling_game/modules/travel/Travel.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/travel/interface.cairo b/contracts/settling_game/modules/travel/interface.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/modules/travel/library.cairo b/contracts/settling_game/modules/travel/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/proxy/PROXY_Logic.cairo b/contracts/settling_game/proxy/PROXY_Logic.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/proxy/library.cairo b/contracts/settling_game/proxy/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/tokens/Crypts_ERC721_Mintable.cairo b/contracts/settling_game/tokens/Crypts_ERC721_Mintable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/tokens/Lords_ERC20_Mintable.cairo b/contracts/settling_game/tokens/Lords_ERC20_Mintable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/tokens/Realms_ERC721_Mintable.cairo b/contracts/settling_game/tokens/Realms_ERC721_Mintable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/tokens/Resources_ERC1155_Mintable_Burnable.cairo b/contracts/settling_game/tokens/Resources_ERC1155_Mintable_Burnable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/tokens/S_Crypts_ERC721_Mintable.cairo b/contracts/settling_game/tokens/S_Crypts_ERC721_Mintable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/tokens/S_Realms_ERC721_Mintable.cairo b/contracts/settling_game/tokens/S_Realms_ERC721_Mintable.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/unused_modules/L06_Combat.cairo b/contracts/settling_game/unused_modules/L06_Combat.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/unused_modules/library_combat.cairo b/contracts/settling_game/unused_modules/library_combat.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/utils/constants.cairo b/contracts/settling_game/utils/constants.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/utils/game_structs.cairo b/contracts/settling_game/utils/game_structs.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/utils/general.cairo b/contracts/settling_game/utils/general.cairo old mode 100644 new mode 100755 diff --git a/contracts/settling_game/utils/pow2.cairo b/contracts/settling_game/utils/pow2.cairo old mode 100644 new mode 100755 diff --git a/contracts/solidity/loot/DistillLoot.sol b/contracts/solidity/loot/DistillLoot.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/loot/ILoot.sol b/contracts/solidity/loot/ILoot.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/pre/Bridge.sol b/contracts/solidity/pre/Bridge.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/pre/Journey.sol b/contracts/solidity/pre/Journey.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/pre/Vesting.sol b/contracts/solidity/pre/Vesting.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/ERC165.sol b/contracts/solidity/shared/interfaces/ERC165.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC1155.sol b/contracts/solidity/shared/interfaces/IERC1155.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC1155Meta.sol b/contracts/solidity/shared/interfaces/IERC1155Meta.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC1155Metadata.sol b/contracts/solidity/shared/interfaces/IERC1155Metadata.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC1155TokenReceiver.sol b/contracts/solidity/shared/interfaces/IERC1155TokenReceiver.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC165.sol b/contracts/solidity/shared/interfaces/IERC165.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC173.sol b/contracts/solidity/shared/interfaces/IERC173.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/interfaces/IERC20.sol b/contracts/solidity/shared/interfaces/IERC20.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/Address.sol b/contracts/solidity/shared/utils/Address.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/ERC165.sol b/contracts/solidity/shared/utils/ERC165.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/LibBytes.sol b/contracts/solidity/shared/utils/LibBytes.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/LibEIP712.sol b/contracts/solidity/shared/utils/LibEIP712.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/Ownable.sol b/contracts/solidity/shared/utils/Ownable.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/SafeMath.sol b/contracts/solidity/shared/utils/SafeMath.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/shared/utils/SignatureValidator.sol b/contracts/solidity/shared/utils/SignatureValidator.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/tokens/LootRealms.sol b/contracts/solidity/tokens/LootRealms.sol old mode 100644 new mode 100755 diff --git a/contracts/solidity/tokens/TheLordsToken.sol b/contracts/solidity/tokens/TheLordsToken.sol old mode 100644 new mode 100755 diff --git a/contracts/staking/README.md b/contracts/staking/README.md old mode 100644 new mode 100755 diff --git a/contracts/staking/SingleSidedStaking.cairo b/contracts/staking/SingleSidedStaking.cairo old mode 100644 new mode 100755 diff --git a/contracts/staking/Splitter.cairo b/contracts/staking/Splitter.cairo old mode 100644 new mode 100755 diff --git a/contracts/staking/interfaces/ISplitter.cairo b/contracts/staking/interfaces/ISplitter.cairo old mode 100644 new mode 100755 diff --git a/contracts/token/ERC1155_Mintable_Burnable.cairo b/contracts/token/ERC1155_Mintable_Burnable.cairo old mode 100644 new mode 100755 diff --git a/contracts/token/constants.cairo b/contracts/token/constants.cairo old mode 100644 new mode 100755 diff --git a/contracts/token/interfaces/IERC1155_Receiver.cairo b/contracts/token/interfaces/IERC1155_Receiver.cairo old mode 100644 new mode 100755 diff --git a/contracts/token/library.cairo b/contracts/token/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/utils/xoroshiro128_starstar.cairo b/contracts/utils/xoroshiro128_starstar.cairo old mode 100644 new mode 100755 diff --git a/contracts/yagi/erc4626/ERC4626.cairo b/contracts/yagi/erc4626/ERC4626.cairo old mode 100644 new mode 100755 diff --git a/contracts/yagi/erc4626/interfaces/IERC4626.cairo b/contracts/yagi/erc4626/interfaces/IERC4626.cairo old mode 100644 new mode 100755 diff --git a/contracts/yagi/erc4626/library.cairo b/contracts/yagi/erc4626/library.cairo old mode 100644 new mode 100755 diff --git a/contracts/yagi/utils/fixedpointmathlib.cairo b/contracts/yagi/utils/fixedpointmathlib.cairo old mode 100644 new mode 100755 diff --git a/data/coords.json b/data/coords.json old mode 100644 new mode 100755 diff --git a/data/crypts.json b/data/crypts.json old mode 100644 new mode 100755 diff --git a/data/crypts_affinities.json b/data/crypts_affinities.json old mode 100644 new mode 100755 diff --git a/data/crypts_environments.json b/data/crypts_environments.json old mode 100644 new mode 100755 diff --git a/data/json_data.json b/data/json_data.json old mode 100644 new mode 100755 diff --git a/data/orders.json b/data/orders.json old mode 100644 new mode 100755 diff --git a/data/realms.json b/data/realms.json old mode 100644 new mode 100755 diff --git a/data/realms_bit.json b/data/realms_bit.json old mode 100644 new mode 100755 diff --git a/data/resources.json b/data/resources.json old mode 100644 new mode 100755 diff --git a/data/wonders.json b/data/wonders.json old mode 100644 new mode 100755 diff --git a/lib/cairo_contracts b/lib/cairo_contracts index 70cbd05e..86f0f878 160000 --- a/lib/cairo_contracts +++ b/lib/cairo_contracts @@ -1 +1 @@ -Subproject commit 70cbd05ed24ccd147f24b18c638dbd6e7fea88bb +Subproject commit 86f0f878906211977a276ab40bff1484295b7f97 diff --git a/localhost.accounts.json b/localhost.accounts.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/localhost.accounts.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/node.json b/node.json old mode 100644 new mode 100755 diff --git a/protostar.toml b/protostar.toml old mode 100644 new mode 100755 index e02557d4..2bc48827 --- a/protostar.toml +++ b/protostar.toml @@ -1,5 +1,5 @@ ["protostar.config"] -protostar_version = "0.6.0" +protostar_version = "0.8.1" ["protostar.project"] libs_path = "./lib" diff --git a/pytest.ini b/pytest.ini old mode 100644 new mode 100755 diff --git a/realms_cli/.gitignore b/realms_cli/.gitignore old mode 100644 new mode 100755 diff --git a/realms_cli/README.md b/realms_cli/README.md old mode 100644 new mode 100755 diff --git a/realms_cli/amm/__init__.py b/realms_cli/amm/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/amm/change_values.py b/realms_cli/amm/change_values.py old mode 100644 new mode 100755 diff --git a/realms_cli/amm/deploy.py b/realms_cli/amm/deploy.py old mode 100644 new mode 100755 diff --git a/realms_cli/amm/fees.py b/realms_cli/amm/fees.py old mode 100644 new mode 100755 diff --git a/realms_cli/amm/readme.md b/realms_cli/amm/readme.md old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/__init__.py b/realms_cli/deploy/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/access.py b/realms_cli/deploy/access.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/contract_deployer.py b/realms_cli/deploy/contract_deployer.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/deploy_game_contracts.py b/realms_cli/deploy/deploy_game_contracts.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/guild_contracts.py b/realms_cli/deploy/guild_contracts.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/new_module_deployer.py b/realms_cli/deploy/new_module_deployer.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/set_coordinates.py b/realms_cli/deploy/set_coordinates.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/set_costs.py b/realms_cli/deploy/set_costs.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/set_realm_data.py b/realms_cli/deploy/set_realm_data.py old mode 100644 new mode 100755 diff --git a/realms_cli/deploy/update.py b/realms_cli/deploy/update.py old mode 100644 new mode 100755 index 5fda4735..9c248034 --- a/realms_cli/deploy/update.py +++ b/realms_cli/deploy/update.py @@ -1,12 +1,10 @@ from collections import namedtuple from nile.common import get_class_hash -from realms_cli.caller_invoker import wrapped_send, compile, wrapped_declare -from realms_cli.deployer import logged_deploy +from realms_cli.caller_invoker import wrapped_send, compile, wrapped_declare from realms_cli.config import Config from realms_cli.utils import delete_existing_deployment, delete_existing_declaration - -Contracts = namedtuple('Contracts', 'name') +Contracts = namedtuple("Contracts", "name") # STEPS # 0. Set new names in array accordingly to the tuple structure @@ -30,19 +28,18 @@ # Contracts("S_Realms_ERC721_Mintable"), # Contracts("Resources_ERC1155_Mintable_Burnable"), # Contracts("Exchange_ERC20_1155"), - # Contracts("Adventurer"), - Contracts("Loot"), + Contracts("Adventurer"), + # Contracts("LootMarketArcade"), + # Contracts("Beast"), ] async def run(nre): - config = Config(nre.network) - #---------------- SET MODULES ----------------# + # ---------------- SET MODULES ----------------# for contract in NEW_MODULES: - delete_existing_deployment(contract.name) delete_existing_declaration(contract.name) @@ -50,14 +47,7 @@ async def run(nre): compile(contract.name) await wrapped_declare( - config.ADMIN_ALIAS, contract.name, nre.network, contract.name) - - await logged_deploy( - nre.network, - config.ADMIN_ALIAS, - contract.name, - alias=contract.name, - calldata=[], + config.ADMIN_ALIAS, contract.name, nre.network, contract.name ) class_hash = get_class_hash(contract.name) diff --git a/realms_cli/loot/__init__.py b/realms_cli/loot/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/loot/deploy.py b/realms_cli/loot/deploy.py old mode 100644 new mode 100755 index b1acc995..8678dcfc --- a/realms_cli/loot/deploy.py +++ b/realms_cli/loot/deploy.py @@ -1,14 +1,12 @@ from collections import namedtuple -from realms_cli.deployer import logged_deploy -from realms_cli.caller_invoker import wrapped_send, wrapped_declare, declare_class +from realms_cli.caller_invoker import wrapped_declare, wrapped_send from realms_cli.config import Config, safe_load_deployment -from realms_cli.utils import str_to_felt, strhex_as_felt +from realms_cli.deployer import logged_deploy +from realms_cli.utils import str_to_felt, strhex_as_strfelt -from nile_upgrades.deploy_proxy import deploy_proxy from nile.common import get_class_hash from enum import IntEnum -import time class ExternalContractIds(IntEnum): @@ -35,21 +33,20 @@ class ModuleId(IntEnum): MODULE_CONTRACT_IMPLEMENTATIONS = [ ModuleContracts( "Adventurer", ModuleId.Adventurer), - ModuleContracts("Loot", ModuleId.Loot), + ModuleContracts("LootMarketArcade", ModuleId.Loot), ModuleContracts("Beast", ModuleId.Beast), ] TOKEN_CONTRACT_IMPLEMENTATIONS = [ ModuleContracts("Realms_ERC721_Mintable", ExternalContractIds.Realms_ERC721_Mintable), - ModuleContracts("Lords_ERC20_Mintable", - ExternalContractIds.Lords_ERC20_Mintable), ] # Lords LORDS = str_to_felt("Lords") LORDS_SYMBOL = str_to_felt("LORDS") DECIMALS = 18 +MINT_ROLE = 1835626100 # Realms REALMS = str_to_felt("Realms") @@ -68,21 +65,80 @@ async def run(nre): config = Config(nre.network) - #---------------- CONTROLLERS ----------------# - for contract in CONTROLLER_CONTRACT_IMPLEMENTATIONS: - + # # ---------------- CONTROLLERS ----------------# + # for contract in CONTROLLER_CONTRACT_IMPLEMENTATIONS: + + # await wrapped_declare( + # config.ADMIN_ALIAS, contract.name, nre.network, contract.alias) + + # class_hash = get_class_hash(contract.name) + + # await logged_deploy( + # nre.network, + # config.ADMIN_ALIAS, + # 'PROXY_Logic', + # alias='proxy_' + contract.alias, + # calldata=[class_hash], + # ) + + # await wrapped_declare( + # config.ADMIN_ALIAS, 'xoroshiro128_starstar', nre.network, 'xoroshiro128_starstar') + + # await logged_deploy( + # nre.network, + # config.ADMIN_ALIAS, + # 'xoroshiro128_starstar', + # alias='xoroshiro128_starstar', + # calldata=['123'], + # ) + + # await wrapped_send( + # network=config.nile_network, + # signer_alias=config.ADMIN_ALIAS, + # contract_alias="proxy_Arbiter_Loot", + # function="initializer", + # arguments=[config.ADMIN_ADDRESS], + # ) + + # module, _ = safe_load_deployment("proxy_Arbiter_Loot", nre.network) + + # await wrapped_send( + # network=config.nile_network, + # signer_alias=config.ADMIN_ALIAS, + # contract_alias="proxy_ModuleController_Loot", + # function="initializer", + # arguments=[module, config.ADMIN_ADDRESS], + # ) + + # module, _ = safe_load_deployment( + # "proxy_ModuleController_Loot", nre.network) + + # await wrapped_send( + # network=config.nile_network, + # signer_alias=config.ADMIN_ALIAS, + # contract_alias="proxy_Arbiter_Loot", + # function="set_address_of_controller", + # arguments=[ + # module, + # ] + # ) + + # xoroshiro, _ = safe_load_deployment("xoroshiro128_starstar", nre.network) + + # await wrapped_send( + # network=config.nile_network, + # signer_alias=config.ADMIN_ALIAS, + # contract_alias="proxy_Arbiter_Loot", + # function="set_xoroshiro", + # arguments=[xoroshiro], + # ) + + # ---------------- MODULE IMPLEMENTATIONS ----------------# + for contract in MODULE_CONTRACT_IMPLEMENTATIONS: await wrapped_declare( - config.ADMIN_ALIAS, contract.name, nre.network, contract.alias) - - class_hash = get_class_hash(contract.name) + config.ADMIN_ALIAS, contract.alias, nre.network, contract.alias) - await logged_deploy( - nre.network, - config.ADMIN_ALIAS, - contract.name, - alias=contract.alias, - calldata=[], - ) + class_hash = get_class_hash(contract.alias) await logged_deploy( nre.network, @@ -92,52 +148,11 @@ async def run(nre): calldata=[class_hash], ) - await wrapped_send( - network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, - contract_alias="proxy_Arbiter_Loot", - function="initializer", - arguments=[config.ADMIN_ADDRESS], - ) - - module, _ = safe_load_deployment("proxy_Arbiter_Loot", nre.network) - - await wrapped_send( - network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, - contract_alias="proxy_ModuleController_Loot", - function="initializer", - arguments=[module, config.ADMIN_ADDRESS], - ) - - module, _ = safe_load_deployment( - "proxy_ModuleController_Loot", nre.network) - - await wrapped_send( - network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, - contract_alias="proxy_Arbiter_Loot", - function="set_address_of_controller", - arguments=[ - module, - ] - ) - - xoroshiro, _ = safe_load_deployment("xoroshiro128_starstar", nre.network) - - await wrapped_send( - network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, - contract_alias="proxy_Arbiter_Loot", - function="set_xoroshiro", - arguments=[xoroshiro], - ) - - #---------------- MODULE IMPLEMENTATIONS ----------------# - for contract in MODULE_CONTRACT_IMPLEMENTATIONS: + # #---------------- TOKEN IMPLEMENTATIONS ----------------# + for contract in TOKEN_CONTRACT_IMPLEMENTATIONS: await wrapped_declare( config.ADMIN_ALIAS, contract.alias, nre.network, contract.alias) - + class_hash = get_class_hash(contract.alias) await logged_deploy( @@ -147,21 +162,36 @@ async def run(nre): alias='proxy_' + contract.alias, calldata=[class_hash], ) + await wrapped_declare( + config.ADMIN_ALIAS, 'Lords_ERC20_Mintable', nre.network, 'Lords_ERC20_Mintable') + + await logged_deploy( + nre.network, + config.ADMIN_ALIAS, + 'Lords_ERC20_Mintable', + alias='Lords_ERC20_Mintable', + calldata=[ + LORDS, + LORDS_SYMBOL, + DECIMALS, + config.ADMIN_ADDRESS, + ], + ) - # # # # #---------------- TOKEN IMPLEMENTATIONS ----------------# - # # # for contract in TOKEN_CONTRACT_IMPLEMENTATIONS: - # # # class_hash = await wrapped_declare( - # # # config.ADMIN_ALIAS, contract.contract_name, nre.network, contract.alias) + # give minting rights to the deployer - # # # await logged_deploy( - # # # nre, - # # # config.ADMIN_ALIAS, - # # # 'PROXY_Logic', - # # # alias='proxy_' + contract.alias, - # # # calldata=[strhex_as_felt(class_hash)], - # # # ) + await wrapped_send( + network=config.nile_network, + signer_alias=config.ADMIN_ALIAS, + contract_alias="Lords_ERC20_Mintable", + function="grant_role", + arguments=[ + MINT_ROLE, + config.ADMIN_ADDRESS, + ], + ) - #---------------- INIT MODULES ----------------# + # ---------------- INIT MODULES ----------------# deployment, _ = safe_load_deployment( "proxy_ModuleController_Loot", nre.network) @@ -169,7 +199,7 @@ async def run(nre): await wrapped_send( network=config.nile_network, signer_alias=config.ADMIN_ALIAS, - contract_alias="proxy_Loot", + contract_alias="proxy_LootMarketArcade", function="initializer", arguments=[ LOOT, @@ -203,37 +233,21 @@ async def run(nre): ], ) - # # # #---------------- INIT TOKENS ----------------# - - # # # await wrapped_send( - # # # network=config.nile_network, - # # # signer_alias=config.ADMIN_ALIAS, - # # # contract_alias="proxy_Lords_ERC20_Mintable", - # # # function="initializer", - # # # arguments=[ - # # # LORDS, - # # # LORDS_SYMBOL, - # # # DECIMALS, - # # # config.INITIAL_LORDS_SUPPLY, - # # # 0, - # # # config.ADMIN_ADDRESS, - # # # config.ADMIN_ADDRESS - # # # ], - # # # ) - - # # # await wrapped_send( - # # # network=config.nile_network, - # # # signer_alias=config.ADMIN_ALIAS, - # # # contract_alias="proxy_Realms_ERC721_Mintable", - # # # function="initializer", - # # # arguments=[ - # # # REALMS, # name - # # # REALMS_SYMBOL, # ticker - # # # config.ADMIN_ADDRESS, # contract_owner - # # # ], - # # # ) - - # #---------------- SET MODULES ----------------# + #---------------- INIT TOKENS ----------------# + + await wrapped_send( + network=config.nile_network, + signer_alias=config.ADMIN_ALIAS, + contract_alias="proxy_Realms_ERC721_Mintable", + function="initializer", + arguments=[ + REALMS, # name + REALMS_SYMBOL, # ticker + config.ADMIN_ADDRESS, # contract_owner + ], + ) + + #---------------- SET MODULES ----------------# module_contract_setup = [] for module in MODULE_CONTRACT_IMPLEMENTATIONS: @@ -269,10 +283,10 @@ async def run(nre): arguments=write_list ) - # # #---------------- SET EXTERNAL CONTRACT ADDRESSES ----------------# + #---------------- SET EXTERNAL CONTRACT ADDRESSES ----------------# lords_deployment, _ = safe_load_deployment( - "proxy_Lords_ERC20_Mintable", nre.network) + "Lords_ERC20_Mintable", nre.network) realms_deployment, _ = safe_load_deployment( "proxy_Realms_ERC721_Mintable", nre.network) diff --git a/realms_cli/nexus/deploy.py b/realms_cli/nexus/deploy.py old mode 100644 new mode 100755 diff --git a/realms_cli/nexus/upgrade.py b/realms_cli/nexus/upgrade.py old mode 100644 new mode 100755 diff --git a/realms_cli/pyproject.toml b/realms_cli/pyproject.toml old mode 100644 new mode 100755 index 5f3d9790..e2442d10 --- a/realms_cli/pyproject.toml +++ b/realms_cli/pyproject.toml @@ -22,8 +22,12 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "^3.7.11" +python = "^3.9.0" click = "^8.0.4" +dearpygui="1.8.0" +cairo-nile = "^0.13.0" +rich = "^13.3.1" +climage = "^0.1.3" [tool.poetry.dev-dependencies] darglint = "^1.5.8" @@ -40,7 +44,7 @@ pre-commit = "^2.9.3" flake8 = "^3.9.2" # We need to specify that click commands are Poetry entrypoints of type `nile_plugins`. Do not modify this -cairo-nile = "^0.11.0" +cairo-nile = "^0.13.0" [tool.poetry.plugins."nile_plugins.cli"] # Here you specify you command name and location = @@ -168,21 +172,34 @@ cairo-nile = "^0.11.0" #-----------LOOT -"mint_loot" = "realms_cli.loot.loot.mint_loot" -"get_loot" = "realms_cli.loot.loot.get_loot" -"set_loot" = "realms_cli.loot.loot.set_loot" +"loot" = "realms_cli.loot.loot.loot" +"get" = "realms_cli.loot.loot.get" +"bag" = "realms_cli.loot.loot.bag" +"bid" = "realms_cli.loot.loot.bid" +"claim" = "realms_cli.loot.loot.claim" +"market" = "realms_cli.loot.loot.market" + +#-----------LOOT MARKET +"mint_daily_items" = "realms_cli.loot.loot.mint_daily_items" + #-----------ADVENTURER -"mint_adventurer" = "realms_cli.loot.adventurer.mint_adventurer" +"new_adventurer" = "realms_cli.loot.adventurer.mint_adventurer_with_item" "get_adventurer" = "realms_cli.loot.adventurer.get_adventurer" "equip" = "realms_cli.loot.adventurer.equip" "unequip" = "realms_cli.loot.adventurer.unequip" "explore" = "realms_cli.loot.adventurer.explore" +"all_adventurers" = "realms_cli.loot.adventurer.all_adventurers" #-----------BEAST "get_beast" = "realms_cli.loot.beast.get_beast" "attack_beast" = "realms_cli.loot.beast.attack_beast" -"flee_from_beast" = "realms_cli.loot.beast.flee_from_beast" +"flee_beast" = "realms_cli.loot.beast.flee_beast" + +#-----------KING +"get_king" = "realms_cli.loot.loot.get_king" +"become_king" = "realms_cli.loot.loot.become_king" +"pay_king_tribute" = "realms_cli.loot.loot.pay_king_tribute" #-----------TRAVEL "set_coordinates" = "realms_cli.player.travel.set_coordinates" diff --git a/realms_cli/realms_cli/__init__.py b/realms_cli/realms_cli/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/admin/__init__.py b/realms_cli/realms_cli/admin/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/admin/main.py b/realms_cli/realms_cli/admin/main.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/binary_converter.py b/realms_cli/realms_cli/binary_converter.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/caller_invoker.py b/realms_cli/realms_cli/caller_invoker.py old mode 100644 new mode 100755 index b9d1f04d..6f66b482 --- a/realms_cli/realms_cli/caller_invoker.py +++ b/realms_cli/realms_cli/caller_invoker.py @@ -7,6 +7,7 @@ import subprocess import asyncio import os +import json from nile.core.declare import declare from nile.core.types.account import Account, get_nonce @@ -17,7 +18,6 @@ from realms_cli.config import Config from starkware.starknet.compiler.compile import compile_starknet_files - import logging from nile.common import get_class_hash, ABIS_DIRECTORY @@ -59,6 +59,7 @@ async def send_multi(self, to, method, calldata, nonce=None): max_fee=str(config.MAX_FEE), ) + # bind it to the account class so that we can use the function when signing Account.send_multi = send_multi @@ -81,8 +82,7 @@ def call(network, contract_alias, function, arguments) -> str: async def proxy_call(network, contract_alias, abi, function, params) -> str: """Nile proxy call function.""" - address, _ = next(deployments.load( - contract_alias, network)) or contract_alias + address, _ = next(deployments.load(contract_alias, network)) or contract_alias address = hex_address(address) @@ -99,33 +99,36 @@ async def proxy_call(network, contract_alias, abi, function, params) -> str: async def _call_async(network, contract_alias, function, arguments) -> str: """Nile async call function.""" - command = " ".join([ - "nile", - "call", - "--network", - network, - contract_alias, - function, - *map(str, arguments), - ]) + command = " ".join( + [ + "nile", + "call", + "--network", + network, + contract_alias, + function, + *map(str, arguments), + ] + ) proc = await asyncio.create_subprocess_shell( - command, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE) + command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) stdout, stderr = await proc.communicate() if stderr: - print(f'[stderr]\n{stderr.decode()}') + print(f"[stderr]\n{stderr.decode()}") return stdout.decode() async def _call_sync_manager(network, contract_alias, function, calldata) -> str: - """"Helper function to create multiple coroutines.""" - stdout = await asyncio.gather(*[ - _call_async(network, contract_alias, function, arguments) - for arguments in calldata - ]) + """ "Helper function to create multiple coroutines.""" + stdout = await asyncio.gather( + *[ + _call_async(network, contract_alias, function, arguments) + for arguments in calldata + ] + ) return stdout @@ -144,7 +147,7 @@ def wrapped_call(network, contract_alias, function, arguments) -> str: print("------- CALL ----------------------------------------------------") print(f"calling {function} from {contract_alias} with {arguments}") out = call(network, contract_alias, function, arguments) - print("------- CALL ----------------------------------------------------") + print("_________________________________________________________________") # return out such that it can be prettified at a higher level return out @@ -158,7 +161,7 @@ async def wrapped_proxy_call(network, contract_alias, abi, function, arguments) print("------- CALL ----------------------------------------------------") print(f"calling {function} from {contract_alias} with {arguments}") out = await proxy_call(network, contract_alias, abi, function, arguments) - print("------- CALL ----------------------------------------------------") + print("_________________________________________________________________") # return out such that it can be prettified at a higher level return out @@ -166,9 +169,12 @@ async def wrapped_proxy_call(network, contract_alias, abi, function, arguments) async def send(network, signer_alias, contract_alias, function, arguments) -> str: """Nile send function.""" account = await Account(signer_alias, network) - if isinstance(arguments[0], list): + if not arguments: + return await account.send_multi(contract_alias, function, []) + elif isinstance(arguments[0], list): return await account.send_multi(contract_alias, function, arguments) - return await account.send_multi(contract_alias, function, [arguments]) + else: + return await account.send_multi(contract_alias, function, [arguments]) async def wrapped_send(network, signer_alias, contract_alias, function, arguments): @@ -183,10 +189,14 @@ async def wrapped_send(network, signer_alias, contract_alias, function, argument out = await send(network, signer_alias, contract_alias, function, arguments) if out: _, tx_hash = parse_send(out) - get_tx_status(network, tx_hash,) + get_tx_status( + network, + tx_hash, + ) else: raise Exception("send message returned None") print("------- SEND ----------------------------------------------------") + return out def get_tx_status(network, tx_hash: str) -> dict: @@ -229,9 +239,18 @@ def deploy(network, alias) -> str: def compile(contract_alias) -> str: """Nile call function.""" + if os.path.dirname(__file__).split("/")[1] == "Users": + path = "/" + os.path.join( + os.path.dirname(__file__).split("/")[1], + os.path.dirname(__file__).split("/")[2], + "Documents", + "realms", + "realms-contracts", + ) + else: + path = "/workspaces/realms-contracts" - location = find_file( - '/workspaces/realms-contracts', contract_alias + '.cairo') + location = find_file(path, contract_alias + ".cairo") command = [ "nile", @@ -250,20 +269,34 @@ def find_file(root_dir, file_name): async def wrapped_declare(account, contract_name, network, alias): + if os.path.dirname(__file__).split("/")[1] == "Users": + path = "/" + os.path.join( + os.path.dirname(__file__).split("/")[1], + os.path.dirname(__file__).split("/")[2], + "Documents", + "realms", + "realms-contracts", + ) + else: + path = "/workspaces/realms-contracts" - location = find_file( - '/workspaces/realms-contracts', contract_name + '.cairo') + location = find_file(path, contract_name + ".cairo") account = await Account(account, network) compile_starknet_files( - files=[f"{location}"], debug_info=True, cairo_path=["/workspaces/realms-contracts/lib/cairo_contracts/src"] + files=[f"{location}"], + debug_info=True, + cairo_path=[path + "/lib/cairo_contracts/src"], ) - tx_wrapper = await account.declare(contract_name, max_fee=11111111111111) + tx_wrapper = await account.declare(contract_name, max_fee=4226601250467000) tx_status, declared_hash = await tx_wrapper.execute(watch_mode="track") - get_tx_status(network, str(tx_wrapper.hash),) + get_tx_status( + network, + str(tx_wrapper.hash), + ) return tx_wrapper @@ -276,17 +309,22 @@ async def declare_class(network, contract_name, account, max_fee, overriding_pat """ logging.debug(f"Declaring contract class {contract_name}...") class_hash = get_class_hash( - contract_name=contract_name, overriding_path=overriding_path) + contract_name=contract_name, overriding_path=overriding_path + ) padded_hash = hex_class_hash(class_hash) if class_hash_exists(class_hash, network): logging.debug(f"Contract class with hash {padded_hash} already exists") else: - tx = await account.declare(contract_name, max_fee=max_fee, overriding_path=overriding_path) + tx = await account.declare( + contract_name, max_fee=max_fee, overriding_path=overriding_path + ) tx_status, declared_hash = await tx.execute(watch_mode="track") if tx_status.status.is_rejected: raise Exception( - f"Could not declare contract class. Transaction rejected.", tx_status.error_message) + f"Could not declare contract class. Transaction rejected.", + tx_status.error_message, + ) if padded_hash != declared_hash: raise Exception( @@ -300,3 +338,17 @@ async def declare_class(network, contract_name, account, max_fee, overriding_pat def get_contract_abi(contract_name): return f"{ABIS_DIRECTORY}/{contract_name}.json" + + +def get_transaction_result(network, tx_hash): + command = [ + "starknet", + "get_transaction_trace", + "--hash", + tx_hash, + "--network", + "alpha-goerli", + ] + out = subprocess.check_output(command).strip().decode("utf-8") + out_dict = json.loads(out) + return out_dict["function_invocation"]["result"] diff --git a/realms_cli/realms_cli/config.py b/realms_cli/realms_cli/config.py old mode 100644 new mode 100755 index a1c5f4e5..46b887b8 --- a/realms_cli/realms_cli/config.py +++ b/realms_cli/realms_cli/config.py @@ -11,35 +11,35 @@ class ContractAlias(auto): - Settling = 'Settling' - Resources = 'Resources' - Arbiter = 'Arbiter' - ModuleController = 'ModuleController' - xoroshiro128_starstar = 'xoroshiro128_starstar' - Buildings = 'Buildings' - Calculator = 'Calculator' - Combat = 'Combat' - Travel = 'Travel' - Food = 'Food' - Relics = 'Relics' - GoblinTown = 'GoblinTown' - Lords_ERC20_Mintable = 'Lords_ERC20_Mintable' - Realms_ERC721_Mintable = 'Realms_ERC721_Mintable' - S_Realms_ERC721_Mintable = 'S_Realms_ERC721_Mintable' - Resources_ERC1155_Mintable_Burnable = 'Resources_ERC1155_Mintable_Burnable' - Exchange_ERC20_1155 = 'Exchange_ERC20_1155' - ModuleLootController = 'ModuleController_Loot' - ArbiterLoot = 'Arbiter_Loot' + Settling = "Settling" + Resources = "Resources" + Arbiter = "Arbiter" + ModuleController = "ModuleController" + xoroshiro128_starstar = "xoroshiro128_starstar" + Buildings = "Buildings" + Calculator = "Calculator" + Combat = "Combat" + Travel = "Travel" + Food = "Food" + Relics = "Relics" + GoblinTown = "GoblinTown" + Lords_ERC20_Mintable = "Lords_ERC20_Mintable" + Realms_ERC721_Mintable = "Realms_ERC721_Mintable" + S_Realms_ERC721_Mintable = "S_Realms_ERC721_Mintable" + Resources_ERC1155_Mintable_Burnable = "Resources_ERC1155_Mintable_Burnable" + Exchange_ERC20_1155 = "Exchange_ERC20_1155" + ModuleLootController = "ModuleController_Loot" + ArbiterLoot = "Arbiter_Loot" def safe_load_deployment(alias: str, network: str): """Safely loads address from deployments file""" try: address, _ = next(deployments.load(alias, network)) - print(f"Found deployment for alias {alias}.") + # print(f"Found deployment for alias {alias}.") return address, _ except StopIteration: - print(f"Deployment for alias {alias} not found.") + # print(f"Deployment for alias {alias} not found.") return None, None @@ -76,109 +76,144 @@ def __init__(self, nile_network: str): self.Relics_alias = "proxy_" + ContractAlias.Relics self.GoblinTown_alias = "proxy_" + ContractAlias.GoblinTown + # @distracteddev to change back self.Lords_ERC20_Mintable_alias = "proxy_" + ContractAlias.Lords_ERC20_Mintable - self.Realms_ERC721_Mintable_alias = "proxy_" + \ - ContractAlias.Realms_ERC721_Mintable - self.S_Realms_ERC721_Mintable_alias = "proxy_" + \ - ContractAlias.S_Realms_ERC721_Mintable - self.Resources_ERC1155_Mintable_Burnable_alias = "proxy_" + \ - ContractAlias.Resources_ERC1155_Mintable_Burnable + self.Realms_ERC721_Mintable_alias = ( + "proxy_" + ContractAlias.Realms_ERC721_Mintable + ) + self.S_Realms_ERC721_Mintable_alias = ( + "proxy_" + ContractAlias.S_Realms_ERC721_Mintable + ) + self.Resources_ERC1155_Mintable_Burnable_alias = ( + "proxy_" + ContractAlias.Resources_ERC1155_Mintable_Burnable + ) self.Exchange_ERC20_1155_alias = "proxy_" + ContractAlias.Exchange_ERC20_1155 self.ADMIN_ALIAS = "STARKNET_ADMIN_PRIVATE_KEY" self.ADMIN_ADDRESS, _ = safe_load_deployment( - "STARKNET_ADMIN_PRIVATE_KEY", self.nile_network) + "STARKNET_ADMIN_PRIVATE_KEY", self.nile_network + ) - self.INITIAL_LORDS_SUPPLY = 500000000 * (10 ** 18) + self.INITIAL_LORDS_SUPPLY = 500000000 * (10**18) self.USER_ALIAS = "STARKNET_PRIVATE_KEY" self.USER_ADDRESS, _ = safe_load_deployment( - "account-0", self.nile_network) + "STARKNET_PRIVATE_KEY", self.nile_network + ) self.ARBITER_ADDRESS, _ = safe_load_deployment( - ContractAlias.Arbiter, self.nile_network) + ContractAlias.Arbiter, self.nile_network + ) self.CONTROLLER_ADDRESS, _ = safe_load_deployment( - ContractAlias.ModuleController, self.nile_network) + ContractAlias.ModuleController, self.nile_network + ) self.ARBITER_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Arbiter, self.nile_network) + "proxy_" + ContractAlias.Arbiter, self.nile_network + ) self.CONTROLLER_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.ModuleController, self.nile_network) + "proxy_" + ContractAlias.ModuleController, self.nile_network + ) self.ARBITER_LOOT_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.ArbiterLoot, self.nile_network) + "proxy_" + ContractAlias.ArbiterLoot, self.nile_network + ) self.CONTROLLER_LOOT_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.ModuleLootController, self.nile_network) + "proxy_" + ContractAlias.ModuleLootController, self.nile_network + ) self.LORDS_ADDRESS, _ = safe_load_deployment( - ContractAlias.Lords_ERC20_Mintable, self.nile_network) + ContractAlias.Lords_ERC20_Mintable, self.nile_network + ) self.REALMS_ADDRESS, _ = safe_load_deployment( - ContractAlias.Realms_ERC721_Mintable, self.nile_network) + ContractAlias.Realms_ERC721_Mintable, self.nile_network + ) self.RESOURCES_ADDRESS, _ = safe_load_deployment( - ContractAlias.Resources_ERC1155_Mintable_Burnable, self.nile_network) + ContractAlias.Resources_ERC1155_Mintable_Burnable, self.nile_network + ) self.S_REALMS_ADDRESS, _ = safe_load_deployment( - ContractAlias.S_Realms_ERC721_Mintable, self.nile_network) - self.CRYPTS_ADDRESS, _ = safe_load_deployment( - "crypts", self.nile_network) - self.S_CRYPTS_ADDRESS, _ = safe_load_deployment( - "s_crypts", self.nile_network) + ContractAlias.S_Realms_ERC721_Mintable, self.nile_network + ) + self.CRYPTS_ADDRESS, _ = safe_load_deployment("crypts", self.nile_network) + self.S_CRYPTS_ADDRESS, _ = safe_load_deployment("s_crypts", self.nile_network) self.LORDS_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Lords_ERC20_Mintable, self.nile_network) + "proxy_" + ContractAlias.Lords_ERC20_Mintable, self.nile_network + ) self.REALMS_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Realms_ERC721_Mintable, self.nile_network) + "proxy_" + ContractAlias.Realms_ERC721_Mintable, self.nile_network + ) self.RESOURCES_MINT_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Resources_ERC1155_Mintable_Burnable, self.nile_network) + "proxy_" + ContractAlias.Resources_ERC1155_Mintable_Burnable, + self.nile_network, + ) self.S_REALMS_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.S_Realms_ERC721_Mintable, self.nile_network) + "proxy_" + ContractAlias.S_Realms_ERC721_Mintable, self.nile_network + ) # self.CRYPTS_PROXY_ADDRESS, _ = safe_load_deployment("proxy_crypts", self.nile_network) # self.S_CRYPTS_PROXY_ADDRESS, _ = safe_load_deployment("proxy_s_crypts", self.nile_network) self.SETTLING_ADDRESS, _ = safe_load_deployment( - ContractAlias.Settling, self.nile_network) + ContractAlias.Settling, self.nile_network + ) self.RESOURCES_ADDRESS, _ = safe_load_deployment( - ContractAlias.Resources, self.nile_network) + ContractAlias.Resources, self.nile_network + ) self.BUILDINGS_ADDRESS, _ = safe_load_deployment( - ContractAlias.Buildings, self.nile_network) + ContractAlias.Buildings, self.nile_network + ) self.CALCULATOR_ADDRESS, _ = safe_load_deployment( - ContractAlias.Calculator, self.nile_network) + ContractAlias.Calculator, self.nile_network + ) self.COMBAT_ADDRESS, _ = safe_load_deployment( - ContractAlias.Combat, self.nile_network) + ContractAlias.Combat, self.nile_network + ) # self.L07_CRYPTS_ADDRESS, _ = safe_load_deployment("L07_Crypts", self.nile_network) self.SETTLING_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Settling, self.nile_network) + "proxy_" + ContractAlias.Settling, self.nile_network + ) self.RESOURCES_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Resources, self.nile_network) + "proxy_" + ContractAlias.Resources, self.nile_network + ) self.BUILDINGS_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Buildings, self.nile_network) + "proxy_" + ContractAlias.Buildings, self.nile_network + ) self.CALCULATOR_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Calculator, self.nile_network) + "proxy_" + ContractAlias.Calculator, self.nile_network + ) self.L06_COMBAT_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_" + ContractAlias.Combat, self.nile_network) + "proxy_" + ContractAlias.Combat, self.nile_network + ) # self.L07_CRYPTS_PROXY_ADDRESS, _ = safe_load_deployment("proxy_L07_Crypts", self.nile_network) self.XOROSHIRO_ADDRESS, _ = safe_load_deployment( - ContractAlias.xoroshiro128_starstar, self.nile_network) + ContractAlias.xoroshiro128_starstar, self.nile_network + ) self.Exchange_ERC20_1155_ADDRESS, _ = safe_load_deployment( - "Exchange_ERC20_1155", self.nile_network) + "Exchange_ERC20_1155", self.nile_network + ) self.Exchange_ERC20_1155_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_Exchange_ERC20_1155", self.nile_network) + "proxy_Exchange_ERC20_1155", self.nile_network + ) self.GUILD_PROXY_CONTRACT, _ = safe_load_deployment( "proxy_GuildContract", self.nile_network ) self.PROXY_NEXUS, _ = safe_load_deployment( - "proxy_SingleSidedStaking", self.nile_network) + "proxy_SingleSidedStaking", self.nile_network + ) self.PROXY_SPLITTER, _ = safe_load_deployment( - "proxy_Splitter", self.nile_network) + "proxy_Splitter", self.nile_network + ) self.GOBLIN_TOWN_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_GoblinTown", self.nile_network) + "proxy_GoblinTown", self.nile_network + ) self.RESOURCES = [ "Wood", @@ -210,7 +245,7 @@ def __init__(self, nile_network: str): # "SunkenShekel", # "Demonhide", "Wheat", - "Fish" + "Fish", ] self.BUILDINGS = [ @@ -226,6 +261,7 @@ def __init__(self, nile_network: str): ] self.LOOT = [ + "tokenId", "Id", "Slot", "Type", @@ -235,14 +271,15 @@ def __init__(self, nile_network: str): "Prefix_2", "Suffix", "Greatness", - "CreatedBlock", + "Age", "XP", "Adventurer", "Bag", ] self.LOOT_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_Loot", self.nile_network) + "proxy_Loot", self.nile_network + ) self.ADVENTURER = [ "Race", @@ -271,11 +308,12 @@ def __init__(self, nile_network: str): "NeckId", "RingId", "Status", - "Beast" + "Beast", ] self.ADVENTURER_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_Adventurer", self.nile_network) + "proxy_Adventurer", self.nile_network + ) self.BEAST = [ "Id", @@ -292,4 +330,113 @@ def __init__(self, nile_network: str): ] self.BEAST_PROXY_ADDRESS, _ = safe_load_deployment( - "proxy_Beast", self.nile_network) + "proxy_Beast", self.nile_network + ) + + self.BID = ["Price", "Expiry", "Bidder", "Status"] + + self.LOOT_ITEMS = [ + "Pendant", + "Necklace", + "Amulet", + "SilverRing", + "BronzeRing", + "PlatinumRing", + "TitaniumRing", + "GoldRing", + "GhostWand", + "GraveWand", + "BoneWand", + "Wand", + "Grimoire", + "Chronicle", + "Tome", + "Book", + "DivineRobe", + "SilkRobe", + "LinenRobe", + "Robe", + "Shirt", + "Crown", + "DivineHood", + "SilkHood", + "LinenHood", + "Hood", + "BrightsilkSash", + "SilkSash", + "WoolSash", + "LinenSash", + "Sash", + "DivineSlippers", + "SilkSlippers", + "WoolShoes", + "LinenShoes", + "Shoes", + "DivineGloves", + "SilkGloves", + "WoolGloves", + "LinenGloves", + "Gloves", + "Katana", + "Falchion", + "Scimitar", + "LongSword", + "ShortSword", + "DemonHusk", + "DragonskinArmor", + "StuddedLeatherArmor", + "HardLeatherArmor", + "LeatherArmor", + "DemonCrown", + "DragonsCrown", + "WarCap", + "LeatherCap", + "Cap", + "DemonhideBelt", + "DragonskinBelt", + "StuddedLeatherBelt", + "HardLeatherBelt", + "LeatherBelt", + "DemonhideBoots", + "DragonskinBoots", + "StuddedLeatherBoots", + "HardLeatherBoots", + "LeatherBoots", + "DemonsHands", + "DragonskinGloves", + "StuddedLeatherGloves", + "HardLeatherGloves", + "LeatherGloves", + "Warhammer", + "Quarterstaff", + "Maul", + "Mace", + "Club", + "HolyChestplate", + "OrnateChestplate", + "PlateMail", + "ChainMail", + "RingMail", + "AncientHelm", + "OrnateHelm", + "GreatHelm", + "FullHelm", + "Helm", + "OrnateBelt", + "WarBelt", + "PlatedBelt", + "MeshBelt", + "HeavyBelt", + "HolyGreaves", + "OrnateGreaves", + "Greaves", + "ChainBoots", + "HeavyBoots", + "HolyGauntlets", + "OrnateGauntlets", + "Gauntlets", + "ChainGloves", + "HeavyGloves", + ] + + self.SLOT = ["Weapon", "Chest", "Head", "Waist", "Foot", "Hand", "Neck", "Ring"] diff --git a/realms_cli/realms_cli/coordinates.py b/realms_cli/realms_cli/coordinates.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/deployer.py b/realms_cli/realms_cli/deployer.py old mode 100644 new mode 100755 index d430d5e7..e86d9dbb --- a/realms_cli/realms_cli/deployer.py +++ b/realms_cli/realms_cli/deployer.py @@ -17,7 +17,7 @@ async def logged_deploy(network, account, contract_name, alias, calldata): unique=False, calldata=calldata, alias=alias, - max_fee=11111111111111 + max_fee=4226601250467000 ) await tx_wrapper.execute(watch_mode='track') diff --git a/realms_cli/realms_cli/exchange/__init__.py b/realms_cli/realms_cli/exchange/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/exchange/admin.py b/realms_cli/realms_cli/exchange/admin.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/exchange/trade.py b/realms_cli/realms_cli/exchange/trade.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/game_structs.py b/realms_cli/realms_cli/game_structs.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/loot/adventurer.py b/realms_cli/realms_cli/loot/adventurer.py old mode 100644 new mode 100755 index 7719bada..be6df3c9 --- a/realms_cli/realms_cli/loot/adventurer.py +++ b/realms_cli/realms_cli/loot/adventurer.py @@ -1,201 +1,296 @@ import asyncclick as click -from realms_cli.caller_invoker import wrapped_proxy_call, wrapped_send +from realms_cli.caller_invoker import wrapped_send, wrapped_proxy_call from realms_cli.config import Config -from realms_cli.utils import print_over_colums, uint, felt_to_str, str_to_felt, strhex_as_felt - +from realms_cli.utils import uint, str_to_felt +from realms_cli.loot.getters import _get_adventurer, _get_beast, print_adventurer @click.command() @click.option("--network", default="goerli") -@click.option('--race', is_flag=False, - metavar='', type=click.STRING, help='adventurer race', prompt=True) -@click.option('--home_realm', is_flag=False, - metavar='', type=click.STRING, help='adventurer home realm', prompt=True) -@click.option('--name', is_flag=False, - metavar='', type=click.STRING, help='adventurer name', prompt=True) -@click.option('--order', is_flag=False, - metavar='', type=click.STRING, help='adventurer order', prompt=True) -@click.option('--image_hash_1', is_flag=False, - metavar='', type=click.STRING, help='adventurer image hash part 1', prompt=True) -@click.option('--image_hash_2', is_flag=False, - metavar='', type=click.STRING, help='adventurer image hash part 2', prompt=True) -async def mint_adventurer(network, race, home_realm, name, order, image_hash_1, image_hash_2): +@click.option( + "--item", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer item to start", + prompt=True, +) +@click.option( + "--race", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer race", + prompt=True, +) +@click.option( + "--home_realm", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer home realm", + prompt=True, +) +@click.option( + "--name", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer name", + prompt=True, +) +@click.option( + "--order", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer order", + prompt=True, +) +@click.option( + "--image_hash_1", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer image hash part 1", + prompt=True, +) +@click.option( + "--image_hash_2", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer image hash part 2", + prompt=True, +) +async def new_adventurer( + network, item, race, home_realm, name, order, image_hash_1, image_hash_2 +): """ Mint a Random Loot Item """ config = Config(nile_network=network) - print('🪙 Minting lords ...') + print("🪙 Minting lords ...") await wrapped_send( network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, + signer_alias=config.USER_ALIAS, contract_alias=config.Lords_ERC20_Mintable_alias, function="mint", - arguments=[ - config.ADMIN_ADDRESS, - 100 * 10 ** 18, # uint 1 - 0 # uint 2 - ] + arguments=[config.USER_ADDRESS, 100 * 10**18, 0], # uint 1 # uint 2 ) - print('🪙 Minted lords ✅') + print("🪙 Minted lords ✅") - print('👍 Approving lords to be spent ...') + print("👍 Approving lords to be spent ...") await wrapped_send( network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, + signer_alias=config.USER_ALIAS, contract_alias=config.Lords_ERC20_Mintable_alias, function="approve", arguments=[ config.ADVENTURER_PROXY_ADDRESS, - 100 * 10 ** 18, # uint 1 - 0, # uint 2 - ] + 100 * 10**18, # uint 1 + 0, # uint 2 + ], ) - # print('👍 Approved lords to be spent ✅') + print("👍 Approved lords to be spent ✅") - # print('🤴 Minting adventurer ...') + print("🤴 Minting adventurer ...") await wrapped_send( network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, + signer_alias=config.USER_ALIAS, contract_alias="proxy_Adventurer", - function="mint", + function="mint_with_starting_weapon", arguments=[ - config.ADMIN_ADDRESS, - str_to_felt(race), - str_to_felt(home_realm), + config.USER_ADDRESS, + race, + home_realm, str_to_felt(name), - str_to_felt(order), - str_to_felt(image_hash_1), - str_to_felt(image_hash_2) - ] + order, + image_hash_1, + image_hash_2, + item, + ], ) - print('🤴 Minted adventurer ✅') + print("🤴 Minted adventurer ✅") @click.command() -@click.argument("adventurer_token_id", nargs=1) +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) @click.option("--network", default="goerli") async def get_adventurer(adventurer_token_id, network): """ Get Adventurer metadata """ - config = Config(nile_network=network) - out = await wrapped_proxy_call( - network=config.nile_network, - contract_alias="proxy_Adventurer", - abi='artifacts/abis/Adventurer.json', - function="get_adventurer_by_id", - arguments=[*uint(adventurer_token_id)] - ) - - out = out.split(" ") - - pretty_out = [] - for i, key in enumerate(config.ADVENTURER): - - # Output names for item name prefix1, prefix2, and suffix - if i in [25]: - pretty_out.append( - f"{key} : {felt_to_str(int(out[i]))}") - else: - pretty_out.append( - f"{key} : {int(out[i])}") - print("_____________________________________________________") - print("_____________________*+ " + - felt_to_str(int(out[3])) + " +*______________________") - print("_____________________________________________________") - print_over_colums(pretty_out) + await _get_adventurer(network, adventurer_token_id) @click.command() @click.option("--network", default="goerli") -@click.option('--adventurer', is_flag=False, - metavar='', type=click.STRING, help='adventurer id', prompt=True) -@click.option('--item', is_flag=False, - metavar='', type=click.STRING, help='item id', prompt=True) -async def equip(network, adventurer, item): +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option( + "--item", + is_flag=False, + metavar="", + type=click.STRING, + help="item id", + prompt=True, +) +async def equip(network, adventurer_token_id, item): """ Equip loot item """ config = Config(nile_network=network) - print('🫴 Equiping item ...') + print("🫴 Equiping item ...") await wrapped_send( network=config.nile_network, signer_alias=config.USER_ALIAS, contract_alias="proxy_Adventurer", function="equip_item", - arguments=[*uint(adventurer), *uint(item)] + arguments=[*uint(adventurer_token_id), *uint(item)], ) - print('🫴 Equiped item ✅') + print("🫴 Equiped item ✅") + await _get_adventurer(network, adventurer_token_id) @click.command() @click.option("--network", default="goerli") -@click.option('--adventurer', is_flag=False, - metavar='', type=click.STRING, help='adventurer id', prompt=True) -@click.option('--item', is_flag=False, - metavar='', type=click.STRING, help='item id', prompt=True) -async def unequip(network, adventurer, item): +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option( + "--item", + is_flag=False, + metavar="", + type=click.STRING, + help="item id", + prompt=True, +) +async def unequip(network, adventurer_token_id, item): """ Unequip loot item """ config = Config(nile_network=network) - print('🫳 Unequiping item ...') + print("🫳 Unequiping item ...") await wrapped_send( network=config.nile_network, signer_alias=config.USER_ALIAS, contract_alias="proxy_Adventurer", function="unequip_item", - arguments=[*uint(adventurer), *uint(item)] + arguments=[*uint(adventurer_token_id), *uint(item)], ) - print('🫳 Unequiped item ...') + print("🫳 Unequiped item ...") + await _get_adventurer(network, adventurer_token_id) @click.command() @click.option("--network", default="goerli") -@click.option('--adventurer', is_flag=False, - metavar='', type=click.STRING, help='adventurer id', prompt=True) -async def explore(network, adventurer): +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +async def explore(network, adventurer_token_id): """ Explore with adventurer """ config = Config(nile_network=network) - print('👣 Exploring ...') + print("👣 Exploring ...") await wrapped_send( network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, + signer_alias=config.USER_ALIAS, contract_alias="proxy_Adventurer", function="explore", - arguments=[*uint(adventurer)] + arguments=[*uint(adventurer_token_id)], ) - print('👣 Explored ✅') + print("👣 Explored ✅") + + out = await _get_adventurer(network, adventurer_token_id) + + if out[23] == "1": + print("🧌 You have discovered a beast") + await _get_beast(out[26], network) + else: + print("🤔 You discovered nothing") + + + +@click.command() +@click.option("--network", default="goerli") +async def all_adventurers(network): + """ + Get all your Adventurers you own. + """ + config = Config(nile_network=network) out = await wrapped_proxy_call( network=config.nile_network, contract_alias="proxy_Adventurer", - abi='artifacts/abis/Adventurer.json', - function="get_adventurer_by_id", - arguments=[*uint(adventurer)] + abi="artifacts/abis/Adventurer.json", + function="balance_of", + arguments=[config.USER_ADDRESS], ) out = out.split(" ") - if out[23] == '1': - print("🧌 You have discovered a beast") - else: - print("🤔 You discovered nothing") + all_items = [] + + for i in range(0, int(out[0])): + item = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="token_of_owner_by_index", + arguments=[config.USER_ADDRESS, *uint(i)], + ) + + id = item.split(" ") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="get_adventurer_by_id", + arguments=[*uint(id[0])], + ) + + all_items.append(out) + + print_adventurer(all_items) diff --git a/realms_cli/realms_cli/loot/beast.py b/realms_cli/realms_cli/loot/beast.py old mode 100644 new mode 100755 index 06e38c8c..20d3d741 --- a/realms_cli/realms_cli/loot/beast.py +++ b/realms_cli/realms_cli/loot/beast.py @@ -1,139 +1,106 @@ -import anyio import asyncclick as click -from realms_cli.caller_invoker import wrapped_call, wrapped_send, wrapped_proxy_call +from realms_cli.caller_invoker import wrapped_send from realms_cli.config import Config -from realms_cli.utils import print_over_colums, uint, felt_to_str, str_to_felt +from realms_cli.utils import uint from realms_cli.loot.constants import BEASTS +from realms_cli.loot.getters import _get_adventurer, _get_beast @click.command() -@click.argument("beast_token_id", nargs=1) +@click.option( + "--beast_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="beast id", + prompt=True, +) @click.option("--network", default="goerli") async def get_beast(beast_token_id, network): """ Get Beast metadata """ - config = Config(nile_network=network) - - out = await wrapped_proxy_call( - network=config.nile_network, - contract_alias="proxy_Beast", - abi='artifacts/abis/Beast.json', - function="get_beast_by_id", - arguments=[*uint(beast_token_id)], - ) - out = out.split(" ") - - pretty_out = [] - for i, key in enumerate(config.BEAST): - - # Output names for beast name prefix1, prefix2, and suffix - if i in [11]: - pretty_out.append( - f"{key} : {felt_to_str(int(out[i]))}") - else: - pretty_out.append( - f"{key} : {int(out[i])}") - print("_____________________________________________________") - print("_____________________*+ " + - BEASTS[str(int(out[0]))] + " +*______________________") - print("_____________________________________________________") - print_over_colums(pretty_out) + await _get_beast(beast_token_id, network) @click.command() -@click.option('--beast', is_flag=False, - metavar='', type=click.STRING, help='beast id', prompt=True) +@click.option( + "--beast_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="beast id", + prompt=True, +) @click.option("--network", default="goerli") -async def attack_beast(beast, network): +async def attack_beast(beast_token_id, network): """ Attack beast """ config = Config(nile_network=network) - print('🧌 Attacking beast ...') + print("🧌 Attacking beast ...") await wrapped_send( network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, + signer_alias=config.USER_ALIAS, contract_alias="proxy_Beast", function="attack", - arguments=[*uint(beast)] + arguments=[*uint(beast_token_id)], ) - print('🧌 Attacked beast ✅') + print("🧌 Attacked beast ✅") - beast_out = await wrapped_proxy_call( - network=config.nile_network, - contract_alias="proxy_Beast", - abi='artifacts/abis/Beast.json', - function="get_beast_by_id", - arguments=[*uint(beast)] - ) - beast_out = beast_out.split(" ") + beast_out = await _get_beast(beast_token_id, network) - adventurer_out = await wrapped_proxy_call( - network=config.nile_network, - contract_alias="proxy_Adventurer", - abi='artifacts/abis/Adventurer.json', - function="get_adventurer_by_id", - arguments=[*uint(beast_out[7])], - ) - adventurer_out = adventurer_out.split(" ") + adventurer_out = await _get_adventurer(network, beast_out[7]) - if adventurer_out[4] == '0': + if adventurer_out[4] == "0": print(f"🪦 You have been killed") else: print( - f"🤕 You didn't kill and were counterattacked, you have {adventurer_out[4]} health remaining") + f"🤕 You didn't kill and were counterattacked, you have {adventurer_out[7]} health remaining" + ) - if beast_out[6] == '0': + if beast_out[6] == "0": print(f"💀 You have killed the {BEASTS[str(int(beast_out[0]))]} 🎉") else: print( - f"👹 You hurt the {BEASTS[str(int(beast_out[0]))]}, health is now {beast_out[6]}") + f"👹 You hurt the {BEASTS[str(int(beast_out[0]))]}, health is now {beast_out[6]}" + ) @click.command() -@click.option('--beast', is_flag=False, - metavar='', type=click.STRING, help='beast id', prompt=True) +@click.option( + "--beast_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="beast id", + prompt=True, +) @click.option("--network", default="goerli") -async def flee_from_beast(beast, network): +async def flee_beast(beast_token_id, network): """ Flee from beast """ config = Config(nile_network=network) - print('🏃‍♂️ Fleeing from beast ...') + print("🏃‍♂️ Fleeing from beast ...") await wrapped_send( network=config.nile_network, signer_alias=config.USER_ALIAS, contract_alias="proxy_Beast", function="flee", - arguments=[*uint(beast)] + arguments=[*uint(beast_token_id)], ) - beast_out = await wrapped_proxy_call( - network=config.nile_network, - contract_alias="proxy_Beast", - abi='artifacts/abis/Beast.json', - function="get_beast_by_id", - arguments=[*uint(beast)] - ) - beast_out = beast_out.split(" ") + beast_out = await _get_beast(beast_token_id, network) - adventurer_out = await wrapped_proxy_call( - network=config.nile_network, - contract_alias="proxy_Adventurer", - abi='artifacts/abis/Adventurer.json', - function="get_adventurer_by_id", - arguments=[*uint(beast_out[7])], - ) - adventurer_out = adventurer_out.split(" ") + adventurer_out = await _get_adventurer(network, beast_out[7]) - if adventurer_out[23] == '0': + if adventurer_out[23] == "0": print(f"🏃‍♂️ You successfully fled from beast ✅") - if adventurer_out[23] == '1': - print( - f"😫 You have been ambushed! Your health is now {adventurer_out[4]}") + if adventurer_out[23] == "1": + print(f"😫 You have been ambushed! Your health is now {adventurer_out[4]}") diff --git a/realms_cli/realms_cli/loot/constants.py b/realms_cli/realms_cli/loot/constants.py old mode 100644 new mode 100755 index 04dfda82..71deea01 --- a/realms_cli/realms_cli/loot/constants.py +++ b/realms_cli/realms_cli/loot/constants.py @@ -1,23 +1,190 @@ - - - BEASTS = { "1": "Pheonix", "2": "Griffin", "3": "Minotaur", "4": "Basilisk", - "5": "Wraith", - "6": "Ghoul", - "7": "Goblin", - "8": "Skeleton", - "9": "Giant", - "10": "Yeti", - "11": "Orc", - "12": "Beserker", - "13": "Ogre", - "14": "Dragon", - "15": "Vampire", - "16": "Werewolf", - "17": "Spider", - "18": "Rat", -} \ No newline at end of file + "5": "Gnome", + "6": "Wraith", + "7": "Ghoul", + "8": "Goblin", + "9": "Skeleton", + "10": "Golem", + "11": "Giant", + "12": "Yeti", + "13": "Orc", + "14": "Beserker", + "15": "Ogre", + "16": "Dragon", + "17": "Vampire", + "18": "Werewolf", + "19": "Spider", + "20": "Rat", +} + +ITEMS = { + 1: "Pendant", + 2: "Necklace", + 3: "Amulet", + 4: "SilverRing", + 5: "BronzeRing", + 6: "PlatinumRing", + 7: "TitaniumRing", + 8: "GoldRing", + 9: "GhostWand", + 10: "GraveWand", + 11: "BoneWand", + 12: "Wand", + 13: "Grimoire", + 14: "Chronicle", + 15: "Tome", + 16: "Book", + 17: "DivineRobe", + 18: "SilkRobe", + 19: "LinenRobe", + 20: "Robe", + 21: "Shirt", + 22: "Crown", + 23: "DivineHood", + 24: "SilkHood", + 25: "LinenHood", + 26: "Hood", + 27: "BrightsilkSash", + 28: "SilkSash", + 29: "WoolSash", + 30: "LinenSash", + 31: "Sash", + 32: "DivineSlippers", + 33: "SilkSlippers", + 34: "WoolShoes", + 35: "LinenShoes", + 36: "Shoes", + 37: "DivineGloves", + 38: "SilkGloves", + 39: "WoolGloves", + 40: "LinenGloves", + 41: "Gloves", + 42: "Katana", + 43: "Falchion", + 44: "Scimitar", + 45: "LongSword", + 46: "ShortSword", + 47: "DemonHusk", + 48: "DragonskinArmor", + 49: "StuddedLeatherArmor", + 50: "HardLeatherArmor", + 51: "LeatherArmor", + 52: "DemonCrown", + 53: "DragonsCrown", + 54: "WarCap", + 55: "LeatherCap", + 56: "Cap", + 57: "DemonhideBelt", + 58: "DragonskinBelt", + 59: "StuddedLeatherBelt", + 60: "HardLeatherBelt", + 61: "LeatherBelt", + 62: "DemonhideBoots", + 63: "DragonskinBoots", + 64: "StuddedLeatherBoots", + 65: "HardLeatherBoots", + 66: "LeatherBoots", + 67: "DemonsHands", + 68: "DragonskinGloves", + 69: "StuddedLeatherGloves", + 70: "HardLeatherGloves", + 71: "LeatherGloves", + 72: "Warhammer", + 73: "Quarterstaff", + 74: "Maul", + 75: "Mace", + 76: "Club", + 77: "HolyChestplate", + 78: "OrnateChestplate", + 79: "PlateMail", + 80: "ChainMail", + 81: "RingMail", + 82: "AncientHelm", + 83: "OrnateHelm", + 84: "GreatHelm", + 85: "FullHelm", + 86: "Helm", + 87: "OrnateBelt", + 88: "WarBelt", + 89: "PlatedBelt", + 90: "MeshBelt", + 91: "HeavyBelt", + 92: "HolyGreaves", + 93: "OrnateGreaves", + 94: "Greaves", + 95: "ChainBoots", + 96: "HeavyBoots", + 97: "HolyGauntlets", + 98: "OrnateGauntlets", + 99: "Gauntlets", + 100: "ChainGloves", + 101: "HeavyGloves", +} + +RACES = { + 1: "Elf", + 2: "Fox", + 3: "Giant", + 4: "Human", + 5: "Orc", + 6: "Demon", + 7: "Goblin", + 8: "Fish", + 9: "Cat", + 10: "Frog", +} + +ORDERS = { + 1: "Power", + 2: "Giants", + 3: "Titans", + 4: "Skill", + 5: "Perfection", + 6: "Brilliance", + 7: "Enlightenment", + 8: "Protection", + 9: "Twins", + 10: "Reflection", + 11: "Detection", + 12: "Fox", + 13: "Vitriol", + 14: "Fury", + 15: "Rage", + 16: "Anger", +} + +STATS = { + 2: "Strength", + 3: "Dexterity", + 4: "Vitality", + 5: "Intelligence", + 6: "Wisdom", + 7: "Charisma", + 8: "Luck", +} + +OBSTACLES = { + 1: "Demonic Alter", + 2: "Curse", + 3: "Hex", + 4: "Magic Lock", + 5: "Dark Mist", + 6: "Collapsing Ceiling", + 7: "Crushing Walls", + 8: "Rockslide", + 9: "Tumbling Boulders", + 10: "Swinging Logs", + 11: "Pendulum Blades", + 12: "Flame Jet", + 13: "Poision Dart", + 14: "Spiked Pit", + 15: "Hidden Arrow", +} + +DISCOVERY_TYPES = {0: "Nothing", 1: "Beast", 2: "Obstacle", 3: "Item", 4: "Adventurer"} + +ITEM_DISCOVERY_TYPES = {0: "Gold", 1: "XP", 2: "Loot", 3: "Health"} diff --git a/realms_cli/realms_cli/loot/getters.py b/realms_cli/realms_cli/loot/getters.py new file mode 100644 index 00000000..397a92c8 --- /dev/null +++ b/realms_cli/realms_cli/loot/getters.py @@ -0,0 +1,171 @@ +import os +from realms_cli.caller_invoker import wrapped_proxy_call +from realms_cli.config import Config +from realms_cli.utils import print_over_colums, uint, felt_to_str, convert_unix_time +from realms_cli.loot.constants import BEASTS +from rich.console import Console +from rich.table import Table +import climage + +console = Console() + + +async def _get_beast(beast_token_id, network): + """ + Get Beast metadata + """ + config = Config(nile_network=network) + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Beast", + abi="artifacts/abis/Beast.json", + function="get_beast_by_id", + arguments=[*uint(beast_token_id)], + ) + _print_beast(out.split(" ")) + + return out.split(" ") + + +def _print_beast(out): + config = Config(nile_network="goerli") + pretty_out = [] + for i, key in enumerate(config.BEAST): + # Output names for beast name prefix1, prefix2, and suffix + if i in [11]: + pretty_out.append(f"{key} : {felt_to_str(int(out[i]))}") + else: + pretty_out.append(f"{key} : {int(out[i])}") + print("_____________________________________________________") + print( + "_____________________*+ " + + BEASTS[str(int(out[0]))] + + " +*______________________" + ) + print("_____________________________________________________") + print_over_colums(pretty_out) + + +async def _get_adventurer(network, adventurer_token_id): + config = Config(nile_network=network) + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="get_adventurer_by_id", + arguments=[*uint(adventurer_token_id)], + ) + + print_adventurer([out]) + return out.split(" ") + + +def print_adventurer(out_list): + config = Config(nile_network="goerli") + table = Table(show_header=True, header_style="bold magenta") + + for i, key in enumerate(config.ADVENTURER): + table.add_column(key) + + for out in out_list: + out = out.split(" ") + item = out[:27] + item = format_array(3, item, felt_to_str(int(out[3]))) + table.add_row(*item) + + console.print(table) + + +async def _get_loot(loot_token_id, network): + config = Config(nile_network=network) + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_item_by_token_id", + arguments=[*uint(loot_token_id)], + ) + out = out.split(" ") + print_loot(out) + return out + + +def print_loot(out_list): + config = Config(nile_network="goerli") + table = Table(show_header=True, header_style="bold magenta") + + for i, key in enumerate(config.LOOT): + table.add_column(key) + + for out in out_list: + item = out[:14] + if out[0] != "0": + item = format_array(1, item, config.LOOT_ITEMS[int(out[1]) - 1]) + else: + item = format_array(1, item, "none") + + table.add_row(*item) + + console.print(table) + + +def print_loot_bid(out): + config = Config(nile_network="goerli") + pretty_bid_out = [] + for i, key in enumerate(config.BID): + if key == "Expiry": + pretty_bid_out.append(f"{key} : {convert_unix_time(int(out[i + 13]))}") + else: + pretty_bid_out.append(f"{key} : {int(out[i + 13])}") + + print_over_colums(pretty_bid_out) + + +def print_loot_and_bid(out_array): + config = Config(nile_network="goerli") + + table = Table(show_header=True, header_style="bold magenta") + for i, key in enumerate(config.LOOT): + table.add_column(key) + + for i, key in enumerate(config.BID): + table.add_column(key) + + for out in out_array: + item = out[:14] + bid = out[14:18] + + item = format_array(1, item, config.LOOT_ITEMS[int(out[1]) - 1]) + + item = format_array(2, item, config.SLOT[int(item[2]) - 1]) + + bid = format_array(1, bid, convert_unix_time(int(bid[1]))) + + table.add_row(*item, *bid) + + console.print(table) + + +def format_array(index, array, value): + array[index] = value + return array + + +def print_beast_img(id): + path = "realms_cli/realms_cli/loot/images/beasts/{}.png".format(id) + if os.path.exists(path): + print(climage.convert(path, is_unicode=True)) + else: + print( + climage.convert( + "realms_cli/realms_cli/loot/images/beasts/1.png", is_unicode=True + ) + ) + + +def print_player(): + print( + climage.convert("realms_cli/realms_cli/loot/images/player.png", is_unicode=True) + ) diff --git a/realms_cli/realms_cli/loot/gui.py b/realms_cli/realms_cli/loot/gui.py new file mode 100644 index 00000000..6b5f42be --- /dev/null +++ b/realms_cli/realms_cli/loot/gui.py @@ -0,0 +1,863 @@ +import asyncio +import datetime +import dearpygui.dearpygui as dpg +import subprocess +from realms_cli.config import Config +from realms_cli.caller_invoker import wrapped_proxy_call +from realms_cli.loot.constants import ITEMS, RACES, ORDERS, STATS, BEASTS +from realms_cli.utils import uint, felt_to_str +from realms_cli.loot.getters import ( + format_array, + _get_beast, + _get_adventurer, + print_loot_and_bid, +) + + +async def get_adventurers(): + config = Config(nile_network="goerli") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="balance_of", + arguments=[config.USER_ADDRESS], + ) + + out = out.split(" ") + + all_adventurers = [] + + for i in range(0, int(out[0])): + item = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="token_of_owner_by_index", + arguments=[config.USER_ADDRESS, *uint(i)], + ) + + id = item.split(" ") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="get_adventurer_by_id", + arguments=[*uint(id[0])], + ) + + # print(felt_to_str(int(out[3]))) + out = out.split(" ") + # needing to add to get rid of weird bytecode + if out[3].startswith("0x"): + out = felt_to_str(int(out[3], 16)) + else: + out = felt_to_str(int(out[3])) + all_adventurers.append("".join(out).replace("\x00", "") + " - " + id[0]) + return all_adventurers + + +async def update_adventurer_list(id): + config = Config(nile_network="goerli") + + adventurers = await get_adventurers() + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="get_adventurer_by_id", + arguments=[*uint(id)], + ) + out = out.split(" ") + # needing to add to get rid of weird bytecode + adventurers.append( + "".join(felt_to_str(int(out[3]))).replace("\x00", "") + " - " + id[0] + ) + print(adventurers) + dpg.configure_item("adventurer_id", items=adventurers) + + +def get_adventurer(sender, app_data, user_dat): + dpg.add_text( + "Getting adventurer", + tag="get_adventurer_load", + pos=[700, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + value = dpg.get_value("adventurer_id").split(" - ")[-1] + adventurer_out = asyncio.run(_get_adventurer("goerli", value)) + print(adventurer_out) + update_gold(value) + update_beast(adventurer_out[26]) + update_health(value) + update_equipped_items(adventurer_out) + dpg.delete_item("get_adventurer_load") + dpg.delete_item("loader") + + +def new_adventurer(sender, app_data, user_data): + dpg.add_text( + "Minting Adventurer", + tag="mint_adventurer_load", + pos=[700, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + config = Config(nile_network="goerli") + starting_weapon = dpg.get_value("starting_weapon") + starting_weapon_id = [ + k for k, v in ITEMS.items() if v == starting_weapon.replace(" ", "") + ][0] + + race = dpg.get_value("race") + race_id = [k for k, v in RACES.items() if v == race][0] + home_realm_id = dpg.get_value("home_realm") + name = dpg.get_value("name") + + order = dpg.get_value("order") + order_id = [k for k, v in ORDERS.items() if v == order][0] + command = [ + "nile", + "loot", + "new", + "--item", + str(starting_weapon_id), + "--race", + str(race_id), + "--home_realm", + home_realm_id, + "--name", + name, + "--order", + str(order_id), + "--image_hash_1", + "1", + "--image_hash_2", + "1", + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + out = asyncio.run( + wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="balance_of", + arguments=[config.USER_ADDRESS], + ) + ) + + out = out.split(" ") + + item = asyncio.run( + wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="token_of_owner_by_index", + arguments=[config.USER_ADDRESS, *uint(out[-1])], + ) + ) + + id = item.split(" ") + # asyncio.run(update_adventurer_list(id[-1])) + # update_gold(id[-1]) + # update_health(id[-1]) + dpg.delete_item("mint_adventurer_load") + dpg.delete_item("loader") + + +def explore(sender, app_data, user_data): + dpg.add_text("Exploring", tag="explore_load", pos=[700, 50], parent="adventurers") + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("adventurer_id").split(" - ")[-1] + command = [ + "nile", + "loot", + "explore", + "--adventurer_token_id", + adventurer, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + update_gold(adventurer) + update_health(adventurer) + adventurer_out = asyncio.run(_get_adventurer("goerli", adventurer)) + update_beast(adventurer_out[26]) + dpg.delete_item("explore_load") + dpg.delete_item("loader") + + +def attack_beast(sender, app_data, user_data): + dpg.add_text( + "Attacking Beast", tag="attack_load", pos=[700, 50], parent="adventurers" + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("adventurer_id").split(" - ")[-1] + command = [ + "nile", + "loot", + "attack", + "--adventurer_token_id", + adventurer, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + update_gold(adventurer) + update_health(adventurer) + dpg.delete_item("attack_load") + dpg.delete_item("loader") + + +def flee(sender, app_data, user_data): + dpg.add_text( + "Fleeing from beast", tag="flee_load", pos=[700, 50], parent="adventurers" + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("adventurer_id").split(" - ")[-1] + command = [ + "nile", + "loot", + "flee", + "--adventurer_token_id", + adventurer, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + adventurer_out = asyncio.run(_get_adventurer("goerli", adventurer)) + update_health(adventurer) + update_beast(adventurer_out[26]) + dpg.delete_item("flee_load") + dpg.delete_item("loader") + + +def equip_item(sender, app_data, user_data): + dpg.add_text( + "Equipping Item", tag="equip_load", pos=[700, 50], parent="adventurers" + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("equip_adventurer_id").split(" - ")[-1] + item = dpg.get_value("equip_loot_token_id") + command = [ + "nile", + "loot", + "health", + "--adventurer_token_id", + adventurer, + "--loot_token_id", + item, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + dpg.delete_item("equip_load") + dpg.delete_item("loader") + + +def unequip_item(sender, app_data, user_data): + dpg.add_text( + "Unequipping Item", tag="unequip_load", pos=[700, 50], parent="adventurers" + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("unequip_adventurer_id").split(" - ")[-1] + item = dpg.get_value("unequip_loot_token_id") + command = [ + "nile", + "loot", + "health", + "--adventurer_token_id", + adventurer, + "--loot_token_id", + item, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + dpg.delete_item("unequip_load") + dpg.delete_item("loader") + + +def purchase_health(sender, app_data, user_data): + dpg.add_text( + "Purchasing Health", + tag="purchase_health_load", + pos=[700, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("potions_adventurer_id").split(" - ")[-1] + number = dpg.get_value("potion_number") + command = [ + "nile", + "loot", + "health", + "--adventurer_token_id", + adventurer, + "--number", + str(number), + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + update_gold(adventurer) + update_health(adventurer) + dpg.delete_item("purchase_health_load") + dpg.delete_item("loader") + + +def mint_daily_items(sender, app_data, user_data): + dpg.add_text( + "Minting daily items", + tag="mint_items_load", + pos=[700, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + command = [ + "nile", + "loot", + "mint-daily-items", + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + dpg.delete_item("mint_items_load") + dpg.delete_item("loader") + + +async def get_market_items(): + config = Config(nile_network="goerli") + + current_index = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_mint_index", + arguments=[], + ) + + new_items = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_new_items", + arguments=[], + ) + + start = int(current_index) - int(new_items) + + print_items = [] + items = [] + + for i in range((int(current_index) + 1) - start): + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="view_unminted_item", + arguments=[*uint(i + start)], + ) + + out = out.split(" ") + out.insert(0, str(i + start)) + print(out) + + print_items.append(out) + items.append(f"{config.LOOT_ITEMS[int(out[1]) - 1]} - {out[-2]}") + print_loot_and_bid(print_items) + return items + + +def get_items(): + asyncio.run(get_market_items()) + + +def get_item_market(): + loot_token_id = dpg.get_value("item_id") + command = ["nile", "loot", "market", "--loot_token_id", loot_token_id] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + + +def bid_on_item(sender, app_data, user_data): + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + loot_token_id = dpg.get_value(tag="loot_token_id") + adventurer_id = dpg.get_value(tag="bid_adventurer_id").split(" - ")[-1] + price = dpg.get_value("bid_price") + command = [ + "nile", + "loot", + "bid", + "--loot_token_id", + loot_token_id, + "--adventurer_token_id", + adventurer_id, + "--price", + price, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + update_gold(adventurer_id) + dpg.delete_item("loader") + + +def upgrade_stat(sender, app_data, user_data): + dpg.add_text( + "Upgrading stat", + tag="upgrade_stat_load", + pos=[300, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value(tag="upgrade_adventurer_id").split(" - ")[-1] + stat = dpg.get_value(tag="stat_id") + stat_id = [k for k, v in STATS.items() if v == stat][0] + command = [ + "nile", + "loot", + "upgrade", + "--adventurer_token_id", + adventurer, + "--stat_id", + stat_id, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + dpg.delete_item("upgrade_stat_load") + dpg.delete_item("loader") + + +def get_king(): + command = [ + "nile", + "loot", + "get-king", + ] + out = subprocess.check_output(command).strip().decode("utf-8") + return out + + +def become_king(sender, app_data, user_data): + dpg.add_text( + "Becoming king", + tag="become_king_load", + pos=[300, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + adventurer = dpg.get_value("king_adventurer_id").split(" - ")[-1] + command = [ + "nile", + "loot", + "become-king", + "--adventurer_token_id", + adventurer, + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + update_king(adventurer) + dpg.delete_item("become_king_load") + dpg.delete_item("loader") + + +def pay_king_tribute(sender, app_data, user_data): + dpg.add_text( + "Paying the king", + tag="paying_king_load", + pos=[300, 50], + parent="adventurers", + ) + dpg.add_loading_indicator(tag="loader", parent="adventurers", pos=[850, 50]) + command = [ + "nile", + "loot", + "pay_king_tribute", + ] + out = subprocess.check_output(command).strip().decode("utf-8") + print(out) + dpg.delete_item("paying_king_load") + dpg.delete_item("loader") + + +def update_gold(adventurer_token_id): + command = ["nile", "loot", "balance", "--adventurer_token_id", adventurer_token_id] + out = subprocess.check_output(command).strip().decode("utf-8") + out = out.split(" ") + out = out[-1].split("\n") + print(f"💰 Gold balance is now {out[-1]}") + dpg.set_value("gold", out[-1]) + king_out = get_king() + king_out = king_out.split(" ") + king_out = king_out[-3].split("\n") + if int(king_out[-1]) == int(adventurer_token_id): + dpg.set_value("your_gold", "You are the king!") + dpg.configure_item("your_gold", color=[0, 128, 0]) + elif out[-1] > king_out[-1]: + dpg.set_value("your_gold", "You have enough gold to be king!") + dpg.configure_item("your_gold", color=[0, 128, 0]) + else: + dpg.set_value("your_gold", "You don't have enough gold to be king.") + dpg.configure_item("your_gold", color=[178, 34, 34]) + + +def update_king(): + command = [ + "nile", + "loot", + "get-king", + ] + out = subprocess.check_output(command).strip().decode("utf-8") + out = out.split(" ") + king_out = out[-3].split("\n") + gold_command = ["nile", "loot", "balance", "--adventurer_token_id", king_out[-1]] + gold_out = subprocess.check_output(gold_command).strip().decode("utf-8") + gold_out = gold_out.split(" ") + gold_out = gold_out[-1].split("\n") + reign_time = datetime.datetime.fromtimestamp(int(out[-1])) + print(f"👑 King is {king_out[-1]}") + print(f"⛳️ Reign started at {reign_time}") + print(f"💰 King's gold balance is now {gold_out[-1]}") + dpg.set_value("king_adventurer", king_out[-1]) + dpg.set_value("kings_reign", reign_time) + dpg.set_value("kings_gold", gold_out[-1]) + + +def update_beast(beast_token_id): + if beast_token_id != "0": + beast_out = asyncio.run(_get_beast(beast_token_id, "goerli")) + beast = BEASTS[str(int(beast_out[0]))] + dpg.set_value("beast", beast) + else: + dpg.set_value("beast", "-") + + +def update_health(adventurer_token_id): + adventurer_out = asyncio.run(_get_adventurer("goerli", adventurer_token_id)) + print(f"💚 Health is now {adventurer_out[7]}") + dpg.set_value("health", adventurer_out[7]) + + +def update_equipped_items(adventurer_data): + config = Config(nile_network="goerli") + + all_items = [] + + for i in adventurer_data[17:25]: + out = asyncio.run( + wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_item_by_token_id", + arguments=[*uint(i)], + ) + ) + out = out.split(" ") + out.insert(0, str(int(i))) + if int(out[1]) == 0: + all_items.append("Nothing") + else: + all_items.append(config.LOOT_ITEMS[int(out[1]) - 1]) + + dpg.set_value("weapon", all_items[0]) + dpg.set_value("chest", all_items[1]) + dpg.set_value("head", all_items[2]) + dpg.set_value("waist", all_items[3]) + dpg.set_value("feet", all_items[4]) + dpg.set_value("hands", all_items[5]) + dpg.set_value("neck", all_items[6]) + dpg.set_value("ring", all_items[7]) + + +if __name__ == "__main__": + dpg.create_context() + dpg.create_viewport(title="Realms GUI", width=1000, height=800) + dpg.setup_dearpygui() + print("Getting adventurers...") + adventurers = asyncio.run(get_adventurers()) + items = asyncio.run(get_market_items()) + + with dpg.window(tag="adventurers", label="Adventurers", width=1000, height=800): + print("Adventurers GUI running ...") + with dpg.group(horizontal=True): + with dpg.group(): + dpg.add_text("Create Adventurer") + dpg.add_combo( + label="Starting Weapon", + tag="starting_weapon", + items=(["Book", "Wand", "Club", "Short Sword"]), + width=100, + ) + dpg.add_combo( + label="Race", + tag="race", + items=( + [ + "Elf", + "Fox", + "Giant", + "Human", + "Orc", + "Demon", + "Goblin", + "Fish", + "Cat", + "Frog", + ] + ), + width=100, + ) + dpg.add_input_text( + label="Home Realm ID", + tag="home_realm", + decimal=True, + hint="1 - 8000", + width=100, + ) + dpg.add_input_text( + label="Name", + tag="name", + width=100, + ) + dpg.add_combo( + label="Order", + tag="order", + items=( + [ + "Power", + "Giants", + "Titans", + "Skill", + "Perfection", + "Brilliance", + "Enlightenment", + "Protection", + "Twins", + "Reflection", + "Detection", + "Fox", + "Vitriol", + "Fury", + "Rage", + "Anger", + ] + ), + width=100, + ) + dpg.add_button(label="Mint Adventurer", callback=new_adventurer) + # Equipped items display + dpg.add_spacer(width=20) + with dpg.group(): + dpg.add_text("Equipped Items") + with dpg.group(horizontal=True): + dpg.add_text("Weapon - ") + dpg.add_text(tag="weapon", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Chest - ") + dpg.add_text(tag="chest", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Head - ") + dpg.add_text(tag="head", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Waist - ") + dpg.add_text(tag="waist", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Feet - ") + dpg.add_text(tag="feet", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Hands - ") + dpg.add_text(tag="hands", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Neck - ") + dpg.add_text(tag="neck", default_value="Nothing") + with dpg.group(horizontal=True): + dpg.add_text("Ring - ") + dpg.add_text(tag="ring", default_value="Nothing") + dpg.add_spacer(height=4) + dpg.add_separator() + dpg.add_spacer(height=4) + with dpg.group(horizontal=True): + with dpg.group(): + dpg.add_text("Play") + dpg.add_combo( + label="Adventurer ID", + tag="adventurer_id", + items=adventurers, + width=100, + ) + with dpg.group(horizontal=True): + dpg.add_button(label="Explore", callback=explore) + dpg.add_button(label="Attack Beast", callback=attack_beast) + dpg.add_button(label="Flee from Beast", callback=flee) + dpg.add_button( + label="Get Adventurer", + callback=get_adventurer, + ) + with dpg.group(): + dpg.add_text("Health") + dpg.add_text(tag="health", default_value="-", color=[0, 128, 0]) + with dpg.group(): + dpg.add_text("Gold") + dpg.add_text(tag="gold", default_value="-", color=[255, 215, 0]) + with dpg.group(): + dpg.add_text("Beast") + dpg.add_text(tag="beast", default_value="-", color=[178, 34, 34]) + dpg.add_spacer(height=4) + dpg.add_separator() + dpg.add_spacer(height=4) + dpg.add_text("Items") + with dpg.group(horizontal=True): + dpg.add_button(label="Mint Daily Loot Items", callback=mint_daily_items) + dpg.add_button(label="Get Market Items", callback=get_items) + with dpg.group(): + dpg.add_text("By Token") + dpg.add_combo( + label="Item Id", + tag="item_id", + items=(items), + width=100, + ) + dpg.add_button(label="Get Item", callback=get_item_market) + dpg.add_spacer(height=4) + with dpg.group(horizontal=True): + with dpg.group(): + dpg.add_text("Bid On Item") + dpg.add_combo( + label="Adventurer ID", + tag="bid_adventurer_id", + items=adventurers, + width=100, + ) + dpg.add_combo( + label="Loot Token ID", + tag="bid_loot_id", + items=(items), + width=100, + ) + dpg.add_input_text( + label="Price", + tag="bid_price", + decimal=True, + hint="Min 3", + width=100, + ) + dpg.add_button(label="Bid", callback=bid_on_item) + with dpg.group(): + dpg.add_text("Equip Item") + dpg.add_combo( + label="Adventurer ID", + tag="equip_adventurer_id", + items=adventurers, + width=100, + ) + dpg.add_combo( + label="Loot Token ID", + tag="equip_loot_id", + items=(items), + width=100, + ) + dpg.add_button(label="Equip", callback=equip_item) + with dpg.group(): + dpg.add_text("Unequip Item") + dpg.add_combo( + label="Adventurer ID", + tag="unequip_adventurer_id", + items=adventurers, + width=100, + ) + dpg.add_combo( + label="Loot Token ID", + tag="unequip_loot_id", + items=(items), + width=100, + ) + dpg.add_button(label="Unequip", callback=unequip_item) + dpg.add_spacer(height=4) + dpg.add_separator() + dpg.add_spacer(height=4) + with dpg.group(horizontal=True): + with dpg.group(): + dpg.add_text("Upgrade Stat") + dpg.add_combo( + label="Adventurer ID", + tag="upgrade_adventurer_id", + items=adventurers, + width=100, + ) + dpg.add_combo( + label="Stat", + tag="stat", + items=[ + "Strength", + "Dexterity", + "Vitality", + "Intelligence", + "Wisdom", + "Charisma", + "Luck", + ], + width=100, + ) + dpg.add_button(label="Upgrade", callback=upgrade_stat) + with dpg.group(): + dpg.add_text("Purchase Health") + dpg.add_combo( + label="Adventurer ID", + tag="potions_adventurer_id", + items=adventurers, + width=100, + ) + dpg.add_slider_int( + label="Health Potions", + tag="potion_number", + min_value=1, + max_value=10, + width=100, + ) + dpg.add_button(label="Purchase Health", callback=purchase_health) + dpg.add_spacer(height=4) + dpg.add_separator() + dpg.add_spacer(height=4) + dpg.add_text("Kings") + dpg.add_spacer(height=4) + with dpg.group(horizontal=True): + with dpg.group(): + dpg.add_text("Become King") + dpg.add_combo( + label="Adventurer ID", + tag="king_adventurer_id", + items=adventurers, + width=100, + ) + dpg.add_button(label="Become King", callback=become_king) + with dpg.group(): + dpg.add_button(label="Pay King Tribue", callback=pay_king_tribute) + with dpg.group(): + dpg.add_text("King") + with dpg.group(horizontal=True): + with dpg.group(): + dpg.add_text("Adventurer") + dpg.add_text( + tag="king_adventurer", + default_value="-", + color=[205, 127, 50], + ) + with dpg.group(): + dpg.add_text("Reign Since") + dpg.add_text(tag="kings_reign", default_value="-") + with dpg.group(): + dpg.add_text("Gold") + dpg.add_text( + tag="kings_gold", default_value="-", color=[255, 215, 0] + ) + with dpg.group(): + dpg.add_text( + "You don't have enough gold to be king.", + tag="your_gold", + color=[178, 34, 34], + ) + update_king() + + dpg.show_viewport() + dpg.start_dearpygui() + dpg.destroy_context() diff --git a/realms_cli/realms_cli/loot/images/beasts/1.png b/realms_cli/realms_cli/loot/images/beasts/1.png new file mode 100644 index 00000000..67d8611e Binary files /dev/null and b/realms_cli/realms_cli/loot/images/beasts/1.png differ diff --git a/realms_cli/realms_cli/loot/images/beasts/12.png b/realms_cli/realms_cli/loot/images/beasts/12.png new file mode 100644 index 00000000..bdcec8bc Binary files /dev/null and b/realms_cli/realms_cli/loot/images/beasts/12.png differ diff --git a/realms_cli/realms_cli/loot/images/beasts/6.png b/realms_cli/realms_cli/loot/images/beasts/6.png new file mode 100644 index 00000000..1237537b Binary files /dev/null and b/realms_cli/realms_cli/loot/images/beasts/6.png differ diff --git a/realms_cli/realms_cli/loot/images/beasts/9.png b/realms_cli/realms_cli/loot/images/beasts/9.png new file mode 100644 index 00000000..7462fdfa Binary files /dev/null and b/realms_cli/realms_cli/loot/images/beasts/9.png differ diff --git a/realms_cli/realms_cli/loot/images/player.png b/realms_cli/realms_cli/loot/images/player.png new file mode 100644 index 00000000..6033bb57 Binary files /dev/null and b/realms_cli/realms_cli/loot/images/player.png differ diff --git a/realms_cli/realms_cli/loot/ipfs.py b/realms_cli/realms_cli/loot/ipfs.py new file mode 100644 index 00000000..e69de29b diff --git a/realms_cli/realms_cli/loot/loot.py b/realms_cli/realms_cli/loot/loot.py old mode 100644 new mode 100755 index 53fc062c..5911705e --- a/realms_cli/realms_cli/loot/loot.py +++ b/realms_cli/realms_cli/loot/loot.py @@ -1,35 +1,86 @@ -import anyio import asyncclick as click -from realms_cli.caller_invoker import wrapped_call, wrapped_send, wrapped_proxy_call +from realms_cli.caller_invoker import ( + wrapped_send, + wrapped_proxy_call, + parse_send, + get_transaction_result, +) from realms_cli.config import Config -from realms_cli.utils import print_over_colums, uint, felt_to_str +from realms_cli.utils import uint, str_to_felt +from realms_cli.loot.getters import ( + _get_loot, + print_loot, + print_loot_and_bid, + _get_adventurer, + _get_beast, + print_adventurer, + print_beast_img, + print_player, +) +from realms_cli.loot.constants import ( + BEASTS, + OBSTACLES, + DISCOVERY_TYPES, + ITEM_DISCOVERY_TYPES, +) +import time -@click.command() +@click.group() +def loot(): + pass + + +@loot.command() +@click.option( + "--loot_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="loot_token_id", + prompt=True, +) @click.option("--network", default="goerli") -async def mint_loot(network): +async def get(loot_token_id, network): """ - Mint a Random Loot Item + Get Loot Item metadata + """ + + await _get_loot(loot_token_id, network) + + +@loot.command() +@click.option("--network", default="goerli") +async def mint_daily_items(network): + """ + Set Loot Item metadata """ config = Config(nile_network=network) - print('🎲 Minting random item ...') + print("🗡 Setting item by id ...") await wrapped_send( network=config.nile_network, - signer_alias=config.ADMIN_ALIAS, - contract_alias="proxy_Loot", - function="mint", - arguments=[config.ADMIN_ADDRESS] + signer_alias=config.USER_ALIAS, + contract_alias="proxy_LootMarketArcade", + function="mint_daily_items", + arguments=[], ) - print('🎲 Minted random item ✅') + print("🗡 Daily items minted ✅") -@click.command() -@click.argument("loot_token_id", nargs=1) +@loot.command() +@click.option( + "--loot_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="loot_token_id", + prompt=True, +) @click.option("--network", default="goerli") -async def get_loot(loot_token_id, network): +async def market(loot_token_id, network): """ Get Loot Item metadata """ @@ -37,52 +88,849 @@ async def get_loot(loot_token_id, network): out = await wrapped_proxy_call( network=config.nile_network, - contract_alias="proxy_Loot", - abi='artifacts/abis/Loot.json', - function="getItemByTokenId", + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="view_unminted_item", arguments=[*uint(loot_token_id)], ) out = out.split(" ") - pretty_out = [] - for i, key in enumerate(config.LOOT): + out.insert(0, "0") + + print_loot_and_bid([out]) + + +@loot.command() +@click.option("--network", default="goerli") +async def all_market(network): + """ + Get Loot Item metadata + """ + config = Config(nile_network=network) + + current_index = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_mint_index", + arguments=[], + ) + + new_items = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_new_items", + arguments=[], + ) + + start = int(current_index) - int(new_items) + + items = [] + + for i in range((int(current_index) + 1) - start): + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="view_unminted_item", + arguments=[*uint(i + start)], + ) + + out = out.split(" ") + out.insert(0, str(i + start)) + print(out) + + items.append(out) + + # print(items) + print_loot_and_bid(items) + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--loot_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="loot_token_id", + prompt=True, +) +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id for the bid, you have to bid as an adventurer not a wallet", + prompt=True, +) +@click.option( + "--price", + is_flag=False, + metavar="", + type=click.STRING, + help="price for item, must be greater than past bid or above 10", + prompt=True, +) +async def bid(network, loot_token_id, adventurer, price): + """ + Bid on an item. You can only bid on an item that is currently for sale and has not expired in bid. + """ + config = Config(nile_network=network) + + print("🗡 Bidding on Item ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_LootMarketArcade", + function="bid_on_item", + arguments=[*uint(loot_token_id), *uint(adventurer), price], + ) + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--loot_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="loot_token_id", + prompt=True, +) +@click.option( + "--adventurer", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id for the bid, you have to bid as an adventurer not a wallet", + prompt=True, +) +async def claim(network, loot_token_id, adventurer): + """ + Claim item. You can only claim past the expiry time. + """ + config = Config(nile_network=network) + + print("🗡 Claiming item ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_LootMarketArcade", + function="claim_item", + arguments=[*uint(loot_token_id), *uint(adventurer)], + ) + + +@loot.command() +@click.option("--network", default="goerli") +async def bag(network): + """ + Get all your loot + """ + config = Config(nile_network=network) + + print("🗡 Claiming item ...") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="balanceOf", + arguments=[config.USER_ADDRESS], + ) + + out = out.split(" ") + + all_items = [] + + for i in range(0, int(out[0])): + item = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="tokenOfOwnerByIndex", + arguments=[config.USER_ADDRESS, *uint(i)], + ) + + id = item.split(" ") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_item_by_token_id", + arguments=[*uint(id[0])], + ) + out = out.split(" ") + out.insert(0, str(int(id[0]))) + all_items.append(out) + + print_loot(all_items) + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option( + "--number", + is_flag=False, + metavar="", + type=click.STRING, + help="number of health potions", + prompt=True, +) +async def health(network, adventurer_token_id, number): + """ + Purchase health for gold + """ + config = Config(nile_network=network) + + print("🧪 Purchasing health ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="purchase_health", + arguments=[*uint(adventurer_token_id), number], + ) + + adventurer_out = await _get_adventurer(network, adventurer_token_id) + + print(f"🧪 You bought {number} potions. Your health is now {adventurer_out[7]}") + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option( + "--stat_id", + is_flag=False, + metavar="", + type=click.STRING, + help="stat id", + prompt=True, +) +async def upgrade(network, adventurer_token_id, stat_id): + """ + Upgrade adventurer stat + """ + config = Config(nile_network=network) + + print("💪 Upgrading stat ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="upgrade_stat", + arguments=[*uint(adventurer_token_id), stat_id], + ) + + print("💪 Upgraded stat ✅") + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.pass_context +async def explore(ctx, network, adventurer_token_id): + """ + Explore with adventurer + """ + config = Config(nile_network=network) + + print("👣 Exploring ...") + + pre_adventurer = await _get_adventurer(network, adventurer_token_id) + + send_out = await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="explore", + arguments=[*uint(adventurer_token_id)], + ) + + _, tx_hash = parse_send(send_out) + + result = get_transaction_result(network, tx_hash) + + print("👣 Explored ✅") + + adventurer_out = await _get_adventurer(network, adventurer_token_id) + + if int(result[0], 16) == 0: + print("🤔 You discovered nothing!") + if int(result[0], 16) == 1: + print("🧌 You have discovered a beast") + print_beast_img(adventurer_out[26]) + await _get_beast(adventurer_out[26], network) + if int(result[0], 16) == 2: + print( + f"🪤 You were hit by {OBSTACLES[int(result[1],16)]} and took {str(int(pre_adventurer[7]) - int(adventurer_out[7]))} damage!" + ) + if int(result[0], 16) == 3: + print(f"🎉 You discovered {ITEM_DISCOVERY_TYPES[int(result[1],16)]}") + + +@loot.command() +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option("--network", default="goerli") +async def adventurer(adventurer_token_id, network): + """ + Get Adventurer metadata + """ + + print_player() + _adventurer = await _get_adventurer(network, adventurer_token_id) + + split = _adventurer[17:25] + + all_items = [] + + for i in _adventurer[17:25]: + out = await wrapped_proxy_call( + network=network, + contract_alias="proxy_LootMarketArcade", + abi="artifacts/abis/LootMarketArcade.json", + function="get_item_by_token_id", + arguments=[*uint(i)], + ) + out = out.split(" ") + out.insert(0, str(int(i))) + all_items.append(out) + + print_loot(all_items) + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option( + "--loot_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="item id", + prompt=True, +) +async def equip(network, adventurer_token_id, loot_token_id): + """ + Equip loot item + """ + config = Config(nile_network=network) + + print("🫴 Equiping item ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="equip_item", + arguments=[*uint(adventurer_token_id), *uint(loot_token_id)], + ) + + print("🫴 Equiped item ✅") + await _get_adventurer(network, adventurer_token_id) + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option( + "--loot_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="item id", + prompt=True, +) +async def unequip(network, adventurer_token_id, loot_token_id): + """ + Unequip loot item + """ + config = Config(nile_network=network) + + print("🫳 Unequiping item ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="unequip_item", + arguments=[*uint(adventurer_token_id), *uint(loot_token_id)], + ) + + print("🫳 Unequiped item ...") + await _get_adventurer(network, adventurer_token_id) + + +@loot.command() +@click.option("--network", default="goerli") +async def all_adventurers(network): + """ + Get all your Adventurers you own. + """ + config = Config(nile_network=network) + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="balance_of", + arguments=[config.USER_ADDRESS], + ) + + out = out.split(" ") + + all_items = [] + + for i in range(0, int(out[0])): + item = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="token_of_owner_by_index", + arguments=[config.USER_ADDRESS, *uint(i)], + ) + + id = item.split(" ") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="get_adventurer_by_id", + arguments=[*uint(id[0])], + ) + + all_items.append(out) + + print_adventurer(all_items) + + +@loot.command() +@click.option( + "--beast_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="beast id", + prompt=True, +) +@click.option("--network", default="goerli") +async def beast(beast_token_id, network): + """ + Get Beast metadata + """ + await _get_beast(beast_token_id, network) - # Output names for item name prefix1, prefix2, and suffix - if i in [13]: - pretty_out.append( - f"{key} : {felt_to_str(int(out[i]))}") + +@loot.command() +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="Adventuer Id", + prompt=True, +) +@click.option("--network", default="goerli") +async def attack(adventurer_token_id, network): + """ + Attack beast + """ + config = Config(nile_network=network) + + print("🧌 Attacking beast ...") + + pre_adventurer = await _get_adventurer(network, adventurer_token_id) + + pre_beast = await _get_beast(pre_adventurer[26], network) + + if pre_adventurer[26] != "0": + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Beast", + function="attack", + arguments=[*uint(pre_adventurer[26])], + ) + + print("🧌 Attacked beast ✅") + + beast_out = await _get_beast(pre_adventurer[26], network) + + adventurer_out = await _get_adventurer(network, beast_out[7]) + + if beast_out[6] == "0": + print( + f"💀 You dealt {str(int(pre_beast[6]) - int(beast_out[6]))} damage and have killed the {BEASTS[str(int(beast_out[0]))]} 🎉" + ) else: - pretty_out.append( - f"{key} : {int(out[i])}") + if int(pre_beast[6]) - int(beast_out[6]) == 0: + print( + f"😖 The {BEASTS[str(int(beast_out[0]))]}'s armor is too strong, you do no damage." + ) + else: + print( + f"👹 You did {str(int(pre_beast[6]) - int(beast_out[6]))} damage to the {BEASTS[str(int(beast_out[0]))]}, its health is now {beast_out[6]}" + ) + if adventurer_out[4] == "0": + print( + f"🪦 You took {str(int(pre_adventurer[7]) - int(adventurer_out[7]))} damage and have been killed" + ) + else: + print( + f"🤕 You didn't kill and were counterattacked losing {str(int(pre_adventurer[7]) - int(adventurer_out[7]))} health, you have {adventurer_out[7]} health remaining" + ) - print("_________ LOOT ITEM - " + str(out[0]) + "___________") - print_over_colums(pretty_out) + else: + print("You are not in a battle...") -@click.command() -@click.argument("loot_token_id", nargs=1) +@loot.command() +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) @click.option("--network", default="goerli") -@click.option('--item', is_flag=False, - metavar='', type=click.STRING, help='item id', prompt=True) -@click.option('--greatness', is_flag=False, - metavar='', type=click.STRING, help='greatness', prompt=True) -@click.option('--xp', is_flag=False, - metavar='', type=click.STRING, help='xp', prompt=True) -@click.option('--adventurer', is_flag=False, - metavar='', type=click.STRING, help='adventurer', prompt=True) -@click.option('--bag', is_flag=False, - metavar='', type=click.STRING, help='bag', prompt=True) -async def set_loot(loot_token_id, item, greatness, xp, adventurer, bag, network): +async def flee(adventurer_token_id, network): """ - Set Loot Item metadata + Flee from beast + """ + config = Config(nile_network=network) + + print("🏃‍♂️ Fleeing from beast ...") + + pre_adventurer = await _get_adventurer(network, adventurer_token_id) + + send_out = await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Beast", + function="flee", + arguments=[*uint(pre_adventurer[26])], + ) + + _, tx_hash = parse_send(send_out) + + result = get_transaction_result(network, tx_hash) + + beast_out = await _get_beast(pre_adventurer[26], network) + + adventurer_out = await _get_adventurer(network, adventurer_token_id) + + if int(result[0], 16) == 1: + print(f"🏃‍♂️ You successfully fled from the {BEASTS[str(int(beast_out[0]))]} ✅") + else: + if int(pre_adventurer[7]) > int(adventurer_out[7]): + print( + f"😫 You have been ambushed by the {BEASTS[str(int(beast_out[0]))]} and took {str(int(pre_adventurer[7]) - int(adventurer_out[7]))} damage!" + ) + else: + print(f"😮 You did not flee from the {BEASTS[str(int(beast_out[0]))]}!") + + +@loot.command() +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer id", + prompt=True, +) +@click.option("--network", default="goerli") +async def balance(network, adventurer_token_id): + """ + Get the balance of gold your Adventurer owns. + """ + config = Config(nile_network=network) + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Beast", + abi="artifacts/abis/Beast.json", + function="balance_of", + arguments=[*uint(adventurer_token_id)], + ) + + print(out) + + +@loot.command() +@click.option("--network", default="goerli") +@click.option( + "--item", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer item to start", + prompt=True, +) +@click.option( + "--race", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer race", + prompt=True, +) +@click.option( + "--home_realm", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer home realm", + prompt=True, +) +@click.option( + "--name", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer name", + prompt=True, +) +@click.option( + "--order", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer order", + prompt=True, +) +@click.option( + "--image_hash_1", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer image hash part 1", + prompt=True, +) +@click.option( + "--image_hash_2", + is_flag=False, + metavar="", + type=click.STRING, + help="adventurer image hash part 2", + prompt=True, +) +async def new(network, item, race, home_realm, name, order, image_hash_1, image_hash_2): + """ + Mint a Random Loot Item """ config = Config(nile_network=network) - print('🗡 Setting item by id ...') + print("🪙 Minting lords ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias=config.Lords_ERC20_Mintable_alias, + function="mint", + arguments=[config.USER_ADDRESS, 100 * 10**18, 0], # uint 1 # uint 2 + ) + + print("🪙 Harvesting lords ✅") + + print("👍 Approving lords to be spent ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias=config.Lords_ERC20_Mintable_alias, + function="approve", + arguments=[ + config.ADVENTURER_PROXY_ADDRESS, + 100 * 10**18, # uint 1 + 0, # uint 2 + ], + ) + + print("👍 Approved lords to be spent ✅") + + print("🤴 Minting adventurer ...") await wrapped_send( network=config.nile_network, signer_alias=config.USER_ALIAS, - contract_alias="proxy_Loot", - function="setItemById", - arguments=[*uint(loot_token_id), item, greatness, xp, adventurer, bag] + contract_alias="proxy_Adventurer", + function="mint_with_starting_weapon", + arguments=[ + config.USER_ADDRESS, + race, + home_realm, + str_to_felt(name), + order, + image_hash_1, + image_hash_2, + item, + ], + ) + + print_player() + print("In the void between worlds, a mighty warrior was born.") + time.sleep(2) + print( + "His name was " + + name + + ", and he was forged from the very fabric of the ether." + ) + time.sleep(2) + print( + "He emerged into the world with a sense of purpose and power, his very presence filling the air with electricity." ) + time.sleep(2) + print( + "" + + name + + " knew that he had been born for a reason, and he was eager to discover what that reason was." + ) + time.sleep(2) + print( + "He set out into the unknown, his eyes fixed on the horizon, his heart filled with determination." + ) + time.sleep(2) + print( + "As he journeyed through the strange and wondrous land, he encountered many challenges." + ) + time.sleep(2) + print( + "But " + + name + + " was not deterred. He was a creature of the void, born to overcome any obstacle that stood in his way." + ) + time.sleep(2) + print( + "And so he pushed on, through fire and ice, through darkness and light, until he reached his ultimate destination." + ) + time.sleep(2) + print( + "There, in the heart of the world, he found his true purpose, his reason for being." + ) + time.sleep(2) + print( + "And with a final surge of power, he fulfilled his destiny, becoming a legend that would be spoken of for generations to come." + ) + + +@loot.command() +@click.option("--network", default="goerli") +async def get_king(network): + """ + Get information on the king. + """ + config = Config(nile_network=network) + + print("♔ Getting king info ...") + + out = await wrapped_proxy_call( + network=config.nile_network, + contract_alias="proxy_Adventurer", + abi="artifacts/abis/Adventurer.json", + function="get_king", + arguments=[], + ) + print(out) + + +@loot.command() +@click.option( + "--adventurer_token_id", + is_flag=False, + metavar="", + type=click.STRING, + help="Adventuer Id", + prompt=True, +) +@click.option("--network", default="goerli") +async def become_king(network, adventurer_token_id): + """ + Become adventurer king. + """ + config = Config(nile_network=network) + + print("👑 Applying for king ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="become_king", + arguments=[*uint(adventurer_token_id)], + ) + + print("👑 Became King ✅") + + +@loot.command() +@click.option("--network", default="goerli") +async def pay_king_tribute(network, adventurer_token_id): + """ + Pay the king his tribute. + """ + config = Config(nile_network=network) + + print("🪙 Paying king their tribute ...") + + await wrapped_send( + network=config.nile_network, + signer_alias=config.USER_ALIAS, + contract_alias="proxy_Adventurer", + function="pay_king_tribute", + arguments=[], + ) + + print("🪙 King tribute paid ✅") diff --git a/realms_cli/realms_cli/nexus/admin.py b/realms_cli/realms_cli/nexus/admin.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/__init__.py b/realms_cli/realms_cli/player/__init__.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/account.py b/realms_cli/realms_cli/player/account.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/buildings.py b/realms_cli/realms_cli/player/buildings.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/calculator.py b/realms_cli/realms_cli/player/calculator.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/combat.py b/realms_cli/realms_cli/player/combat.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/crypts.py b/realms_cli/realms_cli/player/crypts.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/food.py b/realms_cli/realms_cli/player/food.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/guilds.py b/realms_cli/realms_cli/player/guilds.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/lords.py b/realms_cli/realms_cli/player/lords.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/resources.py b/realms_cli/realms_cli/player/resources.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/settle.py b/realms_cli/realms_cli/player/settle.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/player/travel.py b/realms_cli/realms_cli/player/travel.py old mode 100644 new mode 100755 diff --git a/realms_cli/realms_cli/utils.py b/realms_cli/realms_cli/utils.py old mode 100644 new mode 100755 index 8b2706d8..c455bc1f --- a/realms_cli/realms_cli/utils.py +++ b/realms_cli/realms_cli/utils.py @@ -2,11 +2,12 @@ from typing import List from nile.common import get_class_hash, ABIS_DIRECTORY from nile import deployments +import datetime def print_over_colums(array_of_strings, cols=2, width=40): """Takes in an array of strings and prints the content over a - number of colums.""" + number of colums.""" ans = "" for i, text in enumerate(array_of_strings): if i % cols == 0: @@ -31,7 +32,7 @@ def parse_multi_input(cli_input) -> List: """ if "-" in cli_input: low, high = cli_input.split("-") - return list(range(int(low), int(high)+1)) + return list(range(int(low), int(high) + 1)) if "," in cli_input: words = cli_input.split(",") return [int(word) for word in words] @@ -53,7 +54,7 @@ def pack_values(values: list) -> int: def uint_decimal(a): - x = int(a) * 10 ** 18 + x = int(a) * 10**18 return (x, 0) @@ -134,3 +135,19 @@ def delete_existing_declaration(contract_name: str): def get_contract_abi(contract_name): return f"{ABIS_DIRECTORY}/{contract_name}.json" + + +def convert_unix_time(unix_time): + # Convert datetime object to a localized datetime object + + # Get the current time in UTC + current_time = datetime.datetime.utcnow().timestamp() + + # Compare the unix_time with the current time to see if it's in the past + if unix_time > current_time: + time_diff = int(unix_time - current_time) + hours, remainder = divmod(time_diff, 3600) + minutes, seconds = divmod(remainder, 60) + return f"open ({minutes}m, {seconds}s left)" + else: + return "closed" diff --git a/requirements.txt b/requirements.txt old mode 100644 new mode 100755 diff --git a/scripts/generate_strings.py b/scripts/generate_strings.py old mode 100644 new mode 100755 diff --git a/scripts/get_public_key_from_private_key.py b/scripts/get_public_key_from_private_key.py old mode 100644 new mode 100755 index 79a7785a..f9627cd4 --- a/scripts/get_public_key_from_private_key.py +++ b/scripts/get_public_key_from_private_key.py @@ -1,12 +1,30 @@ import os +import sys +import json from nile.signer import Signer -# put your private key in the system environment variables -private_key = int(os.environ["STARKNET_ADMIN_PRIVATE_KEY"]) +# Get the private key from the command line argument +if len(sys.argv) < 2: + print("Error: Please provide the private key as an argument") + sys.exit(1) + +private_key = int(sys.argv[1]) +address = sys.argv[2] signer = Signer(private_key) if __name__ == "__main__": - print(f"private: {private_key}") - print(f"public: {hex(signer.public_key)}") - print("--> put the public key as a dict key in NETWORK.accounts.json") + public_key = hex(signer.public_key) + + + # Create a dictionary with the public key and address + account_info = { + public_key: { + "address": address, + "index": 0, + "alias": "STARKNET_PRIVATE_KEY" + } + } + + # Convert the dictionary to JSON and print it to the console + print(json.dumps(account_info)) \ No newline at end of file diff --git a/scripts/readme.md b/scripts/readme.md old mode 100644 new mode 100755 diff --git a/scripts/run_binary_converter.py b/scripts/run_binary_converter.py old mode 100644 new mode 100755 diff --git a/scripts/set_all_realm_data.sh b/scripts/set_all_realm_data.sh old mode 100644 new mode 100755 diff --git a/scripts/setup_cli_env.sh b/scripts/setup_cli_env.sh old mode 100644 new mode 100755 index c2627296..9f244ba3 --- a/scripts/setup_cli_env.sh +++ b/scripts/setup_cli_env.sh @@ -146,41 +146,6 @@ run_setup () { cp $GOERLI_DEPLOYMENTS_FILE $GOERLI_DEPLOYMENTS_FILE.backup fi -cat < $GOERLI_DEPLOYMENTS_FILE -0x003ca62a639a4e3821eb02f6ac0101f0877b925ef718b5e1a6f5d51b59b5d3d0:artifacts/abis/Arbiter.json:Arbiter -0x0221d3881e8f136838bc6cbd9d425e800ea584fb019cd566ac05a4c5fb7befa1:artifacts/abis/Arbiter.json:proxy_Arbiter -0x0648e8fd66cde815636c62e2e97d761c4f56a6c041c22568e8fab8466021fc57:artifacts/abis/ModuleController.json:ModuleController -0x032d7b20d1e0455cf9cd40784d8a5fe1e02acb6f7278179c6c2011bb98bed154:artifacts/abis/ModuleController.json:proxy_ModuleController -0x014b32c7def1977cf85d9ac4e90c040249dfe61a71e090890f69a4d7a01dba89:artifacts/abis/xoroshiro128_starstar.json:xoroshiro128_starstar -0x007a29730cfaed96839660577c3b3019038862187b0865280b79e944c66ac215:artifacts/abis/Settling.json:proxy_Settling -0x058d3a1a5fe490cdbfbb14c7a648142b3b7debb65747450b76f604c3c39f4cfe:artifacts/abis/Resources.json:proxy_Resources -0x01c7a86cea8febe69d688dd5ffa361e7924f851db730f4256ed67fd805ea8aa7:artifacts/abis/Buildings.json:proxy_Buildings -0x04354c123f60faf3507aa9c9abf0e7fddfcac40a322df88e06d18de6dad61988:artifacts/abis/Calculator.json:Calculator -0x04f65c9451f333e0fbe33f912f470da360cf959ea0cefb85f0abef54fd3bb76c:artifacts/abis/Calculator.json:proxy_Calculator -0x039f40b33de4d22b2c140fccbcf2092ccc24ebdb7ed985716b93f763ae5607e8:artifacts/abis/Combat.json:proxy_Combat -0x0415bda0925437cee1cd70c5782c65a5b1f5c72945c5204dbba71c6d69c8575a:artifacts/abis/Travel.json:proxy_Travel -0x02d73a83afeaf5927c2dfb51b2412ea9dfe1fb6cd41b1b702607e7345ce47d09:artifacts/abis/Food.json:proxy_Food -0x06052bf4631585f7074a118543121561d12cc910e0ab95b48039eab587e078d2:artifacts/abis/Relics.json:proxy_Relics -0x04de5e1a2aaf2f577618f17f9c1ff4b73ab26e1b85df4742ab314e1e5337874b:artifacts/abis/Lords_ERC20_Mintable.json:Lords_ERC20_Mintable -0x0371e76cc9dc2cf151201e3fff62dc816636fe918e4c90604e9ed1369b7d1d5e:artifacts/abis/Lords_ERC20_Mintable.json:proxy_Lords_ERC20_Mintable -0x02ab849a3eaf4fd54f80e6dbe7a8d182646ec41684d1f1a4f718623bd8cb0695:artifacts/abis/Realms_ERC721_Mintable.json:proxy_Realms_ERC721_Mintable -0x016a1b978c62be5c30faa565f2086336126db3f120fbe61f368d8e07f289ef03:artifacts/abis/S_Realms_ERC721_Mintable.json:proxy_S_Realms_ERC721_Mintable -0x07080e87497f82ac814c6eaf91d66ac93672927a8c019014f05eb6d688ebd0fc:artifacts/abis/Resources_ERC1155_Mintable_Burnable.json:proxy_Resources_ERC1155_Mintable_Burnable -0x0441181da8e4d3ca2add537dff9d80b4ac1300cc67b0ceffd75147c4f1915048:artifacts/abis/Settling.json:Settling -0x06454ecb367df2d47f557dc5ff130ecde1b66dd98119881ae327b4b3c8ff9944:artifacts/abis/Buildings.json:Buildings -0x0285a8061f3114997f5e479b6985fa4e51a71d68cc910d4eb0f1fe5422dfdd0e:artifacts/abis/Relics.json:Relics -0x079155beb3187926dc87cf3c42bb4729f73cbf56c5e19e32bec702650bf0c3ef:artifacts/abis/Exchange_ERC20_1155.json:Exchange_ERC20_1155 -0x042bf805eb946855cc55b1321a86cd4ece9904b2d15f50c47439af3166c7c5e2:artifacts/abis/PROXY_Logic.json:proxy_Exchange_ERC20_1155 -0x001bdf6e7049994c2f4bfb20111bd1e7957c9453f1d8d57b6cfe79e22ce647fd:artifacts/abis/Resources_ERC1155_Mintable_Burnable.json:Resources_ERC1155_Mintable_Burnable -0x0451cbe505243521da1fd9276b4cade0d3e1300ee4ee1a909d52e7b2fa3ee8e1:artifacts/abis/Realms_ERC721_Mintable.json:Realms_ERC721_Mintable -0x076a008edb23e45dc3e5e2cedaa2a6d6cfc848f0a435483aa8501e10f438667e:artifacts/abis/S_Realms_ERC721_Mintable.json:S_Realms_ERC721_Mintable -0x0442d96807d4bb464ecde88496f22e88dfa17ec227bc053cbf81f475507c1d15:artifacts/abis/Resources.json:Resources -0x04097d3c8c6cf53c874a8acbf0eb11c1caa6d48f895347c94229275f98028d5a:artifacts/abis/Food.json:Food -0x0191c8d38bbae6722ef6cd85a050b754a892df1aa0d90d5973df25ab3c99f01b:artifacts/abis/Travel.json:Travel -0x0545af632491bef458c5d389c787ab59b265d4c9f5c0323260a5d0e596572075:artifacts/abis/Combat.json:Combat -$STARKNET_ACCOUNT_ADDRESS:/usr/local/lib/python3.9/site-packages/nile/artifacts/abis/Account.json:account-0 -EOT - GOERLI_ACCOUNTS_JSON_FILE=goerli.accounts.json # if the system already has a goerli accoounts file if [ -f "$GOERLI_ACCOUNTS_JSON_FILE" ]; then diff --git a/scripts/startup.sh b/scripts/startup.sh new file mode 100755 index 00000000..bb93c038 --- /dev/null +++ b/scripts/startup.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +file_does_not_exist() { + if [ -f "$1" ]; then + return 1 + else + return 0 + fi +} + +if file_does_not_exist "goerli.accounts.json"; then + # Prompt the user for the private key + read -p "Enter your private key (You get this from Argent): " private_key + + # Prompt the user for the address + read -p "Enter the address (You get this from Argent): " address + + # Call the Python script and pass the private key and address as arguments + json=$(python3 scripts/get_public_key_from_private_key.py "$private_key" "$address") + + echo "$json" > "goerli.accounts.json" + + # Write the JSON output to a file + echo "export STARKNET_PRIVATE_KEY=${private_key}" > "realms_cli/.env.nile" + + echo "${address}:/usr/local/lib/python3.9/site-packages/nile/artifacts/abis/Account.json:STARKNET_PRIVATE_KEY" > goerli.deployments.txt + echo "0x047bccb3bb7707224431efdb5b24d0f5051569a858b4bef3ec5f145f5bddd741:artifacts/abis/Arbiter.json:Arbiter_Loot" >> goerli.deployments.txt + echo "0x04bf33f5750cf91b274e454aee797bd6cc9a45f51cb2b83c206ab85a66182fdc:artifacts/abis/PROXY_Logic.json:proxy_Arbiter_Loot" >> goerli.deployments.txt + echo "0x0584c995814e70bae0cf23972d72458d7ac748c2c890e1860e2b9ec44f76f6a4:artifacts/abis/ModuleController.json:ModuleController_Loot" >> goerli.deployments.txt + echo "0x066213a37197a8ffee97c66696ed7eb9ec89fe80ef984e02df456224b2fbf436:artifacts/abis/PROXY_Logic.json:proxy_ModuleController_Loot" >> goerli.deployments.txt + echo "0x03ff460370753891a18e13662d22f1849859a552291cea3d72efd3807065ae53:artifacts/abis/PROXY_Logic.json:proxy_Adventurer" >> goerli.deployments.txt + echo "0x05b1e584fc5da3bbee9d260761521604142e9b5b1cda2fa533b4fdfbc038cfb6:artifacts/abis/PROXY_Logic.json:proxy_LootMarketArcade" >> goerli.deployments.txt + echo "0x07f50583c7e4f9b56eff393f5b5136fc45c21b48eef3408aaca7983d654de109:artifacts/abis/PROXY_Logic.json:proxy_Beast" >> goerli.deployments.txt + echo "0x0371e76cc9dc2cf151201e3fff62dc816636fe918e4c90604e9ed1369b7d1d5e:artifacts/abis/Lords_ERC20_Mintable.json:proxy_Lords_ERC20_Mintable" >> goerli.deployments.txt + + # Print success message to console + echo "File 'goerli.deployments.txt' created successfully." + + nile compile contracts/loot + nile compile contracts/settling_game/tokens/Lords_ERC20_Mintable.cairo + + source realms_cli/.env.nile +else + source realms_cli/.env.nile +fi + + diff --git a/static/Resource_Emporium.png b/static/Resource_Emporium.png old mode 100644 new mode 100755 diff --git a/static/realmslogo.jpg b/static/realmslogo.jpg old mode 100644 new mode 100755 diff --git a/static/realmsxbibliotheca.jpg b/static/realmsxbibliotheca.jpg old mode 100644 new mode 100755 diff --git a/tasks/deploy_account.ts b/tasks/deploy_account.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/README.md b/tasks/desiege/README.md old mode 100644 new mode 100755 diff --git a/tasks/desiege/create_game.ts b/tasks/desiege/create_game.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_arbiter.ts b/tasks/desiege/deploy_arbiter.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_divine_eclipse_storage.ts b/tasks/desiege/deploy_divine_eclipse_storage.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_element_balancer.ts b/tasks/desiege/deploy_element_balancer.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_elements_token.ts b/tasks/desiege/deploy_elements_token.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_module_controller.ts b/tasks/desiege/deploy_module_controller.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_tower_defense.ts b/tasks/desiege/deploy_tower_defense.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/deploy_tower_defense_storage.ts b/tasks/desiege/deploy_tower_defense_storage.ts old mode 100644 new mode 100755 diff --git a/tasks/desiege/setup_controller_modules.ts b/tasks/desiege/setup_controller_modules.ts old mode 100644 new mode 100755 diff --git a/tasks/helpers/index.ts b/tasks/helpers/index.ts old mode 100644 new mode 100755 diff --git a/tasks/migrations/upgrade_01_20220215.ts b/tasks/migrations/upgrade_01_20220215.ts old mode 100644 new mode 100755 diff --git a/tasks/migrations/upgrade_01_20220227.ts b/tasks/migrations/upgrade_01_20220227.ts old mode 100644 new mode 100755 diff --git a/tasks/migrations/upgrade_01_20220301.ts b/tasks/migrations/upgrade_01_20220301.ts old mode 100644 new mode 100755 diff --git a/tasks/migrations/upgrade_02_20220223.ts b/tasks/migrations/upgrade_02_20220223.ts old mode 100644 new mode 100755 diff --git a/test.json b/test.json new file mode 100644 index 00000000..59633925 --- /dev/null +++ b/test.json @@ -0,0 +1,363 @@ +{ + "fee_transfer_invocation": { + "call_type": "CALL", + "calldata": [ + "0x46a89ae102987331d369645031b49c27738ed096f2789c24449966da4c6de6b", + "0x176a27f039108", + "0x0" + ], + "caller_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", + "contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 21 + }, + "n_memory_holes": 40, + "n_steps": 590 + }, + "internal_calls": [ + { + "call_type": "DELEGATE", + "calldata": [ + "0x46a89ae102987331d369645031b49c27738ed096f2789c24449966da4c6de6b", + "0x176a27f039108", + "0x0" + ], + "caller_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", + "contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entry_point_type": "EXTERNAL", + "events": [ + { + "data": [ + "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "0x46a89ae102987331d369645031b49c27738ed096f2789c24449966da4c6de6b", + "0x176a27f039108", + "0x0" + ], + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "order": 0 + } + ], + "execution_resources": { + "builtin_instance_counter": { + "pedersen_builtin": 4, + "range_check_builtin": 21 + }, + "n_memory_holes": 40, + "n_steps": 530 + }, + "internal_calls": [], + "messages": [], + "result": ["0x1"], + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e" + } + ], + "messages": [], + "result": ["0x1"], + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e" + }, + "function_invocation": { + "call_type": "CALL", + "calldata": [ + "0x1", + "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "0x1f64d317ff277789ba74de95db50418ab0fa47c09241400b7379b50d6334c3a", + "0x0", + "0x2", + "0x2", + "0x3", + "0x0" + ], + "caller_address": "0x0", + "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", + "contract_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "bitwise_builtin": 51, + "pedersen_builtin": 11, + "range_check_builtin": 218 + }, + "n_memory_holes": 195, + "n_steps": 6760 + }, + "internal_calls": [ + { + "call_type": "DELEGATE", + "calldata": [ + "0x1", + "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "0x1f64d317ff277789ba74de95db50418ab0fa47c09241400b7379b50d6334c3a", + "0x0", + "0x2", + "0x2", + "0x3", + "0x0" + ], + "caller_address": "0x0", + "class_hash": "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2", + "contract_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "entry_point_type": "EXTERNAL", + "events": [ + { + "data": [ + "0x1f785571202c892b05274540b6df27fe7199f0f078181844ac08f39cd53bd2d", + "0x2", + "0x0", + "0x0" + ], + "keys": [ + "0x5ad857f66a5b55f1301ff1ed7e098ac6d4433148f0b72ebc4a2945ab85ad53" + ], + "order": 0 + } + ], + "execution_resources": { + "builtin_instance_counter": { + "bitwise_builtin": 51, + "pedersen_builtin": 11, + "range_check_builtin": 218 + }, + "n_memory_holes": 195, + "n_steps": 6700 + }, + "internal_calls": [ + { + "call_type": "CALL", + "calldata": ["0x3", "0x0"], + "caller_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "class_hash": "0x3e553b1af6553778daeb60f1023a9a229630d33d447b084e72199486d62af9b", + "contract_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "bitwise_builtin": 51, + "pedersen_builtin": 11, + "range_check_builtin": 215 + }, + "n_memory_holes": 192, + "n_steps": 6471 + }, + "internal_calls": [ + { + "call_type": "DELEGATE", + "calldata": ["0x3", "0x0"], + "caller_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "class_hash": "0x5092f2fe8c543d79ad5dae316fb669c2d43624e567c496da4c48f289b3ef1b5", + "contract_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "bitwise_builtin": 51, + "pedersen_builtin": 11, + "range_check_builtin": 215 + }, + "n_memory_holes": 192, + "n_steps": 6411 + }, + "internal_calls": [ + { + "call_type": "CALL", + "calldata": ["0x3"], + "caller_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "class_hash": "0x3e553b1af6553778daeb60f1023a9a229630d33d447b084e72199486d62af9b", + "contract_address": "0x3ddb0ca77fc93ca2205ee448077ca72e03b68483978d39bd9b47cbbdcfdc0ae", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "pedersen_builtin": 1, + "range_check_builtin": 3 + }, + "n_memory_holes": 10, + "n_steps": 144 + }, + "internal_calls": [ + { + "call_type": "DELEGATE", + "calldata": ["0x3"], + "caller_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "class_hash": "0x48ba0fa6f47c3bfcc64b136169e6e3444c14d2e2168b6c733e42599b57ba873", + "contract_address": "0x3ddb0ca77fc93ca2205ee448077ca72e03b68483978d39bd9b47cbbdcfdc0ae", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "pedersen_builtin": 1, + "range_check_builtin": 3 + }, + "n_memory_holes": 10, + "n_steps": 84 + }, + "internal_calls": [], + "messages": [], + "result": [ + "0x6088adbd933cb06e376affe781ed0d3b9629e77ac1d364c70fc40e9fc9a1703" + ], + "selector": "0x15b18825b249dcabe4c3a17cd7e8636175c8c38cf18091e68f42f2b421aeb6" + } + ], + "messages": [], + "result": [ + "0x6088adbd933cb06e376affe781ed0d3b9629e77ac1d364c70fc40e9fc9a1703" + ], + "selector": "0x15b18825b249dcabe4c3a17cd7e8636175c8c38cf18091e68f42f2b421aeb6" + }, + { + "call_type": "CALL", + "calldata": [], + "caller_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "class_hash": "0x3e553b1af6553778daeb60f1023a9a229630d33d447b084e72199486d62af9b", + "contract_address": "0x3ddb0ca77fc93ca2205ee448077ca72e03b68483978d39bd9b47cbbdcfdc0ae", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 106 + }, + "internal_calls": [ + { + "call_type": "DELEGATE", + "calldata": [], + "caller_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "class_hash": "0x48ba0fa6f47c3bfcc64b136169e6e3444c14d2e2168b6c733e42599b57ba873", + "contract_address": "0x3ddb0ca77fc93ca2205ee448077ca72e03b68483978d39bd9b47cbbdcfdc0ae", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": {}, + "n_memory_holes": 0, + "n_steps": 46 + }, + "internal_calls": [], + "messages": [], + "result": [ + "0x6043f3a49c17ed4b13d21f2f9e35aa4f907a05e82a49afdfe4bd3325d95a24b" + ], + "selector": "0x3d86862f3be0ebd3c7396457ed05f70ed801cf44da58d84b1e0046548c2e843" + } + ], + "messages": [], + "result": [ + "0x6043f3a49c17ed4b13d21f2f9e35aa4f907a05e82a49afdfe4bd3325d95a24b" + ], + "selector": "0x3d86862f3be0ebd3c7396457ed05f70ed801cf44da58d84b1e0046548c2e843" + }, + { + "call_type": "CALL", + "calldata": [], + "caller_address": "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "class_hash": "0x6240d85927b6b70d6db57258e9d9aa3a5e63394a9d1ccb3ee65e10175834e6d", + "contract_address": "0x6043f3a49c17ed4b13d21f2f9e35aa4f907a05e82a49afdfe4bd3325d95a24b", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "bitwise_builtin": 9, + "range_check_builtin": 30 + }, + "n_memory_holes": 0, + "n_steps": 668 + }, + "internal_calls": [], + "messages": [], + "result": ["0xb865fed94a7d96b7"], + "selector": "0x22d392f6b02abfc2117f967337685830683d75ac6b349edee2b041f8fed2a4" + } + ], + "messages": [], + "result": ["0x0", "0x0"], + "selector": "0x1f64d317ff277789ba74de95db50418ab0fa47c09241400b7379b50d6334c3a" + } + ], + "messages": [], + "result": ["0x0", "0x0"], + "selector": "0x1f64d317ff277789ba74de95db50418ab0fa47c09241400b7379b50d6334c3a" + } + ], + "messages": [], + "result": ["0x0", "0x0"], + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" + } + ], + "messages": [], + "result": ["0x0", "0x0"], + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" + }, + "signature": [ + "0x6c9f975cbc16f23ae06f1277deed668d956eb71be3b57ad45a8b770475456d5", + "0x1800624e42396bedfce2e229dda4741795e552f80d83e2353059aa6c81f6842" + ], + "validate_invocation": { + "call_type": "CALL", + "calldata": [ + "0x1", + "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "0x1f64d317ff277789ba74de95db50418ab0fa47c09241400b7379b50d6334c3a", + "0x0", + "0x2", + "0x2", + "0x3", + "0x0" + ], + "caller_address": "0x0", + "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", + "contract_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "ecdsa_builtin": 1, + "range_check_builtin": 3 + }, + "n_memory_holes": 0, + "n_steps": 250 + }, + "internal_calls": [ + { + "call_type": "DELEGATE", + "calldata": [ + "0x1", + "0x27a1f51230a413c89fa4e81ecfe77afafaf34845d5b64917c689ad61faa27ee", + "0x1f64d317ff277789ba74de95db50418ab0fa47c09241400b7379b50d6334c3a", + "0x0", + "0x2", + "0x2", + "0x3", + "0x0" + ], + "caller_address": "0x0", + "class_hash": "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2", + "contract_address": "0x7642a1c8d575b0c0f9a7ad7cceb5517c02f36e5f3b36b25429cc7c99383ed0a", + "entry_point_type": "EXTERNAL", + "events": [], + "execution_resources": { + "builtin_instance_counter": { + "ecdsa_builtin": 1, + "range_check_builtin": 3 + }, + "n_memory_holes": 0, + "n_steps": 190 + }, + "internal_calls": [], + "messages": [], + "result": [], + "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775" + } + ], + "messages": [], + "result": [], + "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775" + } +} diff --git a/tests/__init__.py b/tests/__init__.py old mode 100644 new mode 100755 diff --git a/tests/protostar/exchange/test_deployment.cairo b/tests/protostar/exchange/test_deployment.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/exchange/test_formulas.cairo b/tests/protostar/exchange/test_formulas.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/loot/adventurer/test_adventurer.cairo b/tests/protostar/loot/adventurer/test_adventurer.cairo old mode 100644 new mode 100755 index 25a47d38..3a381a19 --- a/tests/protostar/loot/adventurer/test_adventurer.cairo +++ b/tests/protostar/loot/adventurer/test_adventurer.cairo @@ -1,4 +1,6 @@ %lang starknet + +from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin from starkware.cairo.common.uint256 import Uint256, uint256_add, uint256_sub from starkware.cairo.common.math_cmp import is_nn, is_le @@ -10,7 +12,8 @@ from contracts.loot.constants.rankings import ItemRank from contracts.loot.loot.stats.item import ItemStats from contracts.loot.constants.physics import MaterialDensity from contracts.loot.constants.adventurer import ( - Adventurer, + Adventurer, + AdventurerSlotIds, AdventurerState, AdventurerStatic, AdventurerDynamic, @@ -242,5 +245,71 @@ func test_discovery{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ assert r = DiscoveryType.Beast; + return (); +} + +@external +func test_upgrading{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + alloc_locals; + + let (state) = get_adventurer_state(); + + let (adventurer_static, adventurer_dynamic) = AdventurerLib.split_data(state); + + let (adventurer_state: PackedAdventurerState) = AdventurerLib.pack(adventurer_dynamic); + + let (unpacked_adventurer: AdventurerDynamic) = AdventurerLib.unpack(adventurer_state); + + let (c) = AdventurerLib.set_upgrading(TRUE, unpacked_adventurer); + + assert c.Upgrading = TRUE; + + let (c_statistics) = AdventurerLib.update_statistics(AdventurerSlotIds.Strength, c); + + assert c_statistics.Strength = 1; + + return (); +} + +// @notice Tests gold discovery calculation +// Gold calculation is: +// 1 + (rnd % 4) +@external +func test_calculate_gold_discovery{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + let (gold_discovery) = AdventurerLib.calculate_gold_discovery(1); + + assert gold_discovery = 2; + + return (); +} + +// @notice Tests health discovery calculation +// Health calculation is: +// 10 + (5 * (rnd % 4)) +@external +func test_calculate_health_discovery{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + let (health_discovery) = AdventurerLib.calculate_health_discovery(0); + + assert health_discovery = 10; + + return (); +} + +// @notice Tests xp discovery calculation +// Xp calculation is: +// 10 + (5 * (rnd % 4)) +@external +func test_calculate_xp_discovery{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + let (xp_discovery) = AdventurerLib.calculate_xp_discovery(0); + + assert xp_discovery = 10; + return (); } \ No newline at end of file diff --git a/tests/protostar/loot/adventurer/test_adventurer_logic.cairo b/tests/protostar/loot/adventurer/test_adventurer_logic.cairo old mode 100644 new mode 100755 index 56f4d8d5..44ee94a7 --- a/tests/protostar/loot/adventurer/test_adventurer_logic.cairo +++ b/tests/protostar/loot/adventurer/test_adventurer_logic.cairo @@ -11,14 +11,16 @@ from contracts.loot.constants.rankings import ItemRank from contracts.loot.loot.stats.item import ItemStats from contracts.loot.constants.physics import MaterialDensity from contracts.loot.constants.adventurer import ( - Adventurer, - AdventurerState, - PackedAdventurerState, - AdventurerStatus + Adventurer, + AdventurerSlotIds, + AdventurerState, + PackedAdventurerState, + AdventurerStatus, + DiscoveryType, ) from contracts.loot.adventurer.library import AdventurerLib -from tests.protostar.loot.setup.interfaces import IAdventurer, ILoot, ILords, IRealms +from tests.protostar.loot.setup.interfaces import IAdventurer, IBeast, ILoot, ILords, IRealms from tests.protostar.loot.setup.setup import Contracts, deploy_all from tests.protostar.loot.test_structs import ( TestAdventurerState, @@ -30,8 +32,7 @@ from tests.protostar.loot.test_structs import ( ) @external -func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -{ +func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; let addresses: Contracts = deploy_all(); @@ -41,6 +42,7 @@ func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( context.xoroshiro = ids.addresses.xoroshiro context.realms = ids.addresses.realms context.adventurer = ids.addresses.adventurer + context.beast = ids.addresses.beast context.loot = ids.addresses.loot context.lords = ids.addresses.lords stop_prank_lords = start_prank(ids.addresses.account_1, ids.addresses.lords) @@ -48,9 +50,7 @@ func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( ILords.approve(addresses.lords, addresses.adventurer, Uint256(100000000000000000000, 0)); - %{ - stop_prank_lords() - %} + %{ stop_prank_lords() %} return (); } @@ -74,16 +74,106 @@ func test_mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( %} IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); - let (local allowance: Uint256) = ILords.allowance(lords_address, account_1_address, adventurer_address); + let (local allowance: Uint256) = ILords.allowance( + lords_address, account_1_address, adventurer_address + ); IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); let (new_balance: Uint256) = ILords.balanceOf(lords_address, account_1_address); - assert new_balance = Uint256(0, 0); + assert new_balance = Uint256(100000000000000000000, 0); + + return (); +} + +@external +func test_mint_with_starting_weapon{ + syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + alloc_locals; + + local account_1_address; + local realms_address; + local adventurer_address; + local lords_address; + local loot_address; + %{ - stop_prank_realms() - stop_prank_adventurer() + ids.account_1_address = context.account_1 + ids.realms_address = context.realms + ids.adventurer_address = context.adventurer + ids.lords_address = context.lords + ids.loot_address = context.loot + stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + %} + + IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); + + // Mint an adventurer with a book as a starting weapon + IAdventurer.mint_with_starting_weapon( + adventurer_address, account_1_address, 4, 13, 'Test', 8, 1, 1, ItemIds.Book + ); + + %{ stop_prank_lords = start_prank(ids.account_1_address, ids.lords_address) %} + + ILords.approve(lords_address, adventurer_address, Uint256(100000000000000000000, 0)); + + %{ stop_prank_lords() %} + + // Mint an adventurer with a book as a starting weapon + IAdventurer.mint_with_starting_weapon( + adventurer_address, account_1_address, 4, 13, 'Test', 8, 1, 1, ItemIds.Book + ); + + let (new_balance: Uint256) = ILords.balanceOf(lords_address, account_1_address); + + // assert new_balance = Uint256(0, 0); + + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + let (adventurer_item) = ILoot.get_item_by_token_id( + loot_address, Uint256(adventurer.WeaponId, 0) + ); + assert adventurer_item.Id = ItemIds.Book; + + let (next_adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(2, 0)); + let (next_adventurer_item) = ILoot.get_item_by_token_id( + loot_address, Uint256(next_adventurer.WeaponId, 0) + ); + assert next_adventurer_item.Id = ItemIds.Book; + + return (); +} + +@external +func test_mint_non_starting_weapon{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + ) { + alloc_locals; + + local account_1_address; + local realms_address; + local adventurer_address; + local lords_address; + local loot_address; + + %{ + ids.account_1_address = context.account_1 + ids.realms_address = context.realms + ids.adventurer_address = context.adventurer + ids.lords_address = context.lords + ids.loot_address = context.loot + stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) %} + IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); + + %{ expect_revert(error_message="Loot: Item is not a starter weapon") %} + + // Test minting adventurer with a non starting weapon + IAdventurer.mint_with_starting_weapon( + adventurer_address, account_1_address, 4, 13, 'Test', 8, 1, 1, ItemIds.Katana + ); + return (); } @@ -103,27 +193,27 @@ func test_equip_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check ids.loot_address = context.loot stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) - stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} - let (timestamp) = get_block_timestamp(); - ILoot.mint(loot_address, account_1_address); - ILoot.setItemById(loot_address, Uint256(1,0), ItemIds.Wand, 0, 0, 0, 0); IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); %{ stop_prank_loot() - stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) + stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) %} - IAdventurer.equip_item(adventurer_address, Uint256(1,0), Uint256(1,0)); - let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1,0)); - let (adventurer_item) = ILoot.getItemByTokenId(loot_address, Uint256(adventurer.WeaponId, 0)); - assert adventurer_item.Id = ItemIds.Wand; - + // make sure adventurer and bag are set to 0 + ILoot.set_item_by_id(loot_address, Uint256(1, 0), ItemIds.Wand, 0, 0, 0, 0); %{ - stop_prank_realms() - stop_prank_adventurer() stop_prank_loot() + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} + IAdventurer.equip_item(adventurer_address, Uint256(1, 0), Uint256(1, 0)); + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + let (adventurer_item) = ILoot.get_item_by_token_id( + loot_address, Uint256(adventurer.WeaponId, 0) + ); + assert adventurer_item.Id = ItemIds.Wand; return (); } @@ -144,28 +234,28 @@ func test_unequip_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_che ids.loot_address = context.loot stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) - stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} - let (timestamp) = get_block_timestamp(); - ILoot.mint(loot_address, account_1_address); - ILoot.setItemById(loot_address, Uint256(1,0), ItemIds.Wand, 15, 0, 0, 0); IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); + // make sure adventurer and bag are set to 0 %{ stop_prank_loot() - stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) + stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) %} - IAdventurer.equip_item(adventurer_address, Uint256(1,0), Uint256(1,0)); - IAdventurer.unequip_item(adventurer_address, Uint256(1,0), Uint256(1,0)); - let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1,0)); - let (adventurer_item) = ILoot.getItemByTokenId(loot_address, Uint256(adventurer.WeaponId, 0)); - assert adventurer_item.Id = 0; - + ILoot.set_item_by_id(loot_address, Uint256(1, 0), ItemIds.Wand, 0, 0, 0, 0); %{ - stop_prank_realms() - stop_prank_adventurer() stop_prank_loot() + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} + IAdventurer.equip_item(adventurer_address, Uint256(1, 0), Uint256(1, 0)); + IAdventurer.unequip_item(adventurer_address, Uint256(1, 0), Uint256(1, 0)); + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + let (adventurer_item) = ILoot.get_item_by_token_id( + loot_address, Uint256(adventurer.WeaponId, 0) + ); + assert adventurer_item.Id = 0; return (); } @@ -195,13 +285,9 @@ func test_deduct_health{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_ch stop_prank_adventurer() stop_prank_adventurer = start_prank(ids.loot_address, ids.adventurer_address) %} - IAdventurer.deduct_health(adventurer_address, Uint256(1,0), 50); - let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1,0)); + IAdventurer.deduct_health(adventurer_address, Uint256(1, 0), 50); + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); assert adventurer.Health = 50; - %{ - stop_prank_realms() - stop_prank_adventurer() - %} return (); } @@ -222,7 +308,6 @@ func test_increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec ids.loot_address = context.loot stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) - %} IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); @@ -233,7 +318,7 @@ func test_increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec stop_prank_adventurer = start_prank(ids.loot_address, ids.adventurer_address) %} - let adventurer_token_id = Uint256(1,0); + let adventurer_token_id = Uint256(1, 0); IAdventurer.increase_xp(adventurer_address, adventurer_token_id, 10); let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, adventurer_token_id); @@ -241,47 +326,330 @@ func test_increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec // Adventuer should now have 10XP and be on Level 2 assert adventurer.XP = 10; assert adventurer.Level = 2; + + return (); +} + +@external +func test_purchase_health{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + local account_1_address; + local xoroshiro_address; + local realms_address; + local adventurer_address; + local beast_address; + local loot_address; + + %{ + ids.account_1_address = context.account_1 + ids.realms_address = context.realms + ids.adventurer_address = context.adventurer + ids.beast_address = context.beast + ids.loot_address = context.loot + stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + %} + + IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); + IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + + %{ + stop_prank_beast = start_prank(ids.adventurer_address, ids.beast_address) + stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.beast_address, ids.adventurer_address) + %} + + // store balance of 5 gold + IBeast.add_to_balance(beast_address, Uint256(1, 0), 100); + + %{ + stop_prank_beast() + stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + %} + + IAdventurer.purchase_health(adventurer_address, Uint256(1, 0), 1); + + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + + assert adventurer.Health = 100; + %{ - stop_prank_realms() stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.beast_address, ids.adventurer_address) %} + + IAdventurer.deduct_health(adventurer_address, Uint256(1, 0), 90); + + %{ + stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + %} + + IAdventurer.purchase_health(adventurer_address, Uint256(1, 0), 5); + + let (new_adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + + assert new_adventurer.Health = 60; + return (); } @external -func test_explore{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +func test_upgrade_stat{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; local account_1_address; local xoroshiro_address; local realms_address; local adventurer_address; + local beast_address; local loot_address; %{ ids.account_1_address = context.account_1 - ids.xoroshiro_address = context.xoroshiro ids.realms_address = context.realms ids.adventurer_address = context.adventurer + ids.beast_address = context.beast ids.loot_address = context.loot stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) - stop_mock_adventurer_random = mock_call(ids.xoroshiro_address, 'next', [1]) %} IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); - IAdventurer.explore(adventurer_address, Uint256(1,0)); - let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1,0)); + %{ + stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.beast_address, ids.adventurer_address) + %} + + // enough xp to level up + IAdventurer.increase_xp(adventurer_address, Uint256(1, 0), 9); + + %{ + stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + %} + + // upgrade strength + IAdventurer.upgrade_stat(adventurer_address, Uint256(1, 0), AdventurerSlotIds.Strength); + + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + + assert adventurer.Strength = 1; + + %{ expect_revert(error_message="Adventurer: Adventurer must be upgradable") %} + + // try upgrade strength again + IAdventurer.upgrade_stat(adventurer_address, Uint256(1, 0), AdventurerSlotIds.Strength); + + return (); +} + +// @external +// func test_discover_loot{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +// alloc_locals; + +// local account_1_address; +// local xoroshiro_address; +// local adventurer_address; +// local beast_address; + +// %{ +// ids.account_1_address = context.account_1 +// ids.xoroshiro_address = context.xoroshiro +// ids.adventurer_address = context.adventurer +// ids.beast_address = context.beast +// # 3%4 = 3, therefore DiscoveryType item +// stop_mock = mock_call(ids.xoroshiro_address, 'next', [3]) +// # now we are timsing by timestamp we also need this +// stop_roll_adventurer = roll(1, ids.adventurer_address) +// stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) +// stop_prank_beast = start_prank(ids.adventurer_address, ids.beast_address) +// %} + +// IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + +// %{ +// from tests.protostar.loot.utils import utils +// # need to store adventurer level to greater than 1 to avoid starter beast +// p1, p2, p3, p4 = utils.pack_adventurer(utils.build_adventurer_level(2)) +// store(ids.adventurer_address, "adventurer_dynamic", [p1, p2, p3, p4], key=[1,0]) +// %} + +// let (discovery_type, r) = IAdventurer.explore(adventurer_address, Uint256(1,0)); + +// assert discovery_type = DiscoveryType.Item; +// assert r = 0; + +// return (); +// } + +@external +func test_discover_health{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + local account_1_address; + local xoroshiro_address; + local adventurer_address; + local beast_address; + + %{ + ids.account_1_address = context.account_1 + ids.xoroshiro_address = context.xoroshiro + ids.adventurer_address = context.adventurer + ids.beast_address = context.beast + # 3%4 = 3, therefore DiscoveryType item + stop_mock = mock_call(ids.xoroshiro_address, 'next', [3]) + # now we are timsing by timestamp we also need this + stop_roll_adventurer = roll(1, ids.adventurer_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + stop_prank_beast = start_prank(ids.adventurer_address, ids.beast_address) + %} + + IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + + %{ + from tests.protostar.loot.utils import utils + # need to store adventurer level to greater than 1 to avoid starter beast + p1, p2, p3, p4 = utils.pack_adventurer(utils.build_adventurer_level(2)) + store(ids.adventurer_address, "adventurer_dynamic", [p1, p2, p3, p4], key=[1,0]) + %} + + %{ + stop_prank_adventurer() + stop_prank_adventurer = start_prank(ids.beast_address, ids.adventurer_address) + %} - assert adventurer.Status = AdventurerStatus.Battle; + // deduct health to measure health increase + IAdventurer.deduct_health(adventurer_address, Uint256(1, 0), 50); %{ - stop_prank_realms() stop_prank_adventurer() - stop_mock_adventurer_random() + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) %} + let (discovery_type, r) = IAdventurer.explore(adventurer_address, Uint256(1, 0)); + + assert discovery_type = DiscoveryType.Item; + assert r = 0; + + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + + // 50 + (10 + (5 * 3)) + assert adventurer.Health = 75; + return (); -} \ No newline at end of file +} + +@external +func test_discover_obstacle{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + local account_1_address; + local xoroshiro_address; + local adventurer_address; + local beast_address; + + %{ + ids.account_1_address = context.account_1 + ids.xoroshiro_address = context.xoroshiro + ids.adventurer_address = context.adventurer + ids.beast_address = context.beast + # 2%4 = 2, therefore DiscoveryType obstacle + stop_mock = mock_call(ids.xoroshiro_address, 'next', [2]) + # now we are timsing by timestamp we also need this + stop_roll_adventurer = roll(1, ids.adventurer_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + stop_prank_beast = start_prank(ids.adventurer_address, ids.beast_address) + %} + IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + + %{ + from tests.protostar.loot.utils import utils + # need to store adventurer level to greater than 1 to avoid starter beast + p1, p2, p3, p4 = utils.pack_adventurer(utils.build_adventurer_level(2)) + store(ids.adventurer_address, "adventurer_dynamic", [p1, p2, p3, p4], key=[1,0]) + %} + let (discovery_type, obstacle_id) = IAdventurer.explore(adventurer_address, Uint256(1, 0)); + + assert discovery_type = DiscoveryType.Obstacle; + assert obstacle_id = 3; + + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); + + // Obstacle level will be same as adventurer level (until level 3) + // So for this test since adventurer is level 2, obstacle will be level 2 + // Obstacle ID is 3 which is a Hex which is a tier 3 + // Since adventurer isn't wearing any armor, elemental_multiplier will always be HIGH which is 3 + + // (6 - OBSTACLE_TIER) * OBSTACLE_LEVEL * ELEMENTAL_MULTIPLIER + // (6 - 3) * 2 * 3 = 18HP of damage dealt to adventurer + // 100HP - 18HP = 82 + assert adventurer.Health = 82; + + return (); +} + +@external +func test_king_tribute{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + local account_1_address; + local xoroshiro_address; + local adventurer_address; + local beast_address; + local lords_address; + + %{ + ids.account_1_address = context.account_1 + ids.xoroshiro_address = context.xoroshiro + ids.adventurer_address = context.adventurer + ids.beast_address = context.beast + ids.lords_address = context.lords + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + stop_prank_beast = start_prank(ids.adventurer_address, ids.beast_address) + %} + IAdventurer.mint_with_starting_weapon(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1, 12); + + let (total_lords) = ILords.balanceOf(lords_address, adventurer_address); + + assert total_lords = Uint256(50000000000000000000,0); + + IAdventurer.become_king(adventurer_address, Uint256(1,0)); + + // should fail as not enough time passed + %{ + stop_warp = warp(20000, ids.adventurer_address) + expect_revert(error_message="Adventurer: King not active for 12 hours.") + %} + + IAdventurer.pay_king_tribute(adventurer_address); + + %{ + stop_warp() + # change timestamp to over tribute duration + warp(43201, ids.adventurer_address) + %} + + IAdventurer.pay_king_tribute(adventurer_address); + + let (lords_balance) = ILords.balanceOf(lords_address, account_1_address); + let (new_total_lords) = ILords.balanceOf(lords_address, adventurer_address); + + // check lords balance has increased by 10% of the pool (account 1 still already has 10) + // pool should also have 10% less + + assert new_total_lords = Uint256(45000000000000000000,0); + assert lords_balance = Uint256(105000000000000000000,0); + + // should fail as timer reset + %{ + expect_revert(error_message="Adventurer: King not active for 12 hours.") + %} + + IAdventurer.pay_king_tribute(adventurer_address); + + return (); +} diff --git a/tests/protostar/loot/beast/test_beast.cairo b/tests/protostar/loot/beast/test_beast.cairo old mode 100644 new mode 100755 index 06d65e42..9893b6c0 --- a/tests/protostar/loot/beast/test_beast.cairo +++ b/tests/protostar/loot/beast/test_beast.cairo @@ -16,6 +16,8 @@ from contracts.loot.constants.beast import ( ) from contracts.loot.loot.stats.combat import CombatStats from tests.protostar.loot.test_structs import ( + create_adventurer, + get_adventurer_state, TestUtils, TEST_DAMAGE_HEALTH_REMAINING, TEST_DAMAGE_OVERKILL, @@ -171,6 +173,22 @@ func test_slain{ return (); } +@external +func test_calculate_critical_damage{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + let (critical_damage) = CombatStats.calculate_critical_damage(20, 1); + + assert critical_damage = 30; + return (); +} + +@external +func test_calculate_adventurer_level_boost{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + let (adventurer_level_damage) = CombatStats.calculate_entity_level_boost(20, 1); + + assert adventurer_level_damage = 20; + return (); +} + // @notice Tests damage to beast calculation // Damage Calculation is: // Attack = Greatness * (6 - item_rank) * attack_effectiveness @@ -180,13 +198,18 @@ func test_slain{ func test_calculate_damage_to_beast{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; + let (adventurer_state) = get_adventurer_state(); + let (greatness_8_mace) = TestUtils.create_item(75, 8); // Greatness 8 Mace (Bludgeon) vs let (xp_1_basilisk) = TestUtils.create_beast(4, 1); // Level 1 Basilisk (Magic) // attack = 8 * (6-4) * 1 = 16 // defense = 1 * (6-4) = 2 // 16 - 2 = 14HP damage - let (mace_vs_basilik) = CombatStats.calculate_damage_to_beast(xp_1_basilisk, greatness_8_mace); + let (mace_vs_basilik) = CombatStats.calculate_damage_to_beast(xp_1_basilisk, greatness_8_mace, adventurer_state, 1); + + // adventurer boost = 14 * (1 + ((1-1) * 0.1)) = 14 + // no critical hit assert mace_vs_basilik = 14; // TODO: Test attacking without weapon (melee) @@ -212,11 +235,84 @@ func test_calculate_damage_from_beast{syscall_ptr: felt*, pedersen_ptr: HashBuil // beast_attack = 2 * (6-1) * 1 = 10 // armor_defense = 1 * (6-4) = 2 // 10 attack - 2 defense = 8hp damage - let (local damage) = CombatStats.calculate_damage_from_beast(beast, armor); + let (local damage) = CombatStats.calculate_damage_from_beast(beast, armor, 1); + + // beast level boost = 8 * ((1-1) + 2 * 0.1) = 9 + // no critical assert damage = 8; // TODO: Test defending without armor - // let (armor) = TestUtils.create_zero_item(); return (); -} \ No newline at end of file +} + +// @notice Tests damage from beast calculation in late game +// Damage Calculation is: +// Attack = Greatness * (6 - item_rank) * attack_effectiveness +// Armor = Greatness * (6 - item_rank) +// Damage Taken = Attack - Armor (can't be negative) +@external +func test_calculate_damage_from_beast_late_game{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + let (beast) = TestUtils.create_beast(11, 20); // levl 20 giant (rank 1) + let (cloth_armor) = TestUtils.create_item(18, 20); // lvl 20 silk robe (rank 2) + + // base weapon damage: 100 + // armor strength: 80 + // attack effectiveness: 1 + // total weapon damage: (100 - 80) * 1 = 20 + + let (cloth_damage) = CombatStats.calculate_damage_from_beast(beast, cloth_armor, 1); + + assert cloth_damage = 20; + + let (metal_armor) = TestUtils.create_item(78, 20); // lvl 20 ornate chestplate(rank 2) + + let (metal_damage) = CombatStats.calculate_damage_from_beast(beast, metal_armor, 1); + + assert metal_damage = 40; + + let (hide_armor) = TestUtils.create_item(48, 20); // lvl 20 dragonskin armor (rank 2) + + let (hide_damage) = CombatStats.calculate_damage_from_beast(beast, hide_armor, 1); + + assert hide_damage = 60; + + // TODO: Test defending without armor + + let (no_armor) = TestUtils.create_item(0, 0); // no item + + let (no_armor_damage) = CombatStats.calculate_damage_from_beast(beast, no_armor, 1); + + assert no_armor_damage = 300; + + return (); +} + +// @notice Tests ambush chance calculation +// Ambush calculation is: +// random_number * (health / 50) +@external +func test_ambush_chance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + + let (ambush_chance) = BeastLib.calculate_ambush_chance(1, 69); + + assert ambush_chance = 2; + + return (); +} + +// @notice Tests ambush chance calculation +// Ambush calculation is: +// (xp_gained - (xp_gained/4)) + ((xp_gained/4) * (rand % 4)) +@external +func test_calculate_gold_reward{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { + alloc_locals; + + let (gold_reward) = BeastLib.calculate_gold_reward(0, 5); + + assert gold_reward = 4; + + return (); +} diff --git a/tests/protostar/loot/beast/test_beast_logic.cairo b/tests/protostar/loot/beast/test_beast_logic.cairo old mode 100644 new mode 100755 index 6569d7b9..36c85abc --- a/tests/protostar/loot/beast/test_beast_logic.cairo +++ b/tests/protostar/loot/beast/test_beast_logic.cairo @@ -7,13 +7,7 @@ from starkware.starknet.common.syscalls import get_block_timestamp from contracts.loot.constants.adventurer import AdventurerState, AdventurerStatus from contracts.loot.constants.beast import Beast from contracts.loot.beast.library import BeastLib -from contracts.loot.constants.item import ( - Item, - ItemIds, - ItemType, - ItemMaterial, - ItemSlot -) +from contracts.loot.constants.item import Item, ItemIds, ItemType, ItemMaterial, ItemSlot from contracts.loot.constants.rankings import ItemRank from contracts.loot.loot.stats.combat import CombatStats from tests.protostar.loot.setup.interfaces import ILoot, IRealms, IAdventurer, IBeast, ILords @@ -42,23 +36,23 @@ func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( stop_prank_realms = start_prank(ids.addresses.account_1, ids.addresses.realms) stop_prank_adventurer = start_prank(ids.addresses.account_1, ids.addresses.adventurer) stop_prank_lords = start_prank(ids.addresses.account_1, ids.addresses.lords) - stop_prank_loot = start_prank(ids.addresses.account_1, ids.addresses.loot) + stop_prank_loot = start_prank(ids.addresses.adventurer, ids.addresses.loot) %} - ILords.approve(addresses.lords, addresses.adventurer, Uint256(10000, 0)); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.setItemById(addresses.loot, Uint256(1,0), ItemIds.Wand, 10, 0, 0, 0); + ILords.approve(addresses.lords, addresses.adventurer, Uint256(100000000000000000000, 0)); IRealms.set_realm_data(addresses.realms, Uint256(13, 0), 'Test Realm', 1); - %{ - stop_prank_lords() - %} - + %{ stop_prank_lords() %} IAdventurer.mint(addresses.adventurer, addresses.account_1, 4, 10, 'Test', 8, 1, 1); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1, 0)); %{ stop_prank_loot() + stop_prank_loot = start_prank(ids.addresses.account_1, ids.addresses.loot) %} - IAdventurer.equip_item(addresses.adventurer, Uint256(1,0), Uint256(1,0)); + + ILoot.set_item_by_id(addresses.loot, Uint256(1, 0), ItemIds.Wand, 10, 0, 0, 0); + %{ stop_prank_loot() %} + IAdventurer.equip_item(addresses.adventurer, Uint256(1, 0), Uint256(1, 0)); %{ stop_prank_realms() stop_prank_adventurer() @@ -84,12 +78,12 @@ func test_create{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr stop_mock = mock_call(ids.xoroshiro_address, 'next', [0]) %} - let (beast_id) = IBeast.create(beast_address, Uint256(1,0)); + let (beast_id) = IBeast.create(beast_address, Uint256(1, 0)); let (beast) = IBeast.get_beast_by_id(beast_address, beast_id); assert beast.Id = 1; - assert beast.Health = 100; + assert beast.Health = 11; assert beast.AttackType = 103; assert beast.ArmorType = 203; assert beast.Rank = 1; @@ -100,18 +94,13 @@ func test_create{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr assert beast.Level = 1; assert beast.SlainOnDate = 0; - %{ - stop_prank_beast() - stop_mock() - %} - return (); } @external func test_not_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; - + local account_1_address; local xoroshiro_address; local adventurer_address; @@ -122,34 +111,53 @@ func test_not_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_p ids.xoroshiro_address = context.xoroshiro ids.adventurer_address = context.adventurer ids.beast_address = context.beast - stop_mock_adventurer_random = mock_call(ids.xoroshiro_address, 'next', [1]) + # 1%4 = 1, therefore DiscoveryType beast + stop_mock = mock_call(ids.xoroshiro_address, 'next', [1]) + # now we are timsing by timestamp we also need this + stop_roll_adventurer = roll(1, ids.adventurer_address) + stop_roll_beast = roll(1, ids.beast_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + from tests.protostar.loot.utils import utils + # need to store adventurer level to greater than 1 to avoid starter beast + p1, p2, p3, p4 = utils.pack_adventurer(utils.build_adventurer_level(2)) + store(ids.adventurer_address, "adventurer_dynamic", [p1, p2, p3, p4], key=[1,0]) %} - // discover and create beast - let adventurer_token_id_1 = Uint256(1,0); - let beast_token_id_1 = Uint256(1,0); - + // discover beast + + let adventurer_token_id_1 = Uint256(1, 0); + let beast_token_id_1 = Uint256(1, 0); + IAdventurer.explore(adventurer_address, adventurer_token_id_1); - %{ + let (local adventurer) = IAdventurer.get_adventurer_by_id( + adventurer_address, adventurer_token_id_1 + ); + + %{ + stop_roll_adventurer() + stop_roll_beast = roll(1, ids.beast_address) + stop_mock() stop_prank_adventurer() stop_prank_beast = start_prank(ids.account_1_address, ids.beast_address) %} + let (original_beast) = IBeast.get_beast_by_id(beast_address, beast_token_id_1); + IBeast.attack(beast_address, beast_token_id_1); - let (updated_beast) = IBeast.get_beast_by_id(beast_address,beast_token_id_1); - let (updated_adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, adventurer_token_id_1); + let (updated_beast) = IBeast.get_beast_by_id(beast_address, beast_token_id_1); - %{ - stop_mock_adventurer_random() - stop_prank_beast() - %} + assert updated_beast.Id = 2; + assert updated_beast.Level = 2; + // since we have overwritten adventurer (made level 2 and so removed wand) we will do no damage + assert updated_beast.Health = original_beast.Health; + + let (updated_adventurer) = IAdventurer.get_adventurer_by_id( + adventurer_address, adventurer_token_id_1 + ); - // adventurer did 36hp to the beast - assert updated_beast.Health = 64; - // adventurer took 12 damage from the beasts counter attack - assert updated_adventurer.Health = 88; + // adventurer took 24 damage from the beasts counter attack + assert updated_adventurer.Health = 76; // TODO LH: verify neither beast nor adventurer gained xp @@ -159,7 +167,7 @@ func test_not_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_p @external func test_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; - + local account_1_address; local xoroshiro_address; local adventurer_address; @@ -172,28 +180,39 @@ func test_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( ids.adventurer_address = context.adventurer ids.beast_address = context.beast ids.loot_address = context.loot - stop_mock_adventurer_random = mock_call(ids.xoroshiro_address, 'next', [1]) + # 1%4 = 1, therefore DiscoveryType beast + stop_mock = mock_call(ids.xoroshiro_address, 'next', [1]) + # now we are timsing by timestamp we also need this + stop_roll_adventurer = roll(1, ids.adventurer_address) + stop_roll_beast = roll(1, ids.beast_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) %} - // discover and create beast - let adventurer_token_id = Uint256(1,0); + // discover beast + let adventurer_token_id = Uint256(1, 0); IAdventurer.explore(adventurer_address, adventurer_token_id); - %{ + %{ + stop_mock() stop_prank_adventurer() - stop_prank_beast = start_prank(ids.account_1_address, ids.beast_address) %} - let loot_token_id = Uint256(1,0); - ILoot.setItemById(loot_address, loot_token_id, ItemIds.Katana, 20, 0, 0, 0); + let loot_token_id = Uint256(1, 0); + ILoot.set_item_by_id(loot_address, loot_token_id, ItemIds.Katana, 20, 0, 0, 0); - let beast_token_id = Uint256(1,0); + %{ + stop_prank_loot() + stop_prank_beast = start_prank(ids.account_1_address, ids.beast_address) + %} + + let beast_token_id = Uint256(1, 0); IBeast.attack(beast_address, beast_token_id); let (local updated_beast) = IBeast.get_beast_by_id(beast_address, beast_token_id); - let (local adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, adventurer_token_id); + let (local adventurer) = IAdventurer.get_adventurer_by_id( + adventurer_address, adventurer_token_id + ); // Beast should be dead assert updated_beast.Health = 0; @@ -204,12 +223,7 @@ func test_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( // check our adventurer earned xp for the kill let (expected_xp) = CombatStats.calculate_xp_earned(updated_beast.Rank, updated_beast.Level); // Since we used a new adventurer, this should be the only xp they have gained - assert adventurer.XP = expected_xp; - - %{ - stop_mock_adventurer_random() - stop_prank_beast() - %} + assert adventurer.XP = 10; return (); } @@ -217,7 +231,7 @@ func test_kill{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( @external func test_ambushed{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; - + local account_1_address; local xoroshiro_address; local adventurer_address; @@ -228,37 +242,40 @@ func test_ambushed{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_p ids.xoroshiro_address = context.xoroshiro ids.adventurer_address = context.adventurer ids.beast_address = context.beast - stop_mock_adventurer_random = mock_call(ids.xoroshiro_address, 'next', [1]) + # 1%4 = 1, therefore DiscoveryType beast + stop_mock = mock_call(ids.xoroshiro_address, 'next', [1]) + # now we are timsing by timestamp we also need this + stop_roll_adventurer = roll(1, ids.adventurer_address) + stop_roll_beast = roll(1, ids.beast_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) %} - // discover and create beast - IAdventurer.explore(adventurer_address, Uint256(1,0)); + // discover beast + + IAdventurer.explore(adventurer_address, Uint256(1, 0)); - %{ - stop_mock_adventurer_random() + %{ + stop_mock() stop_prank_adventurer() - stop_prank_beast = start_prank(ids.account_1_address, ids.beast_address) + # 2%4 = 2, therefore not fleeing stop_mock_flee_random = mock_call(ids.xoroshiro_address, 'next', [2]) + # now we are timsing by timestamp we also need this + stop_roll = roll(1, ids.adventurer_address) + stop_prank_beast = start_prank(ids.account_1_address, ids.beast_address) %} - IBeast.flee(beast_address, Uint256(1,0)); + IBeast.flee(beast_address, Uint256(1, 0)); - let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1,0)); + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); assert adventurer.Status = AdventurerStatus.Battle; - %{ - stop_mock_flee_random() - stop_prank_beast() - %} - return (); } @external func test_flee{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; - + local account_1_address; local xoroshiro_address; local adventurer_address; @@ -269,37 +286,40 @@ func test_flee{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( ids.xoroshiro_address = context.xoroshiro ids.adventurer_address = context.adventurer ids.beast_address = context.beast - stop_mock_adventurer_random = mock_call(ids.xoroshiro_address, 'next', [1]) + # 1%4 = 1, therefore DiscoveryType beast + stop_mock = mock_call(ids.xoroshiro_address, 'next', [1]) + # now we are timsing by timestamp we also need this + stop_roll_adventurer = roll(1, ids.adventurer_address) + stop_roll_beast = roll(1, ids.beast_address) stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) %} - // discover and create beast - IAdventurer.explore(adventurer_address, Uint256(1,0)); + // discover beast + + IAdventurer.explore(adventurer_address, Uint256(1, 0)); - %{ - stop_mock_adventurer_random() + %{ + stop_mock() stop_prank_adventurer() stop_prank_beast = start_prank(ids.account_1_address, ids.beast_address) + # 3%4 = 3, therefore fleeing stop_mock_flee_random = mock_call(ids.xoroshiro_address, 'next', [3]) + # now we are timsing by timestamp we also need this + stop_roll = roll(1, ids.beast_address) %} - IBeast.flee(beast_address, Uint256(1,0)); + IBeast.flee(beast_address, Uint256(1, 0)); - let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1,0)); + let (adventurer) = IAdventurer.get_adventurer_by_id(adventurer_address, Uint256(1, 0)); assert adventurer.Status = AdventurerStatus.Idle; - %{ - stop_mock_flee_random() - stop_prank_beast() - %} - return (); } @external func test_increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; - + local account_1_address; local xoroshiro_address; local beast_address; @@ -310,17 +330,19 @@ func test_increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec ids.xoroshiro_address = context.xoroshiro ids.beast_address = context.beast ids.adventurer_address = context.adventurer - stop_mock = mock_call(ids.xoroshiro_address, 'next', [0]) + stop_roll_beast = roll(1, ids.beast_address) stop_prank_adventurer = start_prank(ids.adventurer_address, ids.beast_address) %} - let beast_token_id = Uint256(1,0); + let beast_token_id = Uint256(1, 0); let (beast_id) = IBeast.create(beast_address, beast_token_id); let (beast) = IBeast.get_beast_by_id(beast_address, beast_token_id); let (_, beast_dynamic) = BeastLib.split_data(beast); // Give our level 1 beast 10 XP (started with 1XP) - let (returned_beast_plus_10xp) = IBeast.increase_xp(beast_address, beast_token_id, beast_dynamic, 10); + let (returned_beast_plus_10xp) = IBeast.increase_xp( + beast_address, beast_token_id, beast_dynamic, 10 + ); let (onchain_beast_plus_10xp) = IBeast.get_beast_by_id(beast_address, beast_token_id); // verify it's now level 2 with 11xp @@ -329,10 +351,6 @@ func test_increase_xp{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec assert returned_beast_plus_10xp.Level = 2; assert onchain_beast_plus_10xp.XP = returned_beast_plus_10xp.XP; assert onchain_beast_plus_10xp.Level = returned_beast_plus_10xp.Level; - - %{ - stop_prank_adventurer() - %} return (); -} \ No newline at end of file +} diff --git a/tests/protostar/loot/loot/test_loot.cairo b/tests/protostar/loot/loot/test_loot.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/loot/loot/test_loot_logic.cairo b/tests/protostar/loot/loot/test_loot_logic.cairo old mode 100644 new mode 100755 index 08c32ca0..79e63fd9 --- a/tests/protostar/loot/loot/test_loot_logic.cairo +++ b/tests/protostar/loot/loot/test_loot_logic.cairo @@ -1,4 +1,6 @@ %lang starknet + +from starkware.cairo.common.bool import TRUE, FALSE from starkware.cairo.common.cairo_builtins import HashBuiltin from starkware.cairo.common.math import assert_not_zero from starkware.cairo.common.uint256 import Uint256 @@ -6,6 +8,8 @@ from starkware.cairo.common.uint256 import Uint256 from tests.protostar.loot.setup.interfaces import IAdventurer, ILoot, ILords, IRealms from tests.protostar.loot.setup.setup import Contracts, deploy_all +from contracts.loot.constants.item import ItemIds + @external func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; @@ -16,82 +20,262 @@ func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( context.account_1 = ids.addresses.account_1 context.adventurer = ids.addresses.adventurer context.loot = ids.addresses.loot + context.realms = ids.addresses.realms + stop_prank_lords = start_prank(ids.addresses.account_1, ids.addresses.lords) %} + + ILords.approve(addresses.lords, addresses.adventurer, Uint256(100000000000000000000, 0)); + + %{ stop_prank_lords() %} + return (); } +// @external +// func test_mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +// alloc_locals; + +// local account_1_address; +// local loot_address; +// local adventurer_address; +// local realms_address; + +// %{ +// ids.account_1_address = context.account_1 +// ids.loot_address = context.loot +// ids.adventurer_address = context.adventurer +// ids.realms_address = context.realms +// stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) +// stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) +// stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) +// %} + +// IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); +// IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + +// ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); + +// let (item) = ILoot.get_item_by_token_id(loot_address, Uint256(1, 0)); + +// assert_not_zero(item.Id); + +// return (); +// } + +// @external +// func test_mint_starter_weapon{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +// alloc_locals; + +// local account_1_address; +// local loot_address; +// local adventurer_address; +// local realms_address; + +// %{ +// ids.account_1_address = context.account_1 +// ids.loot_address = context.loot +// ids.adventurer_address = context.adventurer +// ids.realms_address = context.realms +// stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) +// stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) +// stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) +// %} + + +// IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); +// IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + +// // Mint a starter item for the adventurer (book) +// ILoot.mint_starter_weapon(loot_address, account_1_address, ItemIds.Book, Uint256(1, 0)); + +// // Get item from the contract +// let (item) = ILoot.get_item_by_token_id(loot_address, Uint256(1, 0)); + +// // Verify it is indeed a book +// assert item.Id = ItemIds.Book; + +// return (); +// } + +// @external +// func test_set_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +// alloc_locals; +// local account_1_address; +// local loot_address; +// local adventurer_address; +// local realms_address; + +// %{ +// ids.account_1_address = context.account_1 +// ids.loot_address = context.loot +// ids.adventurer_address = context.adventurer +// ids.realms_address = context.realms +// stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) +// stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) +// stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) +// %} + +// IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); +// IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + +// ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); + +// %{ +// stop_prank_loot() +// stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) +// %} + +// ILoot.set_item_by_id(loot_address, Uint256(1, 0), 20, 5, 100, 1, 30); + +// let (item) = ILoot.get_item_by_token_id(loot_address, Uint256(1, 0)); + +// assert item.Id = 20; +// assert item.Greatness = 5; +// assert item.XP = 100; +// assert item.Adventurer = 1; +// assert item.Bag = 30; + +// return (); +// } + +// @external +// func test_update_adventurer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +// alloc_locals; +// local account_1_address; +// local loot_address; +// local adventurer_address; +// local realms_address; + +// %{ +// ids.account_1_address = context.account_1 +// ids.loot_address = context.loot +// ids.adventurer_address = context.adventurer +// ids.realms_address = context.realms +// stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) +// stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) +// stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) +// %} + +// IRealms.set_realm_data(realms_address, Uint256(13, 0), 'Test Realm', 1); +// IAdventurer.mint(adventurer_address, account_1_address, 4, 10, 'Test', 8, 1, 1); + +// ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); + +// %{ +// stop_prank_loot() +// stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) +// %} + +// ILoot.update_adventurer(loot_address, Uint256(1, 0), 2); + +// let (item) = ILoot.get_item_by_token_id(loot_address, Uint256(1, 0)); + +// assert item.Adventurer = 2; + +// return (); +// } + @external -func test_mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +func mint_daily_items{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; - local account_1_address; local loot_address; + local adventurer_address; + local realms_address; %{ ids.account_1_address = context.account_1 ids.loot_address = context.loot + ids.adventurer_address = context.adventurer + ids.realms_address = context.realms + stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} - ILoot.mint(loot_address, account_1_address); - - let (item) = ILoot.getItemByTokenId(loot_address, Uint256(1, 0)); - - assert_not_zero(item.Id); + // mint item and adventurer + ILoot.mint_daily_items(loot_address); return (); } @external -func test_set_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +func test_bid_on_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; local account_1_address; local loot_address; + local adventurer_address; + local realms_address; %{ ids.account_1_address = context.account_1 ids.loot_address = context.loot - stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) + ids.adventurer_address = context.adventurer + ids.realms_address = context.realms + stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} + // mint item and adventurer + ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); + IAdventurer.mint_with_starting_weapon( + adventurer_address, account_1_address, 4, 13, 'Test', 8, 1, 1, ItemIds.Book + ); - ILoot.mint(loot_address, account_1_address); - - ILoot.setItemById(loot_address, Uint256(1, 0), 20, 5, 100, 5, 30); - - let (item) = ILoot.getItemByTokenId(loot_address, Uint256(1, 0)); + %{ + stop_prank_loot() + stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) + %} + ILoot.bid_on_item(loot_address, Uint256(1,0), Uint256(1,0), 3); - assert item.Id = 20; - assert item.Greatness = 5; - assert item.XP = 100; - assert item.Adventurer = 5; - assert item.Bag = 30; + let (bid) = ILoot.view_bid(loot_address, Uint256(1,0)); - %{ stop_prank_loot() %} + assert bid.price = 3; + assert bid.expiry = 1800; + assert bid.bidder = 1; + assert bid.status = 1; return (); } @external -func test_update_adventurer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { +func test_claim_item{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { alloc_locals; local account_1_address; local loot_address; local adventurer_address; + local realms_address; %{ ids.account_1_address = context.account_1 ids.loot_address = context.loot ids.adventurer_address = context.adventurer + ids.realms_address = context.realms + stop_prank_realms = start_prank(ids.account_1_address, ids.realms_address) + stop_prank_adventurer = start_prank(ids.account_1_address, ids.adventurer_address) + stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} + // mint item and adventurer + ILoot.mint(loot_address, account_1_address, Uint256(1, 0)); + IAdventurer.mint_with_starting_weapon( + adventurer_address, account_1_address, 4, 13, 'Test', 8, 1, 1, ItemIds.Book + ); - ILoot.mint(loot_address, account_1_address); + %{ + stop_prank_loot() + stop_prank_loot = start_prank(ids.account_1_address, ids.loot_address) + %} + ILoot.bid_on_item(loot_address, Uint256(1,0), Uint256(1,0), 3); - %{ stop_prank_loot = start_prank(ids.adventurer_address, ids.loot_address) %} + %{ + warp(1800, ids.loot_address) + %} - ILoot.updateAdventurer(loot_address, Uint256(1, 0), 2); + ILoot.claim_item(loot_address, Uint256(1,0), Uint256(1,0)); - let (item) = ILoot.getItemByTokenId(loot_address, Uint256(1, 0)); + let (check_item_owned) = ILoot.item_owner(loot_address, Uint256(1,0), Uint256(1,0)); - assert item.Adventurer = 2; + assert check_item_owned = TRUE; return (); -} +} \ No newline at end of file diff --git a/tests/protostar/loot/metadata/test_item_metadata_logic.cairo b/tests/protostar/loot/metadata/test_item_metadata_logic.cairo old mode 100644 new mode 100755 index d20d70ab..637c7158 --- a/tests/protostar/loot/metadata/test_item_metadata_logic.cairo +++ b/tests/protostar/loot/metadata/test_item_metadata_logic.cairo @@ -1,7 +1,6 @@ %lang starknet from starkware.cairo.common.uint256 import Uint256, uint256_add -from starkware.starknet.common.syscalls import get_block_timestamp from contracts.loot.loot.metadata import LootUri from contracts.loot.constants.adventurer import AdventurerState @@ -24,35 +23,36 @@ func __setup__{syscall_ptr: felt*, range_check_ptr}() { context.lords = ids.addresses.lords stop_prank_realms = start_prank(ids.addresses.account_1, ids.addresses.realms) stop_prank_adventurer = start_prank(ids.addresses.account_1, ids.addresses.adventurer) - stop_prank_loot = start_prank(ids.addresses.account_1, ids.addresses.loot) + stop_prank_loot = start_prank(ids.addresses.adventurer, ids.addresses.loot) stop_prank_lords = start_prank(ids.addresses.account_1, ids.addresses.lords) %} - IRealms.set_realm_data(addresses.realms, Uint256(10, 0), 'Test Realm', 1); - // Store item ids and equip to adventurer + IRealms.set_realm_data(addresses.realms, Uint256(10, 0), 'Test Realm', 1); + + ILords.approve(addresses.lords, addresses.adventurer, Uint256(100000000000000000000, 0)); - let (timestamp) = get_block_timestamp(); + %{ + stop_prank_lords() + stop_prank_lords = start_prank(ids.addresses.adventurer, ids.addresses.lords) + %} + + // Mint adventurer with random params + IAdventurer.mint(addresses.adventurer, addresses.account_1, 4, 10, 'Test', 8, 1, 1); + + // Store item ids and equip to adventurer %{ stop_mock = mock_call(1, 'next', [1]) %} // Mint a token - ILoot.mint(addresses.loot, addresses.account_1); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); %{ stop_mock() + stop_prank_loot() + stop_prank_loot = start_prank(ids.addresses.account_1, ids.addresses.loot) %} // Set tokens to ids above for testing - ILoot.setItemById(addresses.loot, Uint256(1,0), ItemIds.Wand, 20, 100, 0, 0); - - ILords.approve(addresses.lords, addresses.adventurer, Uint256(100,0)); - - %{ - stop_prank_lords() - stop_prank_lords = start_prank(ids.addresses.adventurer, ids.addresses.lords) - %} - - // Mint adventurer with random params - IAdventurer.mint(addresses.adventurer, addresses.account_1, 4, 10, 'Test', 8, 1, 1); + ILoot.set_item_by_id(addresses.loot, Uint256(1,0), ItemIds.Wand, 20, 100, 0, 0); %{ stop_prank_loot() diff --git a/tests/protostar/loot/metadata/test_metadata_logic.cairo b/tests/protostar/loot/metadata/test_metadata_logic.cairo old mode 100644 new mode 100755 index 01a28c2e..bbf04f27 --- a/tests/protostar/loot/metadata/test_metadata_logic.cairo +++ b/tests/protostar/loot/metadata/test_metadata_logic.cairo @@ -28,46 +28,19 @@ func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( context.lords = ids.addresses.lords stop_prank_realms = start_prank(ids.addresses.account_1, ids.addresses.realms) stop_prank_adventurer = start_prank(ids.addresses.account_1, ids.addresses.adventurer) - stop_prank_loot = start_prank(ids.addresses.account_1, ids.addresses.loot) + stop_prank_loot = start_prank(ids.addresses.adventurer, ids.addresses.loot) stop_prank_lords = start_prank(ids.addresses.account_1, ids.addresses.lords) %} IRealms.set_realm_data(addresses.realms, Uint256(10, 0), 'Test Realm', 1); - ILords.approve(addresses.lords, addresses.adventurer, Uint256(10000, 0)); - - // Store item ids and equip to adventurer - - let (timestamp) = get_block_timestamp(); + ILords.approve(addresses.lords, addresses.adventurer, Uint256(100000000000000000000, 0)); %{ - stop_mock = mock_call(1, 'next', [1]) - %} - // Mint 8 tokens - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - ILoot.mint(addresses.loot, addresses.account_1); - %{ - stop_mock() stop_prank_lords() stop_prank_lords = start_prank(ids.addresses.adventurer, ids.addresses.lords) %} - // Set tokens to ids above for testing - ILoot.setItemById(addresses.loot, Uint256(1,0), ItemIds.Wand, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(2,0), ItemIds.DivineRobe, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(3,0), ItemIds.LinenHood, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(4,0), ItemIds.SilkSash, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(5,0), ItemIds.DivineSlippers, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(6,0), ItemIds.WoolGloves, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(7,0), ItemIds.Amulet, 20, 0, 0, 0); - ILoot.setItemById(addresses.loot, Uint256(8,0), ItemIds.PlatinumRing, 20, 0, 0, 0); - // Mint adventurer with random params IAdventurer.mint( addresses.adventurer, @@ -80,6 +53,41 @@ func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 'o6guw2FxsiPEyvfRFnUJWzZ' ); + + // Store item ids and equip to adventurer + + let (timestamp) = get_block_timestamp(); + + %{ + stop_mock = mock_call(1, 'next', [1]) + %} + // Mint 8 tokens + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + ILoot.mint(addresses.loot, addresses.account_1, Uint256(1,0)); + %{ + stop_mock() + stop_prank_lords() + stop_prank_loot() + stop_prank_lords = start_prank(ids.addresses.adventurer, ids.addresses.lords) + stop_prank_loot = start_prank(ids.addresses.account_1, ids.addresses.loot) + %} + + // Set tokens to ids above for testing + ILoot.set_item_by_id(addresses.loot, Uint256(1,0), ItemIds.Wand, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(2,0), ItemIds.DivineRobe, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(3,0), ItemIds.LinenHood, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(4,0), ItemIds.SilkSash, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(5,0), ItemIds.DivineSlippers, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(6,0), ItemIds.WoolGloves, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(7,0), ItemIds.Amulet, 20, 0, 0, 0); + ILoot.set_item_by_id(addresses.loot, Uint256(8,0), ItemIds.PlatinumRing, 20, 0, 0, 0); + %{ stop_prank_loot() %} diff --git a/tests/protostar/loot/setup/interfaces.cairo b/tests/protostar/loot/setup/interfaces.cairo old mode 100644 new mode 100755 index b0fc2e2e..929539c3 --- a/tests/protostar/loot/setup/interfaces.cairo +++ b/tests/protostar/loot/setup/interfaces.cairo @@ -4,7 +4,7 @@ from starkware.cairo.common.uint256 import Uint256 from contracts.loot.constants.adventurer import AdventurerState, PackedAdventurerState from contracts.loot.constants.beast import Beast, BeastStatic, BeastDynamic -from contracts.loot.constants.item import Item +from contracts.loot.constants.item import Item, Bid @contract_interface namespace IController { @@ -18,7 +18,6 @@ namespace IController { } func set_xoroshiro(xoroshiro: felt) { } - } @contract_interface @@ -31,51 +30,60 @@ namespace IRealms { @contract_interface namespace ILoot { - func initializer( - name: felt, - symbol: felt, - proxy_admin: felt, - controller_address: felt - ) { + func initializer(name: felt, symbol: felt, proxy_admin: felt, controller_address: felt) { } - func mint(to: felt) { + func mint(to: felt, adventurer_token_id: Uint256) { } - func updateAdventurer(tokenId: Uint256, adventurerId: felt) { + func mint_starter_weapon(to: felt, weapon_id: felt, adventuer_token_id: Uint256) { } - func setItemById( - tokenId: Uint256, - item_id: felt, - greatness: felt, - xp: felt, - adventurer: felt, - bag_id: felt + func update_adventurer(tokenId: Uint256, adventurerId: felt) { + } + func set_item_by_id( + tokenId: Uint256, item_id: felt, greatness: felt, xp: felt, adventurer: felt, bag_id: felt ) { } - func getItemByTokenId(tokenId: Uint256) -> (item: Item) { + func get_item_by_token_id(tokenId: Uint256) -> (item: Item) { } func tokenURI(tokenId: Uint256) -> (tokenURI_len: felt, tokenURI: felt*) { } + func mint_daily_items() { + } + func bid_on_item(market_item_id: Uint256, adventurer_token_id: Uint256, price: felt) { + } + func claim_item(market_item_id: Uint256, adventurer_token_id: Uint256) { + } + func item_owner(tokenId: Uint256, adventurer_token_id: Uint256) -> (owner: felt) { + } + func view_bid(market_item_id: Uint256) -> (bid: Bid) { + } } @contract_interface namespace IAdventurer { - func initializer( - name: felt, - symbol: felt, - proxy_admin: felt, - address_of_controller: felt, - ) { + func initializer(name: felt, symbol: felt, proxy_admin: felt, address_of_controller: felt) { } func mint( - to: felt, - race: felt, - home_realm: felt, - name: felt, - order: felt, - image_hash_1: felt, - image_hash_2: felt - ) { + to: felt, + race: felt, + home_realm: felt, + name: felt, + order: felt, + image_hash_1: felt, + image_hash_2: felt, + ) -> (adventurer_token_id: Uint256) { + } + func mint_with_starting_weapon( + to: felt, + race: felt, + home_realm: felt, + name: felt, + order: felt, + image_hash_1: felt, + image_hash_2: felt, + weapon_id: felt, + ) -> (adventurer_token_id: Uint256, item_token_id: Uint256) { } + func equip_item(tokenId: Uint256, itemTokenId: Uint256) -> (success: felt) { } func unequip_item(tokenId: Uint256, itemTokenId: Uint256) -> (success: felt) { @@ -84,12 +92,20 @@ namespace IAdventurer { } func increase_xp(tokenId: Uint256, amount: felt) -> (success: felt) { } - func explore(token_id: Uint256) -> (success: felt) { + func explore(token_id: Uint256) -> (type: felt, id: felt) { } func tokenURI(tokenId: Uint256) -> (tokenURI_len: felt, tokenURI: felt*) { } func get_adventurer_by_id(tokenId: Uint256) -> (adventurer: AdventurerState) { } + func purchase_health(tokenId: Uint256, number: felt) -> (success: felt) { + } + func upgrade_stat(adventurer_token_id: Uint256, stat: felt) -> (success: felt) { + } + func become_king(adventurer_token_id: Uint256) -> (success: felt) { + } + func pay_king_tribute() -> (success: felt) { + } } @contract_interface @@ -114,23 +130,22 @@ namespace IBeast { } func get_adventurer_from_beast(beast_token_id: Uint256) -> () { } + func balance_of(adventurer_token_id: Uint256) -> (res: felt) { + } + func add_to_balance(adventurer_token_id: Uint256, addition: felt) { + } } @contract_interface namespace ILords { - func initializer( - name: felt, - symbol: felt, - decimals: felt, - initial_supply: Uint256, - recipient: felt, - proxy_admin: felt, - ) { - } func balanceOf(owner: felt) -> (balance: Uint256) { } func approve(spender: felt, amount: Uint256) -> (success: felt) { } func allowance(owner: felt, spender: felt) -> (allowance: Uint256) { } -} \ No newline at end of file + func mint(to: felt, amount: Uint256) { + } + func grant_role(role: felt, to: felt) { + } +} diff --git a/tests/protostar/loot/setup/setup.cairo b/tests/protostar/loot/setup/setup.cairo old mode 100644 new mode 100755 index 416e4395..67a8b7fa --- a/tests/protostar/loot/setup/setup.cairo +++ b/tests/protostar/loot/setup/setup.cairo @@ -95,7 +95,7 @@ func deploy_all{ ids.contracts.beast = deploy_contract("./contracts/settling_game/proxy/PROXY_LOGIC.cairo", [declared.class_hash] ).contract_address - declared = declare("./contracts/loot/loot/Loot.cairo") + declared = declare("./contracts/loot/loot/LootMarketArcade.cairo") ids.contracts.loot = deploy_contract("./contracts/settling_game/proxy/PROXY_LOGIC.cairo", [declared.class_hash] ).contract_address @@ -103,11 +103,11 @@ func deploy_all{ ids.contracts.realms = deploy_contract("./contracts/settling_game/proxy/PROXY_LOGIC.cairo", [declared.class_hash] ).contract_address - declared = declare("./contracts/settling_game/tokens/Lords_ERC20_Mintable.cairo") - ids.contracts.lords = deploy_contract("./contracts/settling_game/proxy/PROXY_LOGIC.cairo", - [declared.class_hash] + ids.contracts.lords = deploy_contract("./contracts/settling_game/tokens/Lords_ERC20_Mintable.cairo", + [1, 1, 18, ids.contracts.account_1] ).contract_address stop_prank_controller = start_prank(ids.contracts.account_1, ids.contracts.controller) + stop_prank_lords = start_prank(ids.contracts.account_1, ids.contracts.lords) %} IController.initializer(contracts.controller, contracts.account_1, contracts.account_1); IController.set_xoroshiro(contracts.controller, contracts.xoroshiro); @@ -126,14 +126,17 @@ func deploy_all{ ILoot.initializer(contracts.loot, 1, 1, contracts.controller, contracts.account_1); IController.set_address_for_module_id(contracts.controller, ModuleIds.Loot, contracts.loot); IController.set_write_access(contracts.controller, ModuleIds.Loot, ModuleIds.Adventurer); + IController.set_write_access(contracts.controller, ModuleIds.Loot, ModuleIds.Beast); IRealms.initializer(contracts.realms, 1, 1, contracts.account_1); - ILords.initializer(contracts.lords, 1, 1, 18, Uint256(100000000000000000000, 0), contracts.account_1, contracts.account_1); + ILords.grant_role(contracts.lords, 1835626100, contracts.account_1); + ILords.mint(contracts.lords, contracts.account_1, Uint256(200000000000000000000, 0)); IController.set_address_for_external_contract(contracts.controller, ExternalContractIds.Realms, contracts.realms); IController.set_address_for_external_contract(contracts.controller, ExternalContractIds.Lords, contracts.lords); %{ stop_prank_controller() + stop_prank_lords() %} return contracts; diff --git a/tests/protostar/loot/stats/test_combat.cairo b/tests/protostar/loot/stats/test_combat.cairo old mode 100644 new mode 100755 index e82f56aa..bb534f45 --- a/tests/protostar/loot/stats/test_combat.cairo +++ b/tests/protostar/loot/stats/test_combat.cairo @@ -11,7 +11,7 @@ from contracts.loot.constants.combat import WeaponEfficacy from contracts.loot.constants.beast import Beast, BeastAttackType, BeastIds from contracts.loot.constants.obstacle import Obstacle, ObstacleConstants from contracts.loot.loot.stats.combat import CombatStats -from tests.protostar.loot.test_structs import TestUtils +from tests.protostar.loot.test_structs import get_adventurer_state, TestUtils @external func test_weapon_vs_armor_efficacy{syscall_ptr: felt*, range_check_ptr}() { @@ -118,11 +118,13 @@ func test_weapon_vs_armor_efficacy{syscall_ptr: felt*, range_check_ptr}() { func test_calculate_damage_from_weapon{syscall_ptr: felt*, range_check_ptr}() { alloc_locals; + let (adventurer_state) = get_adventurer_state(); + // greatness 20 katana vs greatness 0 shirt // max damage - gg let (g20_katana) = TestUtils.create_item(ItemIds.Katana, 20); let (g0_shirt) = TestUtils.create_item(ItemIds.Shirt, 0); - let (katana_vs_shirt) = CombatStats.calculate_damage_from_weapon(g20_katana, g0_shirt); + let (katana_vs_shirt) = CombatStats.calculate_damage_from_weapon(g20_katana, g0_shirt, adventurer_state, 1); assert katana_vs_shirt = 300; // greatness 3 short sword vs greatness 18 holy chestplate @@ -130,7 +132,7 @@ func test_calculate_damage_from_weapon{syscall_ptr: felt*, range_check_ptr}() { let (g3_short_sword) = TestUtils.create_item(ItemIds.ShortSword, 3); let (g18_holy_chestplate) = TestUtils.create_item(ItemIds.HolyChestplate, 18); let (holy_chestplate_vs_short_sword) = CombatStats.calculate_damage_from_weapon( - g3_short_sword, g18_holy_chestplate + g3_short_sword, g18_holy_chestplate, adventurer_state, 1 ); assert holy_chestplate_vs_short_sword = 0; @@ -143,17 +145,19 @@ func test_calculate_damage_from_beast{ }() { alloc_locals; + let (adventurer_state) = get_adventurer_state(); + // greatness 20 orc vs greatness 0 shirt (oof) let (orc) = TestUtils.create_beast(BeastIds.Orc, 20); let (shirt) = TestUtils.create_item(ItemIds.Shirt, 0); - let (orc_vs_shirt) = CombatStats.calculate_damage_from_beast(orc, shirt); + let (orc_vs_shirt) = CombatStats.calculate_damage_from_beast(orc, shirt, 1); assert orc_vs_shirt = 60; // greatness 10 giant vs greatness 10 leather armor let (leather) = TestUtils.create_item(ItemIds.LeatherArmor, 10); let (giant) = TestUtils.create_beast(BeastIds.Giant, 10); - let (giant_vs_leather) = CombatStats.calculate_damage_from_beast(orc, leather); - assert giant_vs_leather = 170; + let (giant_vs_leather) = CombatStats.calculate_damage_from_beast(giant, leather, 1); + assert giant_vs_leather = 120; return (); } @@ -164,6 +168,8 @@ func test_calculate_damage_from_obstacle{ }() { alloc_locals; + let (adventurer_state) = get_adventurer_state(); + // greatness 0 ring mail vs greatness 20 demonic alter // max damage - gg let (g0_ring_mail) = TestUtils.create_item(ItemIds.RingMail, 0); @@ -182,6 +188,13 @@ func test_calculate_damage_from_obstacle{ ); assert demonhusk_vs_dark_mist = 0; + let zero_item = Item(0,0,0,0,0,0,0,0,0,0,0,0,0); + let (g0_curse) = TestUtils.create_obstacle(ObstacleConstants.ObstacleIds.Curse, 1); + let (zero_vs_curse) = CombatStats.calculate_damage_from_obstacle( + g0_curse, zero_item + ); + assert zero_vs_curse = 12; + return (); } diff --git a/tests/protostar/loot/stats/test_item.cairo b/tests/protostar/loot/stats/test_item.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/loot/test_obstacle.cairo b/tests/protostar/loot/test_obstacle.cairo old mode 100644 new mode 100755 index 2e8e0653..4573abba --- a/tests/protostar/loot/test_obstacle.cairo +++ b/tests/protostar/loot/test_obstacle.cairo @@ -36,4 +36,6 @@ func test_obstacle_type{ assert hidden_arrows_type = ObstacleConstants.ObstacleType.HiddenArrow; return (); -} \ No newline at end of file +} + +// TODO: test obstacle id being generated is as expected, test for adventurer level 1, 2, 3 \ No newline at end of file diff --git a/tests/protostar/loot/test_structs.cairo b/tests/protostar/loot/test_structs.cairo old mode 100644 new mode 100755 index ba950768..6f06cc5e --- a/tests/protostar/loot/test_structs.cairo +++ b/tests/protostar/loot/test_structs.cairo @@ -31,20 +31,20 @@ namespace TestAdventurerState { // evolving stats const Health = 100; // - const Level = 500; // + const Level = 1; // // Physical - const Strength = 1000; - const Dexterity = 1000; - const Vitality = 1000; + const Strength = 0; + const Dexterity = 0; + const Vitality = 0; // Mental - const Intelligence = 1000; - const Wisdom = 1000; - const Charisma = 1000; + const Intelligence = 0; + const Wisdom = 0; + const Charisma = 0; // Meta Physical - const Luck = 1000; + const Luck = 0; const XP = 1000000; // @@ -62,6 +62,7 @@ namespace TestAdventurerState { // Packed Stats p3 const Status = AdventurerStatus.Idle; const Beast = 0; + const Upgrading = 0; } func get_adventurer_state{syscall_ptr: felt*, range_check_ptr}() -> ( @@ -96,6 +97,44 @@ func get_adventurer_state{syscall_ptr: felt*, range_check_ptr}() -> ( TestAdventurerState.RingId, TestAdventurerState.Status, TestAdventurerState.Beast, + TestAdventurerState.Upgrading, + ), + ); +} + +func create_adventurer{syscall_ptr: felt*, range_check_ptr}(level: felt) -> ( + adventurer_state: AdventurerState +) { + return ( + AdventurerState( + TestAdventurerState.Race, + TestAdventurerState.HomeRealm, + TestAdventurerState.Birthdate, + TestAdventurerState.Name, + TestAdventurerState.Order, + TestAdventurerState.ImageHash1, + TestAdventurerState.ImageHash2, + TestAdventurerState.Health, + level, + TestAdventurerState.Strength, + TestAdventurerState.Dexterity, + TestAdventurerState.Vitality, + TestAdventurerState.Intelligence, + TestAdventurerState.Wisdom, + TestAdventurerState.Charisma, + TestAdventurerState.Luck, + TestAdventurerState.XP, + TestAdventurerState.WeaponId, + TestAdventurerState.ChestId, + TestAdventurerState.HeadId, + TestAdventurerState.WaistId, + TestAdventurerState.FeetId, + TestAdventurerState.HandsId, + TestAdventurerState.NeckId, + TestAdventurerState.RingId, + TestAdventurerState.Status, + TestAdventurerState.Beast, + TestAdventurerState.Upgrading, ), ); } @@ -193,6 +232,7 @@ namespace TestUtils { let (type) = ObstacleUtils.get_type_from_id(obstacle_id); let (rank) = ObstacleUtils.get_rank_from_id(obstacle_id); + let (damage_location) = ObstacleUtils.get_damage_location_from_id(obstacle_id); let prefix_1 = 1; let prefix_2 = 1; @@ -204,6 +244,7 @@ namespace TestUtils { prefix_1, prefix_2, greatness, + damage_location ), ); } diff --git a/tests/protostar/loot/utils/utils.py b/tests/protostar/loot/utils/utils.py new file mode 100644 index 00000000..f945beda --- /dev/null +++ b/tests/protostar/loot/utils/utils.py @@ -0,0 +1,60 @@ +from collections import namedtuple + +Adventurer = namedtuple( + 'Adventurer', + 'health level strength dexterity vitality intelligence wisdom charisma luck xp ' + 'weapon_id chest_id head_id waist_id feet_id hands_id neck_id ring_id status beast upgrading', +) + + +def build_adventurer( + health, level, strength, dexterity, vitality, intelligence, wisdom, charisma, luck, xp, + weapon_id, chest_id, head_id, waist_id, feet_id, hands_id, neck_id, ring_id, status, beast, upgrading + ) -> Adventurer: + + return Adventurer( + *[ + health, level, strength, dexterity, vitality, intelligence, wisdom, charisma, luck, xp, + weapon_id, chest_id, head_id, waist_id, feet_id, hands_id, neck_id, ring_id, status, beast, upgrading + ]) + +def build_adventurer_level(level) -> Adventurer: + + return Adventurer( + *[ + 100, level, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ]) + + +def pack_adventurer(adventurer: Adventurer): + packed_1 = ( + adventurer.health * 2**0 + + adventurer.level * 2**10 + + adventurer.strength * 2**20 + + adventurer.dexterity * 2**30 + + adventurer.vitality * 2**40 + + adventurer.intelligence * 2**50 + + adventurer.wisdom * 2**60 + + adventurer.charisma * 2**70 + + adventurer.luck * 2**80 + + adventurer.xp * 2**90 + ) + packed_2 = ( + adventurer.weapon_id * 2**0 + + adventurer.chest_id * 2**41 + + adventurer.head_id * 2**82 + + adventurer.waist_id * 2**123 + ) + packed_3 = ( + adventurer.feet_id * 2**0 + + adventurer.hands_id * 2**41 + + adventurer.neck_id * 2**82 + + adventurer.ring_id * 2**123 + ) + packed_4 = ( + adventurer.status * 2**0 + + adventurer.beast * 2**3 + + adventurer.upgrading * 2**44 + ) + return packed_1, packed_2, packed_3, packed_4 \ No newline at end of file diff --git a/tests/protostar/metadata/test_metadata.cairo b/tests/protostar/metadata/test_metadata.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/metadata/test_metadata_logic.cairo b/tests/protostar/metadata/test_metadata_logic.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/nft_marketplace/bibliotheca_marketplace.cairo b/tests/protostar/nft_marketplace/bibliotheca_marketplace.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/buildings/test_buildings.cairo b/tests/protostar/settling_game/buildings/test_buildings.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/calculator/test_calculator.cairo b/tests/protostar/settling_game/calculator/test_calculator.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/combat/test_combat_2.cairo b/tests/protostar/settling_game/combat/test_combat_2.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/combat/test_combat_logic.cairo b/tests/protostar/settling_game/combat/test_combat_logic.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/combat/test_library_combat.cairo b/tests/protostar/settling_game/combat/test_library_combat.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/combat/utils.py b/tests/protostar/settling_game/combat/utils.py old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/crypts/test_crypt_library.cairo b/tests/protostar/settling_game/crypts/test_crypt_library.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/crypts/test_crypt_run.cairo b/tests/protostar/settling_game/crypts/test_crypt_run.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/deployment/test_deployment.cairo b/tests/protostar/settling_game/deployment/test_deployment.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/food/test_food.cairo b/tests/protostar/settling_game/food/test_food.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/goblintown/test_goblintown.cairo b/tests/protostar/settling_game/goblintown/test_goblintown.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/labor/test_labor.cairo b/tests/protostar/settling_game/labor/test_labor.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/relics/test_relics_logic.cairo b/tests/protostar/settling_game/relics/test_relics_logic.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/resources/test_calculate_resources.cairo b/tests/protostar/settling_game/resources/test_calculate_resources.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/resources/test_resources_logic.cairo b/tests/protostar/settling_game/resources/test_resources_logic.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/test_structs.cairo b/tests/protostar/settling_game/test_structs.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/settling_game/travel/test_travel.cairo b/tests/protostar/settling_game/travel/test_travel.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/utils/utils.cairo b/tests/protostar/utils/utils.cairo old mode 100644 new mode 100755 diff --git a/tests/protostar/utils/utils.py b/tests/protostar/utils/utils.py old mode 100644 new mode 100755 diff --git a/tests/pytest/__init__.py b/tests/pytest/__init__.py old mode 100644 new mode 100755 diff --git a/tests/pytest/build_cache.py b/tests/pytest/build_cache.py old mode 100644 new mode 100755 diff --git a/tests/pytest/conftest.py b/tests/pytest/conftest.py old mode 100644 new mode 100755 diff --git a/tests/pytest/desiege/01_TowerDefence_test.py b/tests/pytest/desiege/01_TowerDefence_test.py old mode 100644 new mode 100755 diff --git a/tests/pytest/desiege/04_Elements_test.py b/tests/pytest/desiege/04_Elements_test.py old mode 100644 new mode 100755 diff --git a/tests/pytest/readme.md b/tests/pytest/readme.md old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/06_combat_test.py b/tests/pytest/settling_game/06_combat_test.py old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/L06_Combat_tests.cairo b/tests/pytest/settling_game/L06_Combat_tests.cairo old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/__init__.py b/tests/pytest/settling_game/__init__.py old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/game_structs.py b/tests/pytest/settling_game/game_structs.py old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/library_combat_tests.cairo b/tests/pytest/settling_game/library_combat_tests.cairo old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/utils/general_tests.cairo b/tests/pytest/settling_game/utils/general_tests.cairo old mode 100644 new mode 100755 diff --git a/tests/pytest/settling_game/utils/utils_tests.py b/tests/pytest/settling_game/utils/utils_tests.py old mode 100644 new mode 100755 diff --git a/tests/pytest/shared.py b/tests/pytest/shared.py old mode 100644 new mode 100755 diff --git a/tests/pytest/utils.py b/tests/pytest/utils.py old mode 100644 new mode 100755