From 70cb98e01224eb7703dae3dac71eff2f4a7abaf3 Mon Sep 17 00:00:00 2001
From: Loaf <90423308+ponderingdemocritus@users.noreply.github.com>
Date: Wed, 1 Mar 2023 17:03:13 +1100
Subject: [PATCH] Feat/adventurer Mart - WIP (#296)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* #295: Contracts for starting adventurers with basic weapon
* adventure mart work
* itemmart work with generative seed
* market work
* cli work, cleanup contracts
* work on Adventurers, readme
* readme
* chmod fix
* downgrade protostar version
* add ownership for nfts to adventurer
* cli work, minor tweaks
* feat: add upgrade stat and purchase health
- add upgrade and purchase health and parameters in adventurer dynamic data
- add functions to upgrade stat and purchase health
- add purchase param reset if adventurer explores
- NOTE: upgrade stat doesn't take into account multi-level
- begin tests
- add gui.py and begin writing gui tasks
* fix internal functions with beast, clean cli, add in world balance
* fixes, add purchase health test
* cli work
* cli work
* fixes
- fix purchase health and upgrade stat functions
- add working tests
- change to camel case
* fixes:
- change naming conventions from camelCase to snake_case (other than OZ funcs and events)
- fix `mint_with_starting_weapon`, no `adventurer_token_id` needed
— add checks for ids in `mint_starting_weapon`
- fix deploy script
— add feature in `wrapped_declare` to recognise file names for container and non-container
- changed python formatting (needs checking)
- fix adventurer tests
* readme
* fix tests for loot and beasts
- fix deployment script names
* fix metadata tests
* market fix
* cli updates
* add loot subcommand
* add starting weapon assertions
* fix market emit
* complete some todos
- overflow checks
- add adventurer level in `damage_from_beast` calc
- add adventurer owner as storage in Loot
- assert adventurer is owner in equip item
* all tests passing
- fix contract bugs
- remove unnecessary prank stops
* add beast health to ambush calc
* add randomness to gold drop
* fix test
* fix
* fixes, add gold discovery formula
* fix
* items can now increase in greatness (wip)
* fix ifs, all tests passing
* fix mint_starting bug
- add calc for health discovery
- add calc for xp discovery
- change lords deployment to non proxy
* cli work
* minor contract tweaks and cli work
* move over increase xp, all tests passing
* fix
* tweaks
* cli
* - add adventurer alive assertion in `bid_on_item`
- Begin market tests
* add market tests
* fix cli issue
* cli work
* Adds Gnome and Golem as bottom tier Beasts
* wip starting beast
* Beasts now attack different body parts
* work on starting beastS
* add .sh script for easy setup, cli work, fix beast bug where it did not unassign after killing it
* add level damage boost and critical hit boost
* add images
* fix, all tests passing
- fix beast level to be 1 in damage calc (to improve)
* add dynamic obstacle damage to armor locations
* fixed print_beast_img and reduced starter beast to 2hp
* Level adventurer up after defeating first beast
* removed hardcode variables
* fix beast
* slight bug in obstacle id
* make market fetch all available items
* added some beasts, fix market cli to print current available
* add adventurer packing utils
* obstacle_ id fix
* fix adventurer packing util
- swap warp for roll (block number over block timestamp)
* fixes
- remove unnecessary adventurer storage var
- fix obstacle test
- fix getting item id from equipped slot
- tidy damage calculations
- switch item and adventurer discovery type (else item never discovered)
- improve explore test cases
* fixes
- remove unnecessary adventurer storage var
- fix obstacle test
- fix getting item id from equipped slot
- tidy damage calculations
- switch item and adventurer discovery type (else item never discovered)
- improve explore test cases
- change beast rand to block number
- all tests passing
- block number causing severe issues in protostar
* Make obstacle levels dynamic
* Adjust test_discover_obstacle for dynamic obstacles
* loot arcade bug fix
* cli work, fix gautlet bug being assigned to the foot slot
* Makes Beast HP dynamic
* change combat calculation
- damage = (base_damage - armor_strength) * efficacy
- improve tests
- add test util to create adventurer with level
* fixes
- grant mint role in deploy script
- tweak attack print output
- fix purchase health cli command
* fix config
* - improve potion health logs
- calculate damages in cli
* add todos, item weight
* add gui complexity
* flesh out gui WIP
* continue gui
* fix logs, continue gui work
* modify flee input to adventurer ID, continue gui
* - fix some info in cli
- gui fetch adventurers on load, only allow selecting these
* add king tibute payment
- add become_king in adventurer
- add pay_king_tribute in adventurer
- add test
- fix config
- change pyproject to python 3.9
* add gui to pyproject
- improve gui
* clean
* add king cli commands and gui functions
* add king timer reset on payout
* improvements
- improve logging
- fix mint daily items guy
- add gold balance outputs to UI
- add update gold balance functions to ones that change it
* add health to gui
* gui work
- add loader on transactions
- add get king contract function, cli etc..
- add king and kings gold widgets
- add your gold dynamic text
- add get items on load
- add market item dropdown
- dynamically update adventurers list WIP
* fix your gold text color
* fix market items
* handling invoke outputs
- add get result from invoke
- add logs for obstacle results
- add logs for flee result
- add gui handlers
* continue gui
- add more loading text
- fix become king logic
- update king on become king
- add king reign time
- add dynamic king recognition
* add equipped items display
---------
Co-authored-by: loothero
Co-authored-by: starknetdev
---
.devcontainer/devcontainer.json | 7 +-
.eslintignore | 0
.eslintrc.js | 0
.gitattributes | 0
.../workflows/check-python-setup/action.yaml | 0
.github/workflows/docker.yaml | 0
.github/workflows/docker_test.yaml | 0
.github/workflows/lint.yml | 0
.github/workflows/protostar-test.yaml | 0
.github/workflows/pytest-test.yaml | 0
.github/workflows/static_analysis.yml | 0
.gitignore | 0
.gitmodules | 0
.prettierignore | 0
.setup.js | 0
.solhint.json | 0
.solhintignore | 0
Dockerfile | 2 +-
LICENSE | 0
README.md | 18 +-
SECURITY.md | 0
contracts/bridge/README.md | 0
contracts/bridge/lords_l1.sol | 0
contracts/bridge/lords_l2.cairo | 0
contracts/desiege/01_TowerDefence.cairo | 0
.../desiege/02_TowerDefenceStorage.cairo | 0
contracts/desiege/03_GridMovement.cairo | 0
contracts/desiege/04_Elements.cairo | 0
contracts/desiege/DesiegeArbiter.cairo | 0
.../desiege/DesiegeModuleController.cairo | 0
contracts/desiege/DivineEclipseElements.cairo | 0
contracts/desiege/desiege.jpg | Bin
.../desiege/game_utils/game_structs.cairo | 0
.../desiege/game_utils/grid_position.cairo | 0
.../game_utils/grid_position_test.cairo | 0
.../ERC1155/ERC1155_Mintable_Ownable.cairo | 0
.../desiege/tokens/ERC1155/ERC1155_base.cairo | 0
.../ERC1155/IERC1155_Mintable_Ownable.cairo | 0
.../desiege/tokens/ERC1155/structs.cairo | 0
contracts/desiege/utils/interfaces.cairo | 0
contracts/exchange/Exchange_ERC20_1155.cairo | 0
contracts/exchange/README.md | 0
contracts/exchange/library.cairo | 0
contracts/loot/ModuleController.cairo | 0
contracts/loot/adventurer/Adventurer.cairo | 567 +++++++++--
contracts/loot/adventurer/interface.cairo | 2 +-
contracts/loot/adventurer/library.cairo | 177 +++-
contracts/loot/adventurer/metadata.cairo | 24 +-
contracts/loot/beast/Beast.cairo | 430 +++++++-
contracts/loot/beast/interface.cairo | 11 +
contracts/loot/beast/library.cairo | 79 +-
contracts/loot/beast/stats/beast.cairo | 39 +-
contracts/loot/constants/adventurer.cairo | 24 +-
contracts/loot/constants/bag.cairo | 0
contracts/loot/constants/beast.cairo | 73 +-
contracts/loot/constants/combat.cairo | 0
contracts/loot/constants/item.cairo | 20 +-
contracts/loot/constants/obstacle.cairo | 97 +-
contracts/loot/constants/physics.cairo | 0
contracts/loot/constants/rankings.cairo | 0
contracts/loot/interfaces/imodules.cairo | 0
contracts/loot/loot/ILoot.cairo | 18 +-
contracts/loot/loot/Loot.cairo | 215 +++-
contracts/loot/loot/LootMarketArcade.cairo | 891 +++++++++++++++++
contracts/loot/loot/LootPhysics.cairo | 0
contracts/loot/loot/library.cairo | 104 +-
contracts/loot/loot/metadata.cairo | 0
contracts/loot/loot/stats/combat.cairo | 128 +--
contracts/loot/loot/stats/item.cairo | 0
contracts/loot/readme.md | 108 ++
contracts/loot/utils/constants.cairo | 6 +
contracts/loot/utils/general.cairo | 41 +
contracts/metadata/metadata.cairo | 0
.../bibliotheca_marketplace.cairo | 0
contracts/poaps/crowns/LisbonCrown.cairo | 0
contracts/poaps/crowns/metadata.cairo | 0
contracts/settling_game/Arbiter.cairo | 0
.../settling_game/ModuleController.cairo | 0
.../settling_game/interfaces/ICrypts.cairo | 0
.../settling_game/interfaces/IERC1155.cairo | 0
.../settling_game/interfaces/IMintable.cairo | 0
.../settling_game/interfaces/IRealms.cairo | 0
.../settling_game/interfaces/imodules.cairo | 0
.../settling_game/interfaces/ixoroshiro.cairo | 0
contracts/settling_game/library/IUtils.cairo | 0
.../library/library_module.cairo | 0
.../modules/buildings/Buildings.cairo | 0
.../modules/buildings/interface.cairo | 0
.../modules/buildings/library.cairo | 0
.../modules/calculator/Calculator.cairo | 0
.../modules/calculator/interface.cairo | 0
.../modules/calculator/library.cairo | 0
.../settling_game/modules/combat/Combat.cairo | 0
.../modules/combat/constants.cairo | 0
.../modules/combat/interface.cairo | 0
.../modules/combat/library.cairo | 0
.../modules/crypts/CryptRun.cairo | 0
.../modules/crypts/L07_Crypts.cairo | 0
.../modules/crypts/L08_Crypts_Resources.cairo | 0
.../modules/crypts/constants.cairo | 0
.../modules/crypts/interface.cairo | 0
.../modules/crypts/library.cairo | 0
.../settling_game/modules/example/Core.cairo | 0
.../modules/example/constants.cairo | 0
.../modules/example/interface.cairo | 0
.../modules/example/library.cairo | 0
.../settling_game/modules/food/Food.cairo | 0
.../modules/food/interface.cairo | 0
.../settling_game/modules/food/library.cairo | 0
.../modules/goblintown/GoblinTown.cairo | 0
.../modules/goblintown/interface.cairo | 0
.../modules/goblintown/library.cairo | 0
.../settling_game/modules/labor/Labor.cairo | 0
.../modules/labor/interface.cairo | 0
.../settling_game/modules/labor/library.cairo | 0
.../settling_game/modules/relics/Relics.cairo | 0
.../modules/relics/interface.cairo | 0
.../modules/relics/library.cairo | 0
.../modules/resources/Resources.cairo | 0
.../modules/resources/interface.cairo | 0
.../modules/resources/library.cairo | 0
.../modules/settling/Settling.cairo | 0
.../modules/settling/interface.cairo | 0
.../settling_game/modules/travel/Travel.cairo | 0
.../modules/travel/interface.cairo | 0
.../modules/travel/library.cairo | 0
.../settling_game/proxy/PROXY_Logic.cairo | 0
contracts/settling_game/proxy/library.cairo | 0
.../tokens/Crypts_ERC721_Mintable.cairo | 0
.../tokens/Lords_ERC20_Mintable.cairo | 0
.../tokens/Realms_ERC721_Mintable.cairo | 0
.../Resources_ERC1155_Mintable_Burnable.cairo | 0
.../tokens/S_Crypts_ERC721_Mintable.cairo | 0
.../tokens/S_Realms_ERC721_Mintable.cairo | 0
.../unused_modules/L06_Combat.cairo | 0
.../unused_modules/library_combat.cairo | 0
contracts/settling_game/utils/constants.cairo | 0
.../settling_game/utils/game_structs.cairo | 0
contracts/settling_game/utils/general.cairo | 0
contracts/settling_game/utils/pow2.cairo | 0
contracts/solidity/loot/DistillLoot.sol | 0
contracts/solidity/loot/ILoot.sol | 0
contracts/solidity/pre/Bridge.sol | 0
contracts/solidity/pre/Journey.sol | 0
contracts/solidity/pre/Vesting.sol | 0
.../solidity/shared/interfaces/ERC165.sol | 0
.../solidity/shared/interfaces/IERC1155.sol | 0
.../shared/interfaces/IERC1155Meta.sol | 0
.../shared/interfaces/IERC1155Metadata.sol | 0
.../interfaces/IERC1155TokenReceiver.sol | 0
.../solidity/shared/interfaces/IERC165.sol | 0
.../solidity/shared/interfaces/IERC173.sol | 0
.../solidity/shared/interfaces/IERC20.sol | 0
contracts/solidity/shared/utils/Address.sol | 0
contracts/solidity/shared/utils/ERC165.sol | 0
contracts/solidity/shared/utils/LibBytes.sol | 0
contracts/solidity/shared/utils/LibEIP712.sol | 0
contracts/solidity/shared/utils/Ownable.sol | 0
contracts/solidity/shared/utils/SafeMath.sol | 0
.../shared/utils/SignatureValidator.sol | 0
contracts/solidity/tokens/LootRealms.sol | 0
contracts/solidity/tokens/TheLordsToken.sol | 0
contracts/staking/README.md | 0
contracts/staking/SingleSidedStaking.cairo | 0
contracts/staking/Splitter.cairo | 0
contracts/staking/interfaces/ISplitter.cairo | 0
.../token/ERC1155_Mintable_Burnable.cairo | 0
contracts/token/constants.cairo | 0
.../token/interfaces/IERC1155_Receiver.cairo | 0
contracts/token/library.cairo | 0
contracts/utils/xoroshiro128_starstar.cairo | 0
contracts/yagi/erc4626/ERC4626.cairo | 0
.../yagi/erc4626/interfaces/IERC4626.cairo | 0
contracts/yagi/erc4626/library.cairo | 0
contracts/yagi/utils/fixedpointmathlib.cairo | 0
data/coords.json | 0
data/crypts.json | 0
data/crypts_affinities.json | 0
data/crypts_environments.json | 0
data/json_data.json | 0
data/orders.json | 0
data/realms.json | 0
data/realms_bit.json | 0
data/resources.json | 0
data/wonders.json | 0
lib/cairo_contracts | 2 +-
localhost.accounts.json | 1 +
node.json | 0
protostar.toml | 2 +-
pytest.ini | 0
realms_cli/.gitignore | 0
realms_cli/README.md | 0
realms_cli/amm/__init__.py | 0
realms_cli/amm/change_values.py | 0
realms_cli/amm/deploy.py | 0
realms_cli/amm/fees.py | 0
realms_cli/amm/readme.md | 0
realms_cli/deploy/__init__.py | 0
realms_cli/deploy/access.py | 0
realms_cli/deploy/contract_deployer.py | 0
realms_cli/deploy/deploy_game_contracts.py | 0
realms_cli/deploy/guild_contracts.py | 0
realms_cli/deploy/new_module_deployer.py | 0
realms_cli/deploy/set_coordinates.py | 0
realms_cli/deploy/set_costs.py | 0
realms_cli/deploy/set_realm_data.py | 0
realms_cli/deploy/update.py | 24 +-
realms_cli/loot/__init__.py | 0
realms_cli/loot/deploy.py | 236 ++---
realms_cli/nexus/deploy.py | 0
realms_cli/nexus/upgrade.py | 0
realms_cli/pyproject.toml | 31 +-
realms_cli/realms_cli/__init__.py | 0
realms_cli/realms_cli/admin/__init__.py | 0
realms_cli/realms_cli/admin/main.py | 0
realms_cli/realms_cli/binary_converter.py | 0
realms_cli/realms_cli/caller_invoker.py | 124 ++-
realms_cli/realms_cli/config.py | 287 ++++--
realms_cli/realms_cli/coordinates.py | 0
realms_cli/realms_cli/deployer.py | 2 +-
realms_cli/realms_cli/exchange/__init__.py | 0
realms_cli/realms_cli/exchange/admin.py | 0
realms_cli/realms_cli/exchange/trade.py | 0
realms_cli/realms_cli/game_structs.py | 0
realms_cli/realms_cli/loot/adventurer.py | 291 ++++--
realms_cli/realms_cli/loot/beast.py | 131 +--
realms_cli/realms_cli/loot/constants.py | 203 +++-
realms_cli/realms_cli/loot/getters.py | 171 ++++
realms_cli/realms_cli/loot/gui.py | 863 ++++++++++++++++
.../realms_cli/loot/images/beasts/1.png | Bin 0 -> 2174628 bytes
.../realms_cli/loot/images/beasts/12.png | Bin 0 -> 1615854 bytes
.../realms_cli/loot/images/beasts/6.png | Bin 0 -> 1731619 bytes
.../realms_cli/loot/images/beasts/9.png | Bin 0 -> 2116863 bytes
realms_cli/realms_cli/loot/images/player.png | Bin 0 -> 1279494 bytes
realms_cli/realms_cli/loot/ipfs.py | 0
realms_cli/realms_cli/loot/loot.py | 940 +++++++++++++++++-
realms_cli/realms_cli/nexus/admin.py | 0
realms_cli/realms_cli/player/__init__.py | 0
realms_cli/realms_cli/player/account.py | 0
realms_cli/realms_cli/player/buildings.py | 0
realms_cli/realms_cli/player/calculator.py | 0
realms_cli/realms_cli/player/combat.py | 0
realms_cli/realms_cli/player/crypts.py | 0
realms_cli/realms_cli/player/food.py | 0
realms_cli/realms_cli/player/guilds.py | 0
realms_cli/realms_cli/player/lords.py | 0
realms_cli/realms_cli/player/resources.py | 0
realms_cli/realms_cli/player/settle.py | 0
realms_cli/realms_cli/player/travel.py | 0
realms_cli/realms_cli/utils.py | 23 +-
requirements.txt | 0
scripts/generate_strings.py | 0
scripts/get_public_key_from_private_key.py | 28 +-
scripts/readme.md | 0
scripts/run_binary_converter.py | 0
scripts/set_all_realm_data.sh | 0
scripts/setup_cli_env.sh | 35 -
scripts/startup.sh | 47 +
static/Resource_Emporium.png | Bin
static/realmslogo.jpg | Bin
static/realmsxbibliotheca.jpg | Bin
tasks/deploy_account.ts | 0
tasks/desiege/README.md | 0
tasks/desiege/create_game.ts | 0
tasks/desiege/deploy_arbiter.ts | 0
.../desiege/deploy_divine_eclipse_storage.ts | 0
tasks/desiege/deploy_element_balancer.ts | 0
tasks/desiege/deploy_elements_token.ts | 0
tasks/desiege/deploy_module_controller.ts | 0
tasks/desiege/deploy_tower_defense.ts | 0
tasks/desiege/deploy_tower_defense_storage.ts | 0
tasks/desiege/setup_controller_modules.ts | 0
tasks/helpers/index.ts | 0
tasks/migrations/upgrade_01_20220215.ts | 0
tasks/migrations/upgrade_01_20220227.ts | 0
tasks/migrations/upgrade_01_20220301.ts | 0
tasks/migrations/upgrade_02_20220223.ts | 0
test.json | 363 +++++++
tests/__init__.py | 0
.../protostar/exchange/test_deployment.cairo | 0
tests/protostar/exchange/test_formulas.cairo | 0
.../loot/adventurer/test_adventurer.cairo | 71 +-
.../adventurer/test_adventurer_logic.cairo | 482 +++++++--
tests/protostar/loot/beast/test_beast.cairo | 104 +-
.../loot/beast/test_beast_logic.cairo | 202 ++--
tests/protostar/loot/loot/test_loot.cairo | 0
.../protostar/loot/loot/test_loot_logic.cairo | 238 ++++-
.../metadata/test_item_metadata_logic.cairo | 34 +-
.../loot/metadata/test_metadata_logic.cairo | 66 +-
tests/protostar/loot/setup/interfaces.cairo | 101 +-
tests/protostar/loot/setup/setup.cairo | 13 +-
tests/protostar/loot/stats/test_combat.cairo | 25 +-
tests/protostar/loot/stats/test_item.cairo | 0
tests/protostar/loot/test_obstacle.cairo | 4 +-
tests/protostar/loot/test_structs.cairo | 57 +-
tests/protostar/loot/utils/utils.py | 60 ++
tests/protostar/metadata/test_metadata.cairo | 0
.../metadata/test_metadata_logic.cairo | 0
.../bibliotheca_marketplace.cairo | 0
.../buildings/test_buildings.cairo | 0
.../calculator/test_calculator.cairo | 0
.../settling_game/combat/test_combat_2.cairo | 0
.../combat/test_combat_logic.cairo | 0
.../combat/test_library_combat.cairo | 0
tests/protostar/settling_game/combat/utils.py | 0
.../crypts/test_crypt_library.cairo | 0
.../settling_game/crypts/test_crypt_run.cairo | 0
.../deployment/test_deployment.cairo | 0
.../settling_game/food/test_food.cairo | 0
.../goblintown/test_goblintown.cairo | 0
.../settling_game/labor/test_labor.cairo | 0
.../relics/test_relics_logic.cairo | 0
.../resources/test_calculate_resources.cairo | 0
.../resources/test_resources_logic.cairo | 0
.../settling_game/test_structs.cairo | 0
.../settling_game/travel/test_travel.cairo | 0
tests/protostar/utils/utils.cairo | 0
tests/protostar/utils/utils.py | 0
tests/pytest/__init__.py | 0
tests/pytest/build_cache.py | 0
tests/pytest/conftest.py | 0
tests/pytest/desiege/01_TowerDefence_test.py | 0
tests/pytest/desiege/04_Elements_test.py | 0
tests/pytest/readme.md | 0
tests/pytest/settling_game/06_combat_test.py | 0
.../settling_game/L06_Combat_tests.cairo | 0
tests/pytest/settling_game/__init__.py | 0
tests/pytest/settling_game/game_structs.py | 0
.../settling_game/library_combat_tests.cairo | 0
.../settling_game/utils/general_tests.cairo | 0
.../pytest/settling_game/utils/utils_tests.py | 0
tests/pytest/shared.py | 0
tests/pytest/utils.py | 0
333 files changed, 7265 insertions(+), 1077 deletions(-)
mode change 100644 => 100755 .devcontainer/devcontainer.json
mode change 100644 => 100755 .eslintignore
mode change 100644 => 100755 .eslintrc.js
mode change 100644 => 100755 .gitattributes
mode change 100644 => 100755 .github/workflows/check-python-setup/action.yaml
mode change 100644 => 100755 .github/workflows/docker.yaml
mode change 100644 => 100755 .github/workflows/docker_test.yaml
mode change 100644 => 100755 .github/workflows/lint.yml
mode change 100644 => 100755 .github/workflows/protostar-test.yaml
mode change 100644 => 100755 .github/workflows/pytest-test.yaml
mode change 100644 => 100755 .github/workflows/static_analysis.yml
mode change 100644 => 100755 .gitignore
mode change 100644 => 100755 .gitmodules
mode change 100644 => 100755 .prettierignore
mode change 100644 => 100755 .setup.js
mode change 100644 => 100755 .solhint.json
mode change 100644 => 100755 .solhintignore
mode change 100644 => 100755 Dockerfile
mode change 100644 => 100755 LICENSE
mode change 100644 => 100755 README.md
mode change 100644 => 100755 SECURITY.md
mode change 100644 => 100755 contracts/bridge/README.md
mode change 100644 => 100755 contracts/bridge/lords_l1.sol
mode change 100644 => 100755 contracts/bridge/lords_l2.cairo
mode change 100644 => 100755 contracts/desiege/01_TowerDefence.cairo
mode change 100644 => 100755 contracts/desiege/02_TowerDefenceStorage.cairo
mode change 100644 => 100755 contracts/desiege/03_GridMovement.cairo
mode change 100644 => 100755 contracts/desiege/04_Elements.cairo
mode change 100644 => 100755 contracts/desiege/DesiegeArbiter.cairo
mode change 100644 => 100755 contracts/desiege/DesiegeModuleController.cairo
mode change 100644 => 100755 contracts/desiege/DivineEclipseElements.cairo
mode change 100644 => 100755 contracts/desiege/desiege.jpg
mode change 100644 => 100755 contracts/desiege/game_utils/game_structs.cairo
mode change 100644 => 100755 contracts/desiege/game_utils/grid_position.cairo
mode change 100644 => 100755 contracts/desiege/game_utils/grid_position_test.cairo
mode change 100644 => 100755 contracts/desiege/tokens/ERC1155/ERC1155_Mintable_Ownable.cairo
mode change 100644 => 100755 contracts/desiege/tokens/ERC1155/ERC1155_base.cairo
mode change 100644 => 100755 contracts/desiege/tokens/ERC1155/IERC1155_Mintable_Ownable.cairo
mode change 100644 => 100755 contracts/desiege/tokens/ERC1155/structs.cairo
mode change 100644 => 100755 contracts/desiege/utils/interfaces.cairo
mode change 100644 => 100755 contracts/exchange/Exchange_ERC20_1155.cairo
mode change 100644 => 100755 contracts/exchange/README.md
mode change 100644 => 100755 contracts/exchange/library.cairo
mode change 100644 => 100755 contracts/loot/ModuleController.cairo
mode change 100644 => 100755 contracts/loot/adventurer/Adventurer.cairo
mode change 100644 => 100755 contracts/loot/adventurer/interface.cairo
mode change 100644 => 100755 contracts/loot/adventurer/library.cairo
mode change 100644 => 100755 contracts/loot/adventurer/metadata.cairo
mode change 100644 => 100755 contracts/loot/beast/Beast.cairo
mode change 100644 => 100755 contracts/loot/beast/interface.cairo
mode change 100644 => 100755 contracts/loot/beast/library.cairo
mode change 100644 => 100755 contracts/loot/beast/stats/beast.cairo
mode change 100644 => 100755 contracts/loot/constants/adventurer.cairo
mode change 100644 => 100755 contracts/loot/constants/bag.cairo
mode change 100644 => 100755 contracts/loot/constants/beast.cairo
mode change 100644 => 100755 contracts/loot/constants/combat.cairo
mode change 100644 => 100755 contracts/loot/constants/item.cairo
mode change 100644 => 100755 contracts/loot/constants/obstacle.cairo
mode change 100644 => 100755 contracts/loot/constants/physics.cairo
mode change 100644 => 100755 contracts/loot/constants/rankings.cairo
mode change 100644 => 100755 contracts/loot/interfaces/imodules.cairo
mode change 100644 => 100755 contracts/loot/loot/ILoot.cairo
mode change 100644 => 100755 contracts/loot/loot/Loot.cairo
create mode 100755 contracts/loot/loot/LootMarketArcade.cairo
mode change 100644 => 100755 contracts/loot/loot/LootPhysics.cairo
mode change 100644 => 100755 contracts/loot/loot/library.cairo
mode change 100644 => 100755 contracts/loot/loot/metadata.cairo
mode change 100644 => 100755 contracts/loot/loot/stats/combat.cairo
mode change 100644 => 100755 contracts/loot/loot/stats/item.cairo
create mode 100755 contracts/loot/readme.md
mode change 100644 => 100755 contracts/loot/utils/constants.cairo
mode change 100644 => 100755 contracts/loot/utils/general.cairo
mode change 100644 => 100755 contracts/metadata/metadata.cairo
mode change 100644 => 100755 contracts/nft_marketplace/bibliotheca_marketplace.cairo
mode change 100644 => 100755 contracts/poaps/crowns/LisbonCrown.cairo
mode change 100644 => 100755 contracts/poaps/crowns/metadata.cairo
mode change 100644 => 100755 contracts/settling_game/Arbiter.cairo
mode change 100644 => 100755 contracts/settling_game/ModuleController.cairo
mode change 100644 => 100755 contracts/settling_game/interfaces/ICrypts.cairo
mode change 100644 => 100755 contracts/settling_game/interfaces/IERC1155.cairo
mode change 100644 => 100755 contracts/settling_game/interfaces/IMintable.cairo
mode change 100644 => 100755 contracts/settling_game/interfaces/IRealms.cairo
mode change 100644 => 100755 contracts/settling_game/interfaces/imodules.cairo
mode change 100644 => 100755 contracts/settling_game/interfaces/ixoroshiro.cairo
mode change 100644 => 100755 contracts/settling_game/library/IUtils.cairo
mode change 100644 => 100755 contracts/settling_game/library/library_module.cairo
mode change 100644 => 100755 contracts/settling_game/modules/buildings/Buildings.cairo
mode change 100644 => 100755 contracts/settling_game/modules/buildings/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/buildings/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/calculator/Calculator.cairo
mode change 100644 => 100755 contracts/settling_game/modules/calculator/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/calculator/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/combat/Combat.cairo
mode change 100644 => 100755 contracts/settling_game/modules/combat/constants.cairo
mode change 100644 => 100755 contracts/settling_game/modules/combat/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/combat/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/crypts/CryptRun.cairo
mode change 100644 => 100755 contracts/settling_game/modules/crypts/L07_Crypts.cairo
mode change 100644 => 100755 contracts/settling_game/modules/crypts/L08_Crypts_Resources.cairo
mode change 100644 => 100755 contracts/settling_game/modules/crypts/constants.cairo
mode change 100644 => 100755 contracts/settling_game/modules/crypts/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/crypts/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/example/Core.cairo
mode change 100644 => 100755 contracts/settling_game/modules/example/constants.cairo
mode change 100644 => 100755 contracts/settling_game/modules/example/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/example/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/food/Food.cairo
mode change 100644 => 100755 contracts/settling_game/modules/food/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/food/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/goblintown/GoblinTown.cairo
mode change 100644 => 100755 contracts/settling_game/modules/goblintown/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/goblintown/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/labor/Labor.cairo
mode change 100644 => 100755 contracts/settling_game/modules/labor/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/labor/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/relics/Relics.cairo
mode change 100644 => 100755 contracts/settling_game/modules/relics/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/relics/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/resources/Resources.cairo
mode change 100644 => 100755 contracts/settling_game/modules/resources/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/resources/library.cairo
mode change 100644 => 100755 contracts/settling_game/modules/settling/Settling.cairo
mode change 100644 => 100755 contracts/settling_game/modules/settling/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/travel/Travel.cairo
mode change 100644 => 100755 contracts/settling_game/modules/travel/interface.cairo
mode change 100644 => 100755 contracts/settling_game/modules/travel/library.cairo
mode change 100644 => 100755 contracts/settling_game/proxy/PROXY_Logic.cairo
mode change 100644 => 100755 contracts/settling_game/proxy/library.cairo
mode change 100644 => 100755 contracts/settling_game/tokens/Crypts_ERC721_Mintable.cairo
mode change 100644 => 100755 contracts/settling_game/tokens/Lords_ERC20_Mintable.cairo
mode change 100644 => 100755 contracts/settling_game/tokens/Realms_ERC721_Mintable.cairo
mode change 100644 => 100755 contracts/settling_game/tokens/Resources_ERC1155_Mintable_Burnable.cairo
mode change 100644 => 100755 contracts/settling_game/tokens/S_Crypts_ERC721_Mintable.cairo
mode change 100644 => 100755 contracts/settling_game/tokens/S_Realms_ERC721_Mintable.cairo
mode change 100644 => 100755 contracts/settling_game/unused_modules/L06_Combat.cairo
mode change 100644 => 100755 contracts/settling_game/unused_modules/library_combat.cairo
mode change 100644 => 100755 contracts/settling_game/utils/constants.cairo
mode change 100644 => 100755 contracts/settling_game/utils/game_structs.cairo
mode change 100644 => 100755 contracts/settling_game/utils/general.cairo
mode change 100644 => 100755 contracts/settling_game/utils/pow2.cairo
mode change 100644 => 100755 contracts/solidity/loot/DistillLoot.sol
mode change 100644 => 100755 contracts/solidity/loot/ILoot.sol
mode change 100644 => 100755 contracts/solidity/pre/Bridge.sol
mode change 100644 => 100755 contracts/solidity/pre/Journey.sol
mode change 100644 => 100755 contracts/solidity/pre/Vesting.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/ERC165.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC1155.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC1155Meta.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC1155Metadata.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC1155TokenReceiver.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC165.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC173.sol
mode change 100644 => 100755 contracts/solidity/shared/interfaces/IERC20.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/Address.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/ERC165.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/LibBytes.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/LibEIP712.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/Ownable.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/SafeMath.sol
mode change 100644 => 100755 contracts/solidity/shared/utils/SignatureValidator.sol
mode change 100644 => 100755 contracts/solidity/tokens/LootRealms.sol
mode change 100644 => 100755 contracts/solidity/tokens/TheLordsToken.sol
mode change 100644 => 100755 contracts/staking/README.md
mode change 100644 => 100755 contracts/staking/SingleSidedStaking.cairo
mode change 100644 => 100755 contracts/staking/Splitter.cairo
mode change 100644 => 100755 contracts/staking/interfaces/ISplitter.cairo
mode change 100644 => 100755 contracts/token/ERC1155_Mintable_Burnable.cairo
mode change 100644 => 100755 contracts/token/constants.cairo
mode change 100644 => 100755 contracts/token/interfaces/IERC1155_Receiver.cairo
mode change 100644 => 100755 contracts/token/library.cairo
mode change 100644 => 100755 contracts/utils/xoroshiro128_starstar.cairo
mode change 100644 => 100755 contracts/yagi/erc4626/ERC4626.cairo
mode change 100644 => 100755 contracts/yagi/erc4626/interfaces/IERC4626.cairo
mode change 100644 => 100755 contracts/yagi/erc4626/library.cairo
mode change 100644 => 100755 contracts/yagi/utils/fixedpointmathlib.cairo
mode change 100644 => 100755 data/coords.json
mode change 100644 => 100755 data/crypts.json
mode change 100644 => 100755 data/crypts_affinities.json
mode change 100644 => 100755 data/crypts_environments.json
mode change 100644 => 100755 data/json_data.json
mode change 100644 => 100755 data/orders.json
mode change 100644 => 100755 data/realms.json
mode change 100644 => 100755 data/realms_bit.json
mode change 100644 => 100755 data/resources.json
mode change 100644 => 100755 data/wonders.json
create mode 100644 localhost.accounts.json
mode change 100644 => 100755 node.json
mode change 100644 => 100755 protostar.toml
mode change 100644 => 100755 pytest.ini
mode change 100644 => 100755 realms_cli/.gitignore
mode change 100644 => 100755 realms_cli/README.md
mode change 100644 => 100755 realms_cli/amm/__init__.py
mode change 100644 => 100755 realms_cli/amm/change_values.py
mode change 100644 => 100755 realms_cli/amm/deploy.py
mode change 100644 => 100755 realms_cli/amm/fees.py
mode change 100644 => 100755 realms_cli/amm/readme.md
mode change 100644 => 100755 realms_cli/deploy/__init__.py
mode change 100644 => 100755 realms_cli/deploy/access.py
mode change 100644 => 100755 realms_cli/deploy/contract_deployer.py
mode change 100644 => 100755 realms_cli/deploy/deploy_game_contracts.py
mode change 100644 => 100755 realms_cli/deploy/guild_contracts.py
mode change 100644 => 100755 realms_cli/deploy/new_module_deployer.py
mode change 100644 => 100755 realms_cli/deploy/set_coordinates.py
mode change 100644 => 100755 realms_cli/deploy/set_costs.py
mode change 100644 => 100755 realms_cli/deploy/set_realm_data.py
mode change 100644 => 100755 realms_cli/deploy/update.py
mode change 100644 => 100755 realms_cli/loot/__init__.py
mode change 100644 => 100755 realms_cli/loot/deploy.py
mode change 100644 => 100755 realms_cli/nexus/deploy.py
mode change 100644 => 100755 realms_cli/nexus/upgrade.py
mode change 100644 => 100755 realms_cli/pyproject.toml
mode change 100644 => 100755 realms_cli/realms_cli/__init__.py
mode change 100644 => 100755 realms_cli/realms_cli/admin/__init__.py
mode change 100644 => 100755 realms_cli/realms_cli/admin/main.py
mode change 100644 => 100755 realms_cli/realms_cli/binary_converter.py
mode change 100644 => 100755 realms_cli/realms_cli/caller_invoker.py
mode change 100644 => 100755 realms_cli/realms_cli/config.py
mode change 100644 => 100755 realms_cli/realms_cli/coordinates.py
mode change 100644 => 100755 realms_cli/realms_cli/deployer.py
mode change 100644 => 100755 realms_cli/realms_cli/exchange/__init__.py
mode change 100644 => 100755 realms_cli/realms_cli/exchange/admin.py
mode change 100644 => 100755 realms_cli/realms_cli/exchange/trade.py
mode change 100644 => 100755 realms_cli/realms_cli/game_structs.py
mode change 100644 => 100755 realms_cli/realms_cli/loot/adventurer.py
mode change 100644 => 100755 realms_cli/realms_cli/loot/beast.py
mode change 100644 => 100755 realms_cli/realms_cli/loot/constants.py
create mode 100644 realms_cli/realms_cli/loot/getters.py
create mode 100644 realms_cli/realms_cli/loot/gui.py
create mode 100644 realms_cli/realms_cli/loot/images/beasts/1.png
create mode 100644 realms_cli/realms_cli/loot/images/beasts/12.png
create mode 100644 realms_cli/realms_cli/loot/images/beasts/6.png
create mode 100644 realms_cli/realms_cli/loot/images/beasts/9.png
create mode 100644 realms_cli/realms_cli/loot/images/player.png
create mode 100644 realms_cli/realms_cli/loot/ipfs.py
mode change 100644 => 100755 realms_cli/realms_cli/loot/loot.py
mode change 100644 => 100755 realms_cli/realms_cli/nexus/admin.py
mode change 100644 => 100755 realms_cli/realms_cli/player/__init__.py
mode change 100644 => 100755 realms_cli/realms_cli/player/account.py
mode change 100644 => 100755 realms_cli/realms_cli/player/buildings.py
mode change 100644 => 100755 realms_cli/realms_cli/player/calculator.py
mode change 100644 => 100755 realms_cli/realms_cli/player/combat.py
mode change 100644 => 100755 realms_cli/realms_cli/player/crypts.py
mode change 100644 => 100755 realms_cli/realms_cli/player/food.py
mode change 100644 => 100755 realms_cli/realms_cli/player/guilds.py
mode change 100644 => 100755 realms_cli/realms_cli/player/lords.py
mode change 100644 => 100755 realms_cli/realms_cli/player/resources.py
mode change 100644 => 100755 realms_cli/realms_cli/player/settle.py
mode change 100644 => 100755 realms_cli/realms_cli/player/travel.py
mode change 100644 => 100755 realms_cli/realms_cli/utils.py
mode change 100644 => 100755 requirements.txt
mode change 100644 => 100755 scripts/generate_strings.py
mode change 100644 => 100755 scripts/get_public_key_from_private_key.py
mode change 100644 => 100755 scripts/readme.md
mode change 100644 => 100755 scripts/run_binary_converter.py
mode change 100644 => 100755 scripts/set_all_realm_data.sh
mode change 100644 => 100755 scripts/setup_cli_env.sh
create mode 100755 scripts/startup.sh
mode change 100644 => 100755 static/Resource_Emporium.png
mode change 100644 => 100755 static/realmslogo.jpg
mode change 100644 => 100755 static/realmsxbibliotheca.jpg
mode change 100644 => 100755 tasks/deploy_account.ts
mode change 100644 => 100755 tasks/desiege/README.md
mode change 100644 => 100755 tasks/desiege/create_game.ts
mode change 100644 => 100755 tasks/desiege/deploy_arbiter.ts
mode change 100644 => 100755 tasks/desiege/deploy_divine_eclipse_storage.ts
mode change 100644 => 100755 tasks/desiege/deploy_element_balancer.ts
mode change 100644 => 100755 tasks/desiege/deploy_elements_token.ts
mode change 100644 => 100755 tasks/desiege/deploy_module_controller.ts
mode change 100644 => 100755 tasks/desiege/deploy_tower_defense.ts
mode change 100644 => 100755 tasks/desiege/deploy_tower_defense_storage.ts
mode change 100644 => 100755 tasks/desiege/setup_controller_modules.ts
mode change 100644 => 100755 tasks/helpers/index.ts
mode change 100644 => 100755 tasks/migrations/upgrade_01_20220215.ts
mode change 100644 => 100755 tasks/migrations/upgrade_01_20220227.ts
mode change 100644 => 100755 tasks/migrations/upgrade_01_20220301.ts
mode change 100644 => 100755 tasks/migrations/upgrade_02_20220223.ts
create mode 100644 test.json
mode change 100644 => 100755 tests/__init__.py
mode change 100644 => 100755 tests/protostar/exchange/test_deployment.cairo
mode change 100644 => 100755 tests/protostar/exchange/test_formulas.cairo
mode change 100644 => 100755 tests/protostar/loot/adventurer/test_adventurer.cairo
mode change 100644 => 100755 tests/protostar/loot/adventurer/test_adventurer_logic.cairo
mode change 100644 => 100755 tests/protostar/loot/beast/test_beast.cairo
mode change 100644 => 100755 tests/protostar/loot/beast/test_beast_logic.cairo
mode change 100644 => 100755 tests/protostar/loot/loot/test_loot.cairo
mode change 100644 => 100755 tests/protostar/loot/loot/test_loot_logic.cairo
mode change 100644 => 100755 tests/protostar/loot/metadata/test_item_metadata_logic.cairo
mode change 100644 => 100755 tests/protostar/loot/metadata/test_metadata_logic.cairo
mode change 100644 => 100755 tests/protostar/loot/setup/interfaces.cairo
mode change 100644 => 100755 tests/protostar/loot/setup/setup.cairo
mode change 100644 => 100755 tests/protostar/loot/stats/test_combat.cairo
mode change 100644 => 100755 tests/protostar/loot/stats/test_item.cairo
mode change 100644 => 100755 tests/protostar/loot/test_obstacle.cairo
mode change 100644 => 100755 tests/protostar/loot/test_structs.cairo
create mode 100644 tests/protostar/loot/utils/utils.py
mode change 100644 => 100755 tests/protostar/metadata/test_metadata.cairo
mode change 100644 => 100755 tests/protostar/metadata/test_metadata_logic.cairo
mode change 100644 => 100755 tests/protostar/nft_marketplace/bibliotheca_marketplace.cairo
mode change 100644 => 100755 tests/protostar/settling_game/buildings/test_buildings.cairo
mode change 100644 => 100755 tests/protostar/settling_game/calculator/test_calculator.cairo
mode change 100644 => 100755 tests/protostar/settling_game/combat/test_combat_2.cairo
mode change 100644 => 100755 tests/protostar/settling_game/combat/test_combat_logic.cairo
mode change 100644 => 100755 tests/protostar/settling_game/combat/test_library_combat.cairo
mode change 100644 => 100755 tests/protostar/settling_game/combat/utils.py
mode change 100644 => 100755 tests/protostar/settling_game/crypts/test_crypt_library.cairo
mode change 100644 => 100755 tests/protostar/settling_game/crypts/test_crypt_run.cairo
mode change 100644 => 100755 tests/protostar/settling_game/deployment/test_deployment.cairo
mode change 100644 => 100755 tests/protostar/settling_game/food/test_food.cairo
mode change 100644 => 100755 tests/protostar/settling_game/goblintown/test_goblintown.cairo
mode change 100644 => 100755 tests/protostar/settling_game/labor/test_labor.cairo
mode change 100644 => 100755 tests/protostar/settling_game/relics/test_relics_logic.cairo
mode change 100644 => 100755 tests/protostar/settling_game/resources/test_calculate_resources.cairo
mode change 100644 => 100755 tests/protostar/settling_game/resources/test_resources_logic.cairo
mode change 100644 => 100755 tests/protostar/settling_game/test_structs.cairo
mode change 100644 => 100755 tests/protostar/settling_game/travel/test_travel.cairo
mode change 100644 => 100755 tests/protostar/utils/utils.cairo
mode change 100644 => 100755 tests/protostar/utils/utils.py
mode change 100644 => 100755 tests/pytest/__init__.py
mode change 100644 => 100755 tests/pytest/build_cache.py
mode change 100644 => 100755 tests/pytest/conftest.py
mode change 100644 => 100755 tests/pytest/desiege/01_TowerDefence_test.py
mode change 100644 => 100755 tests/pytest/desiege/04_Elements_test.py
mode change 100644 => 100755 tests/pytest/readme.md
mode change 100644 => 100755 tests/pytest/settling_game/06_combat_test.py
mode change 100644 => 100755 tests/pytest/settling_game/L06_Combat_tests.cairo
mode change 100644 => 100755 tests/pytest/settling_game/__init__.py
mode change 100644 => 100755 tests/pytest/settling_game/game_structs.py
mode change 100644 => 100755 tests/pytest/settling_game/library_combat_tests.cairo
mode change 100644 => 100755 tests/pytest/settling_game/utils/general_tests.cairo
mode change 100644 => 100755 tests/pytest/settling_game/utils/utils_tests.py
mode change 100644 => 100755 tests/pytest/shared.py
mode change 100644 => 100755 tests/pytest/utils.py
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 @@
-
# 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 0000000000000000000000000000000000000000..67d8611ea9b37697d2e5dd4d5b390deb1a74aa2e
GIT binary patch
literal 2174628
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¡
zk6tN6g`%9si8JDU#WPOPGaEHXT{ci>=qr!;1GnkNUdk|vi(c(VF*?P(5A{yxwC&Nx
zP`}W`KHnj%4Gk{!GVF!QI}nG`NC3O1xvf|Bn3Ex02Jrz+?S4~poz0;%JNGzZ>Hz-<
z;w=r(G%5%f^U-1nDX_ti?qD?WHRlgh|IYXfhAJ9}Mi63(tzzU&weVnwY<1yw_6u4;
zxE|EER*fs|`$p)Zuf)pMA5qV$iz%`3_$mGDV!OI%l&6Lw0I-XQBzriyAfiLvMONw(
z5K0iGR&*m$?qCD#O^6XFRJa`sK;aQ_Q)uC0RCKezA9sCw{`~!0w(w_t{PpYSed}+3
z{`oJTACalKd@8)-gW0-A>y1elwC@!vBQqa@>ekoS^S5uGUHapX-@dwjeBF25kGyzY
z4MpU|Xq7Oz>{ni7RNdEg4frsUk@F*&k$pc2WJGm0rb=p6Y*p1@rpT^4!+j_akqCCH
zqtSiEqv{v>gt@(wQp9yB61)_bCO5(Nnw1flIkE^bS5u|VwdiW3yhKit}|mqmPI#kt^r~ggtC=+dCrN9i1k%4=B$#cf{H8S
zx=aq>I(WgYoo>`!q#$2PWV6*hpS1SBjJf9ykh&P`CU9lsHrX6k1s57cP8!zqI2p6C
zXO>e?G?CthsvXsqzwY01mnA`sP~-^dI9a9%>Z|otb!%FlL_`vou7~TA;Q|wqX>{z8
z!BWHh1_@tCeCq}|#&fh}N(u&a3nsl$qh#a+N{l*(W9tHls1cuC1xWec+U^eIzIR{@1)SBu$z49~$2Ue{p@)B!7Bd__awKXz
zic?2o0M}etcI5E!OMF+4#z?tZgZ+&R9Gco;oR=9!+b7gRwo33-zwD+M-9;j69@KY7oFX(e3JBagV-I_@_i!h}|R
zKjd_3GYzku!~^ma(sb(chc0B8VkXDiclkYM+$LZ%ZBVnMxSVbj1m_{|>@gIrk-Ho1
z@buYIW(vENx_LOvM)`)7_KP-ie{+$dq>O8&ONk0m5xbU_7A9xolpk~g4czC0&e_B%4MCuHxUe%qti_d17_Z~wPU;G71{u6Q#P$ATX<
z=a>}j)N6x~&Uu^ss2wrqXkvytIM?g=e$4Uu#9xduHi^<3?G<5|PkDb`9>g-$rE8se
z)_2sX;Y4xjwlQt(K{DUVIp%fF;9O;UP`kJ{j_k(3l9TrdIDeK6%_)7G;{E$xLlT7G
zoNFtz6Q5b;1+x)12#g#20m7YEq)(VPz;dCtQMZ!=M=m-V0f1&*xZp$r!*0KYAau8R
zT|r>!)5Yl5#YPmV{K?6B&IAZ{1Q4N2YFW#0X^d-nGr;bJCsU1yL|#MjUJFW>U_2mbY2{D+VD>wW(~|NQy=_xvLm&N1G7j?t7YbxZ1w
z2q(}s5E<%1>%RM0io`{JKCb6o1xXzW=dQGMcVhE(MJT8LF=zKopKE6r*cy}}gxI}B
zEXI1l2>}Ux@Z1Q3=0%X8OCO+f;rtN5BaI8&_Df|_V3J&J{pUw{;ASq`PKp(U}+i%@>JDFj%Q_@;XV4(`}O5S5$BjHMyZ_ikg%P_
zU*k+T_O)nm(Y^uY2E&IwjJw>lZ*FPU8J>t>j&s>noE^VY;5liRkd)3R1mNxp_h$^>w>24WnxH&ex^maV26y6j
zgqvEd)wJuW?r?Uj06DaRjbg=8FXOeS-Iqx|yRdc&L?B9?Ck5Q&+8jJbA{IBUd!Jr7
zJy%6Lj1k-YU~+&O^ZJATCNqIJ{3OOEu5XxB;jvsX(uLFt%%vQJh;-tInJ`=jHzswf
zK8D{*P$0$o?4@v~xZ&3v!U2CsSGiqp+AU|(fdsqSL2A%Jte%aCPSAeGba~ngESz_(
z_;d%d(~Tf_e5*gGd+w3prkZGu)pQY?NSFY!Rqg?M^a-AW>@z!{bOHBZ@`Lpcf3Q(J
zH}~=E!udJ(Fw?6s5OD&LD-F08;ChXLl{1H~a9Bd|`X3Ey8EZJfVHfjB2N1vZ9roqs
z{np;`*qpbYy=CECe+-W=%ICEkXRUc=Qa=>{7@M1;z^Ktj-6_$mBT^CRLfkN!`;iqV@4tNl`u6Sd)+v
z^y>^a;NF8h+c+q90i?HDG#U|`or&=CwA)QW^|3qa;k@gdcw$VEw%LrNpp1^InQ=W7
z7nscn&AQp88z}kg1Sn<+%#6GOS@p#^6(cbFR0a0JptB$cMUBI}gaX{KJ^?Buc3?Aq
zH%ez~tC;=n)S8{6!wWTh5>q<7XNcYRX%XS1ob3u4ZuuQ_ClGfdF(HovYSkOdtgf;(
z=}AlpouE)meE=c1IMuNVKB+vROfky6))$w=wk3Zpl##f6(+0X#qJW~F)wlaXS;_*~
z9dWqvT(cZ#q9S5y53Iye?S}Kq*_;g2W^CG~{^|g_-Sm|rS}63>E$@0;Y>lT61|2%+
zDN1(!g>BJGE%GLHR+Tq_3p+elN$Pkr+v|L|wFCJA*j*wZ=O+iVA^H(hbhzSWAY
zES||(u%e0cddb#djws31x{#BC&VAtga<8{oy~<`{6gX}(nd2JIiyhEzQ^1An%RC0$
zJ76`AHU0oG7`Dzw5c=p;(bZ6MZWT6f0B
z3sk;_gpEut%=L~qQaWC<%}7Dc<7$;_p<2BSmEKzk;q1J{D)V0>9fh_WTmWa+7)cOt
zA`^F5JuH7k>ygVd9PcBQLJgqY5JY2IrVQNaX(@KNI)4?E<7a@)4mQU|0tPKbZ#yK`v#JKHwHGUn2#26L!Q>v=Nk
zUif)P(PU#{QU5^zcqzAfb0@DwUqfg1G|6kf0`xb+viNMqHNuD%yT8CYe)*dgKL2Xw
zG%tXcc>fQ-yX0go;fq!n{Kv}l^5-8m^7dKMlu}r}3%w6u_viVF77Akl_1nNktl`^d
zcyiXP0h2*aH5lmbh}06Dv5j^&dI|M>%^_CH*_K}Pl`Jc`dfvm;ia1#=XXXw!ct4U@
z#Dv)a#|-bh&Bo!tkgYoy3O!cT{cy0RcpTePfRvFTUF`9omORb8>DzjR$+sAz?dw;h
zj(BigkW{335k-^?ewfPadPMz>N=7gqH~ti#rd6(ssLG3hMxoR3Ota##Gn&9-MYxnR
zPIpHcn{KU-D6mMcAW1jTm@8=|NtOAyzwUy*Kkwf^KmO^H|MnUG+wa%^@!#vuANBS5
z@!R9Wna#7uEhn0(OQO3M_Vl_-f*b|5beEpb`n>p&@%zW)$ItKG$__XaBq8u}a*NOG@dHj``!)m?qR1x?uNos*Y@!oBGR&V^?Lo7s`q$46Wb
zMB++u>u9GH%-lY}b8_-hIfZh$J$mhl6(2C1iUNx--lmRAwSe^2^&8HX6ohU*9tYpg
z=WzggGDjHF=;-dQQr(+EKy`1v`i7*ed@WxdHgTPs#t$rVkaM9X$S_$nNi^-;1tmZAu>8
zl`eZ@RW|+a@>}t#Pns14OrC
zoRxMPY2ClA*yZ`dYbVU!H?3NafOLDdG1gq!!%am-xY5Sw+?jkLYp%ZE-}B?0bw`Re
zB2x`@z~A_gcU1KH>+u_0pY_YP-dzzElD|E0Ox66YQK@OkvW{zxc_78Is5?%Rtz|{d
znb%!b9gef)%O{uxJB4W-p4Wz}I~%!Su-I%B_jZ_)8yo_IDLHsKt0YlsR{_}RwYFB?
z!oOxScy9x4+*wpRoS?Zfc%Z5xyzJc>+4oI8)b~Od!nUkyj*6(&n7Ohh5v|(Q33Iu0
zO&XUi<=7htR=5|o%P&x;{U2(!FHJ$G7|CEX84U>4=pp#i6@}50=j<4qAK|KF2W15(X(zasn;ir?D7e!a)nZOt{^~oCyK^--
zUb{UO9qXv7ugo{E_}GVc1a3?ijNZPekTVmwxj0MzXVVz7OTbHR#@M|LDz8Sawdx+@
zk$#5(size;5|7sNmk7hY{F~VSj+OCR!;uF}BV9^
z-D7vZQ~h?JR<$wi9|Zz(xsfu5zD*_12no|_&MAYp@Kc@5&vf>8y321+;oKHnPglEg
zl7F$Cg2A{|Y-__Svd}lnN>E9~PT&KPs0&SYhQ;Ol0oIf%b_71q4>2afCxO)H)+bOE
zr`7eMMlVQJUDsUQ0D#O85-i98&Uav@l3m=3RIBXUXwXJlA5QtNm8QF*y?yg%ZX8{Eu
zL~vUE6G@jPV0s*3mX|Q(04N0-Y-EE4!P1!KZQW91;yj{&21_X6mfF{NQ;{*0V=M}s
zU+tn4jXPccId=yfUx4L@14yp}OfeByo)GMQ=QQ_@mroqys9>Ob!T+-$H4hQhP1(S5_`B-Ni-!LHK9Ywr0`2X@tTy}AsEcXa*jAAhg;Z79JNSPh9
z4JL?l`HrWi?v0R`D!mcr^+k*=z3#07bWWI`6kw~g1LI<;m)5_Z=PAMRUT@hz&@HDy
za4vo_e(k=UP}(Refl?HexmDCB+P(xtvqA)<%&QtCt4vxZtlsTVLr2%StO$R0tNvd_v4JGc3;`G6Lk%H}P
zh+<4nv=Hl6#t&v+j4V9ITyfz3Y&|a6vyFPC)xhvI~rkq=)NaTXl?=bLdu!@h0_YAHmvl5zCQgL
zoH{&Vg`qXVubh~Fuwvv|C%l=2w;$s9;@P#YpFBO0-q?Ws#NifrVcGq?8J)%jPqfDp
zFW*_$uXN>Qt$!Jt=hS7mHETLxrPq|cerfbwz`bafBFrh6Z8o=JJ8A2EUS98w{e^V+
z;%%N>$U$C*cL8tIe)^{^#hIV*0OAbvM($BCe~x
zekAkfv%h`I-+$wO=&%3$NB;Mp&+k8eetrJ@me*0rv==%;O0RyVXC#7BHRkrG(Rxd6
zc>np4zkmDq>)%U4i|O~0`gDZ}5M9k%cPLE@t#Di9I{i%cD4>Rkp}KjLj#cBqqkc@i
zZ$u>X*&R0c8<-O#t_%6V^_Xk{3qdN3iW+`e@zg&U{RzpC*4
zb&c-2;oATv9n{Wtt64Up;g7yzQkggjh+=LxGsAIMWec%EP`+W=H>^!+jaMed`%h1U
zHCZux#_PT$t)wS(OJDBDqiM0vEs!M`v6%&2SgCDh1aHpkRyXxj&%FW>yPkLvrJ2@A
zgK>}1Ta#|rrdMM)*Y`>S?$%AW1CI%GOBVQg>WY`ojg1n>053Me$$V6|n}5qUGOUbc
zh}={nESPbEk*b>dgnv6W;CmF~t91
z^OraL>OHl%aXrWpoYmvc8q1hAl`choql%#O=OF7P1UrRifvct
z>2NUJMttGfn1=h9!HE|NL=>K}8AO`oC=g1qP;T{r?e&|y~S7DaeE?Hqag*RNJg_ZACHV)BIUsx_#N9h&bcf{J)E6~H{d^r
z)YfQb6-!GwoM71%FerS>+GY{fm~ej28AbCJBOr}!TR%UJcQfF;O1~m>55a!=@aCB%
zvt}Mgw7+ovex{O(?X_0n-3IO#4=&gHDhw~+IhBpZ{Ie%>WsK3P+PoJfMy}l>#desVM9Y>#HY>Gd9w{JpOS3wWnqj{-}D!)QsShAr3b?$SDWyh
zSiS72$g%1Tj*PJLh8In;d6`hgut2P(4yHx9=@P*Z!`J#^Zql`tQtyDdQ2u6%!RDV;
zkBmeoTT(MHjp_OlEi4iJ1r$)gq*1C%2;eC;kkaR5x>$vduvVR{CYzaj(D{A$XX_`T
zLcX=>Gm#Mh@77EoW27fFoxZW>pw$*>A|7)-r*(Fc>0+CR56CGK&zKZ;I=36a4EB|U
z_;KIAH$T7SZ%_PR|MK`R|Ngv-Kfix}JRb4*usqR1^D
zv6WSGf+C2e6qKNgtAW^lTFr3?)gVTUr@G^Yt_ay90sX7GjLaAQZ{XshH!4jqyqy
zA>Nfi8QeQtbvtbY(da-WbRkkoTuB9SWu!pdAMVgiRNtEy)DNc&+3E&WhB2Jf|20zq
zR8>TF--r}h8rtX9TDS1k_zpe0o+c)(E0bN#55x9dO)%|SXhDz%4
z9v*$7C!Ww23!*PgRB-6BE^>{f8Bl98E=EaO!
zzsV~vkMi+}=d}3WaF!VqZ+PRk!xdv;M);CjnDQ(4*gjSjnNgj?QdV+YXkVtDr!akr}JH
zt~bbw*GMW!G(%M2u4f=KQm<$-;cF=emO1e+fh>GQP(67#PT;W~9uyGMWtU7}0Dk7)
zP$1Z?vy9NgNKpovj%NZZ-p_UrPi&1?NYQH2>FmXbP=M+#(6Qj8<)Ue;Fuq|bWzE+7
znsn(ImKbi%=x9$q9h{P50%EDa0vPTHpK&~qd5w3P5gIu3n+q~f%lGkcl#_H)1eVCF$%
zLy88)V{qlm*vx4h&^s9{o?A;TCsH>X7GuVU*Ga`2PRIN-+;m*q7-Z<>yzeqVE2z({WVKCeqjIlW|$8F89`8MW#1=czBIA#Sp)*?(6*2o`9ml2WejwlwTo=G@=Fv%
zXA0Ku?8dR7kDV6Go*J)qqR^Z{Hdf_b!)YO5GX9-`7U1SGNCxbyz+oEsM_{s_HF6(P
zT?Kq0|K1hJ2W&q`xMgKgom1G!3!#C8%S`6V;pnIl>1-gJJWwqvIum&VUE+m{Li7ba
z5I>88GVlSqIpAF#p@?fm!@0#23?iEfL`2-WAH1j()a~pQ%JLHD{EN}NT{g8lit1*z
z%J(+%`Mke>#pCny`ndkm`cJ<<{@ed}{`h)6pZ6m#x(ju)#@JGU(*2PiRhC*D7`g%Z
zN>&Q@U6l#4`kBe=isyZM^V>1G&LozAmii+f4pzvcb$A+WRhUDhT29TjBF|_wyMy_B
zI=N#-u805`LD#IZ0*|IR;wietctk$pdMGb$KPGf{-Kgqk5zh0K&>ItN0(IZc`e-$%
zz}0d)>X0DVI?9hqOtp;uayM=MpWxUsw+^}#Sh>k@L+`FOH<$HGROY79_6Nd
zx>~Tt1?+8@6Jv}-K6Q&;{MgMiqPsG3>4Hc)RY`LO2C5als7YP*>IDNW
z@0sak?=w7KIHtq@apyZ$cOW7Lh?LtE%f;Cu-E&N`zKAqGB*#K@`(kN_P;8FP)_jW%
zwn>EP5`-$0Q@Py
z+in4`Nt;vfhWE!xb1T+%_J^9jPvDO4?SuX?-Dr!m-uTVZFyDGKoh3XsI|)k)bUtU;
z8W)Z4xR3s$`QEW0u25XgHrvqZsilXtVO*>~ox-gU;RF*94FCT_HaV&{LQ*nXb@7V0
z_Nnb|*Ri*JWMs9z8(l!(3YTBLTtcMO{_{V7{@3sKfBEXa{`>cTeSFJgOQoBP3|2Q0kNkil
zGoF1nDqX4|7^__j1%I|agv^UwzkmC7fBo%e{Rmvw;~LebPag_p5Yf$>e7K)xI652G
zS3N)T@xwc?
zka*v!8&cPEfyQrbtb>&PERG6-~&?KeRnf_
zrCTP@iqzTrs)j?3UQNvc7LyaN_P_pGOhrtA6HOyk&lUL*ipH2)~Y^sQFia-#u*Hf`j~2hbPPubH&}+b!$9)R|r5!5*J6mcYyJi
zzHFR*8BKjre>T6#_q8^h6uK%Q*}>_-_l@~%e1Rnhb0;M*x&9Y28R35F1SH3oXJYyW
z;=`F8;3p9dA)ee<#azPeticG%{p4*2LQXysLP*DWM}2tP83rOPP*%P(uH^`B3d-ur
z>vF~aefQ_*=Wn0&&;9(@Z}DHh`e*l#KmYv80*#fSP1r{nD0YYwBn
zp7+OfHH2hlL>I6aJ&+`@(f_SCyISru?;t>_Gp~{wx9Z6%UynE^+65&5xVM9GGT0dr
zj)^cBDKPV*X@WZN!MvDP#fNwi%NgckdKV&VpJ9PXz&>yY9PN@;zk$cq)x9F%W@B
zMmQy9%-CSKaM`NKWYE2u=Y^+!)z`w!jmQMpE|ysTxQ4NV)5cR_p-?EHq*@zD1~vnT
zOeS0cJUlVzrY3_k8>%2LsnBFRf}a`RuJ{0=Mc7N(IP}Gw(m|cZiwml-i4z3D+qXK6
zXtq{(yVf`)pnS~Dxohl421EUbxX8z3#Q5x&1>8Z^M&>>I833J<;E^y>)w_@VHE?_vRF5X@J?ykK<7}NOm&6SK-ez`=w
zInMv3ADvJB#ii{m>}Hs+2#`7^Mx=vp{2X7wM~-C|vqyVUpf2fh8z$22jI4(5WX}CZ
zK6^wsuH-Z9#pJ>L6RLe77#(If9?831)9=hFD@Mi~KX*JEk0*0G$##2aCxV7>6HeG4
zgdO3mm1#9IfO~J1Jm`NNp8pc-swYu$AlHDV*kp}?4sNpBK*=2^=JuF6@kaR0Iyt}1
zopQ~iCCSBa=R+)JYl6~~$8XU6LN*G;LwRE}VJ8JHw+c80=w)aQvO9sZjrIZ2KqyqBrRnW4*iUjX7AYY)WvOZxO!u-aK!)-!e*=qy5T;%F
zbT^JkhkOllKUlzo<-B8@w)6`8%pc9)o!T-==ecqL+;k+)192Ar99^xtNQcVOwj8=c(K`!m1ni^-T`qU;qDRqkm0?@(*!CuQthZ%ISZ`5a}~B
zIvZfD9%Dy?m*MezEqVUMYixmsMk{>1D95`J)>*bYoN2YYlWlS+;SSuh`Ceu2BYkDW
z9uG;K2(dOF!^f)0)TG6{_TeplNB*tL5bhyC6^t7QU*L3N@}irvSs(ULrFK$dr7dJU
zW+@6Z4CgKOTqmB+WcUOFss@zJz7yHH*}?EdwGAjb<1u%vT4I^SUnMir-HUUX)!EkW
zCz_ZmLj$^kj`FytY@o`<(A0Pc6|G575zyJLCynlZG{`j~)fB!AE+|Md|-F;X2Qm7#EN-3X8K^WknNr{4^?m06PtHFVc8)4rGzo@hYT
z72Wx2umK7grZ@^_2J|dAuykO;GUfnd!t4qliATm~;xl+nXw6CuMTjBrsY-;p>`X`V
z@{4bR<*5Id7a3a+Y^dp!Jdr5i+592=1ph1*!}gj1rdzHMxRdc9Ln2Wx4~r3uBicHV
zB%n~Ys*0^BxnKmEx*!7=n5!_N{nKltR;4#6GF
zxf0kl?MEg}O5J9iNp2T!8>&e`d((j3X_Ya^LySp--4z8e%?TFfzQOgi#|{pVK5Gc6
z(ITSxj7}RG69_?On?w
zI2rR$6YbfLreS}zt>hvdC^uE`?p|7gm}CrZ;mHwikN6d{*ae!$O^<<+d}&Q#i9UC2
zL_lFjPEJwrL76t+n@#hEZ09XsQuDDg7;#}u$H9u{7hgoxDzblbGW+pT
z-@V`dq2=Uj>+SxY@4OOn=E(zA4^hHV7lu#TzrLrdy#0B%O~1g_wGjgLdX5dVtgCpP
zyo1*V#o)zEj;-13#I;U4*j<#@N8%rt9#>L%GuHdP_kFN$biza9kM(-)JaB$?JCb=B
z^EiUx3Ud~4E`2z3!!_&v(cVdZTf8%<2?vgp~1b1Q~
z=9Y48oyVT3rn|!NYtTn1m_Q1I%I(Hmm3+1`FhS35k~fsR!aaY$kRsii)Tps0qRusR
zZm`VIBxX+cN7t2&m_*HG$k4Ou$Jg`sZ{I#Y;y?WU@o&G?U%&e6>;C@z`{Uz7;pR_a
z5Cw)~4p-y_K2hGt)+PZmqUx^h`|f;P0P}iebXDOxO#}=IvHx#gVbahjfWf?50@^AG
z2`5`d)ZK!bx-z#v6#*im2xjteF)uKXS3Evj-AJ`?iIJVjxM22mtM6NCJns>2+w#{+
zJvNvU_a5R!EVKPN1|PKcZ;e)?VNHb+XPc6gi)>=4=loYlnW@E)Se0sSu+b|^@^}^N
zoP=|AyZU)exZaoVjthu^=Zv008LW+uZJ{vjvc{C_0zSy!lfQ*NbNzhN4Fz*f;CR+x
zwr*+k=^o@XMneZ{%}E@vXKS*Aku5x>FX8W1U#_H_Eed~BKuLTAA5%$PG(qGEw(7Kg
z5xcsZ@obg&Y?Un>X*}OeLIpk@H34n`46w(oyzu|nz=AzDB~%Z>1AWbp4NJq<9l)Yq
zA2;<ePq0~x4hY~8c%MUa4eIsw~%na(2~WqawOb)$i~LzlvY#be$8JT!|X;m
zka|LK|9}7R<(dBHpL{vamkfAz?LsN(<>dTzZnDPSa^X9b(VEVcL89^23*ZEOaXEZ4
zUfG^;@6>XWHo%CAC+sk|;=uAA9cKXj@m_lt0$TdnjcT@QOpQ@J^0lcG=yPKmQ~=uh
z3VrR3=(byeAl;ZtN4PEnV1)1yOjVKEYYMcmV!hP>;%=7}D|l@)gaZaJ*Y1!7bW2IV
z{-fWb1+Ec^k`iIJ-=M4x%HQg1Jon%%y!B{v2A(5Wdt7yq1qxkig54{L8|V5imkgZl
zt_vLvCPr3&Wk>@jR0MK9J@$n8%tITE7X|uW(h*nT)~Ewabh?junuP8*mDW%_Uif)_
zcaAn@k1&Q`b2@klPMSKT-IRasq_KHgA-88L2FqDBNJt%X6@VKH?0YkPI;Qo+#waN3
z0mEMWd`%b5F^YyhB7+a~Ez0_nuU>eAj#{u!f(TVVbF$jBD(@i5X&1T?D$Ty!Qm&b{
zO%dT9xIu^U+Q!E~?&+2USkB+2dzr5uGBBoSyuJ(+mtgyuz0mVO%<;?n3p+p@AU)s}
zZ}eqRtp7fakcZ6A^1REgJi_*Tb-v|X*Fzco)}v!Ay?;a1$Ij_Ib*#j&_g&myNzDI5
z1D3{aUEqG%JZbsH>jb{PcJ6Wv%i>nf&D}$4EmBS;r{8uj$vb>nYM{84ChbU07Z*PR}ViwSxN(bWc7b0hf-gjOwXAbL$_bbl-Qm
z&GO0S@~+P5so|7M94(L6mFgm=wAG)Ens%`{*PJ7h-5vRHyRtSP`T1MK)r@>R%7`v<
zTI$3VzWA*hci}E{tBYN}25*Go8C}oL@!Rz|LjorC$ad2$p2yf?%$-?UEb#S?wQGBO
zP(!|8t{K;rrVx!rF#YL!r`Q->8!#!HLJ-?R%!$&R0$rG{HKe*2R|;{Zm#5B>;ry~2!Z9Q0A{zFjzEB_!w;X->gb8_%_$wEqySWilD>eS
z=pX7IttXP06zV_+@IihsKLl5hq?t?KaK8@bB-ykNjRY0YO81UXjIlks(S+}T+r*=B
zBkX|b9;V0pFDylLn~q9lux|ltv<62M=U%Y2)B+a!YZDfzNdan4pf(YiF{^eQFAZuEDpq9lxQ>G!BX~&6ukL2h=$pUU
zzpu+*AhoD^b!hXvBh6!L&fHJ8yRV#%gxfUF8B3jki+px-^DPkP6=%9R*HFLIJ~Fny
z&F&Y=wRF5JDCKkNuTMI-5b~j@(lpNHyQSgD@2492^
zlXPYJs)Key-z=0HLj`;HZ<9M}&)$4WrL>^WLVR<2^Kew%=Ja!BAN9aL7Ei`2E0N8D#qdHideiIS3$$
znr<2l=I}I9*j7pE_Pt1Rgn16{Im|D0M59W-p#Pr0%?za`bh(ISks@%2ip^%&_P&~4
z9}Iu6`irTJh&ztFvp|6cv$
zzQ2F}@yFxAOgFJe?$@^K!(q;ju5kWYn{mJWjHt-y(f3xLBskqj0$?zmp0N4K@5;kDf#)cLuKt){NEmh?
zaL^#RVecjroV$G5y)MYmH0W$QcL-3c-K$Dlzx%SMIoT6I@&SG%FXH2hKnEG28{%H`
z4M`}<7cF;SzSqzTSH#}_x!@%jHH32~TV0J}JX=3+eRbbQS=}&j0!d!L1$PW(t8Uzd
z5zDq}WTZh+qT6r@?r*|rz-YHbu+fUBmTwuGPUx&Yx6TP893Ba5vi;=DKwnMkZno!*
zC4zCQ9=OI8y*#3YJgPM*Rpx;_QXsf#Un`Y?v5`w7NLx$J)hS1fG@lknPv7ys1b(k8
zwh!RR2-bn`5m$GUPRux93vagl%`Ki?x*Xt@4ZN^`uekA?tC#RYU@Icj&B!xBJc6&J
z2q8+9)3e1mpC6e|^fiU%eQf{WrC};_XkXDe2b7LowJTlO_)Oz+GaCo&g>n8%;
zox!*}CFhq3(x#<*Z@DQk=SpKss;Mza1EA>)p4V#{F&D#K#s*WofmD0DZdYFHo#a=<
zvpSd-b2M^}meg2jAm?tM*|WZ|VQts!Z_`m}9jm+APZN@mV<#9S>We1kG)QpUyp=1G
z;Q*JEt@70hjB9)iXb%)I*O(92GV_27OLS7hC|X7uf&xs>9_`w`tww%L3CQvU)HqcbdYHRthYB
zj%cT9BA8yX7)_1Sun$EbkkuUw$G<`(G6(y`4SkV+?K_j~{!E0ZF0pGm3-uNKkmjBZ
z;0cs`XL!#Wqq|!XS6tOob9Lj!GzdV8&+`81&np5-jw9_$?lfM%>+qoFl|+=&qZV(0)GqtHY4ah;wkC
zBBHBi>PU{4q56iVh0)6hxg41X1UQ@NWg=o)J|NPQ$GNr6aTSt4W-^jFh6z+T?@dW?
z3RhZ+rjv&l8z+!wZ(BY%^G6Ye8q@K!MR`kd?cPc
zLEK}wInf69^(L*ux}x3bPbw9ecIp9cb1`cQxTPEYglzu3l
zcuHqMg}It<*DWa>%UVG?Ty9Cwu>{WC5m2iZ7Oy|m7(goFrmFFh%8ux~+EbrXBpjCk
zqXAQ&(zClXeQ-?%#8(JoIM=AA2V1Qpe{)pFdcs`(u4{gqRm(;BL0L_lcm}J7Ji>
zxEN>nYoHIOn<}%Br3LAX04_!XkKD@{Fk=-Yb)!qQG*|14CMRnTCiet*-pA?jOx}5o
z(NLWNZ4t*gXCK8Ah_Gq`tf?Doz%e&Cc7MdvE!hRC%H7;VY6Np?Tel}N698Wt2
zPEa1V+(iLR)D^m@2lOrQE%*Uk?masj7+cF7Uis2ZGM!;Kyu%A&i)O&kTI$1XB#nu=
zw5aK^U{cn7k?cxLXp57#7mL4~Wi;&FmZ9`433BagTW~ykX8bQ4adI~Y0%+egc#fWY
zg-lHbg(pcMqNk$ma0$a2%k6V~b~igzVUe>B@-yTrlpX2pp}A#hf$PfxI1KwjsJ780
zlaHa~2Yc%}cuOjIX(d<;}po_eJXqm+!q3x%Y2zKUFUD@44!}yVh;NIC9HN
z{0r?jKcsi3NErWjSn9l83=lse1rA}{;K^&KJ`rnSf{aOu+)7_VMq&<6GLn(z@+SE$
zN!2Adnp%xpTL`$@#_uq(4njYwza#$r=Fj-}*(l@CZZ}k5KEC=6@+0Ge{1hLPnHIa7
zD0cg*G$oO92NPKCX;pr!xTR;~d7G*P6=>akS2vhKwAf?;cUQj%vn&Cm$r=bCkpYsS
zy>@8RJPDE+0u;LOY%AAf)w6Yr9T(co4+21cT=j2%dHf~$DD|_y|M*$$PK}*u=>d^h
zn`)fA+U+5Tmcxl*HMXY%gEIKIvU@_0F-gBGb%1x@5H6&f23?s~T%z4k#$|AfmNHY2
z=$>o@S(fF=>+y)Zcs(Moh!5r!kB_*nydICoM_!R&m+J1XpWpAVA0fdFeTZ~M?nFwE
zyk6D@({@tbRnO}7-IQkoPx_3bw(js_H#&XxK)RAuHh(Xl;w`w%fQBqj4Z-A&`qK+-
zt*shO-(y7woqBv141avnvL7Fj5us}OYMLz!n1Kf!o0t(AYD$lcZ=d;b@gw7!#<7la
zyH?oZsFFru&4C%uCE$e7?eRkFmmf5EFIn5
zw|qadK)TcFUU)eQLN`j@5-Q)+>sp_-o5!i=e0JM=auayQ`5fpsMRw}$?iPykIaVFK
znj9$kDqsWx4d2i0g`BI7jhQc6Yz3vl#$Y6&%RJTQUXVXBTn9TvKd&^Q@yaiwK5jy<
zFN(pgGQJ$4)TT-h6~R$GkIHT{{%(o?7k~KcfAw++15?(suAw*J$p{Ip+Q{=u8125p
zK{}A(tE&)bB89x;_WkXau`l2g_*s2r7HSUJ44i=DZoV4NLQP;x#0DO7g4+{pRYqJyvqw}Hd{GCPzPgh)$Y2t@brb0exouUQ
zuQOt!QGN`zcI0P*Z0L;eHT6lT?+kqP4PNf&9Fgg!{t+$$5yXg8USdO~dkbf$jlSnf
zC&pr1wW2EDkHrCcv}BnQ!l{!dJ}~JVT!Rvh<@W?(oMKxP9q3#>Ia4Kc(0MxNnzj|R
z$?nZ~?wnirC5o8=i?hkuQ4$vux`z|6n;!g}`e7GxW7!
z`*j>keqNNvuHYr?pXfUFMfl<)FLJSVliX%l+E1PQjhzJI4C+mrd40$}lds|8Oe%l<
z=exCjO#(2Sire{#FQK1|>Y_XB?`P0@yxxLVJP{iLMUhBOe^Dz>o1^j?ge&alDi~WK
zkS;#$4aA|bS>JQ$ZrxWr0_>LWehelBMRS6NFBBIvDiTpG2BK!IoJ`jzF3;c>_*V(7
zf4Qy;opnF>|D)~Swk^qWD?w~dVA(#$-6JBeyw^~xb!lnnK|S>UKhQ7IgY=|P(ookZ
zvYKR)d5Mg0KWEzlrXB#;-X2UG3*T_!-wK%SAO+s$mnnPExN*MjhNKfnF-dZd2#di?U+
z*FSuD-=Xt-Ki^->-MH!iC6O76CPgWD`sf;$I^2#}-aIvo#$}$z?e_L|Ds%4*x|=(@
z5D1EchXJ+Lv?Us7Zmx*3_(ZYU*n7LV(*iuTp=DNj_iiw_+p^-krcaB8+ZHQYaA>#~#GzbF+jN42ayBB)w8EZXIp8gV@?;Zg$Yzyizch
zsCH`WK0*RLyUM2bsx60ghCF~G^vn09yDfJ!>miR=X9l+z$-OOtHC#3aCBV%IrzxFw
z=Gk_93~nLzh)wr{T(lRn12`;~dt`}a!a>n80}3iRMeg4?P9LO{L0oQd@;1_7!G
zE=7kybX%2FPG(3ukzjz4RoYXJf)gVZTaJ_k6+P`^EC$;QG=i=$gHTQRO`cG~0+eZ@
zZ-Ac3Anp+-a0;oB!BMCKYj)lm8jo*dKAB^IySG-A{6b~vQ)xs%Tge`DfT30}F0Oh2
znsXmQhnI=JaQbYAM8(sZnw*ETZ-A?gTrNj7e2##cfS8e!3+45yi-=;SQgJzl4p;v3
zLBP{b$F7C*0bII)Ls#%J{!oz(UHo4GQq@9~x=Ur)D)Yk@C_ItT^r%3{AXnUs=gtyT
zYTs2Ab3IpXz)m563ulnU&2yTwqetc15SdJ&~kZZc0=m
zDRV3hqN+ogC0C2hvMX0b7K_8-qK<{LHES#3cwx6@n2G?n(ni>9Z|*xM|#0a$gXm}PbqJkc1w@kN&y77oy&q1qVA{TVk9K<|E|
zBHicHSR$NkH8G4ytfD~?C23heq1yjD2%q@`%qOr`^@|uu0l)T1?S1ch1uyA>0gGmj
z@2&N+hAo%=i7H+$3E&GFKI%-^^@CkLC`diDu5eTL?}7to3+6RatKe$XsE9vE{~JbY*%kc%pTRV
z#xw0vSuwkPm25%d0d}Hn3b)4Nw#h_RzZYlI_sEWpV*2*&Dz>^)KME^sFx-en?&3B_+9}>U{{(
z;f_r07Hm?=XlDk^WO8%kQ9+xV1Bnbou#&e~L*fx70iTf($Y3VLUAY*5+2sL6BvzF~
z6~ho1jRRMZu@)qb0$rBhXZZo}3Z%;;R4%B?o}T?Z%t>KdInGFh}>Uc3@y%U5Pp
zNgD_=t8{(+pOG>r+QXf#}Lq}43v@din4s3n%V
zbfqeA3eK6jsR|)&=!ABbGNwA`)(^qL_@1$$bADf}$Wxy9VWuy4IiR||L@^>AK3-V5
z46}Ga|1y16Y4$A6LnPOH11~BQV{UQTzXAIV{p&j}bU$YFiNvb&Hc~Krz8h8_=lH^6
zk(AzJkDP)c
zs^H913pm(gJlHCz{X7byUH%pi|Aa@
z@JM`e3DquE&spQeYE4}tdpb<F9k~(9hb0_1=O?o_hpR
zGG*QFl@2OvNEy8_Xtw>Xf^5T*BCW8yVVsmWB8ufX`vFoYlA)iRK~WD|9Uc+plNhV#
zYH9D#d!l*+^pHK3p(-6+BVWKCfc
zl+}{K?m#gSaOFlh8RBRvmaf*w?~^BpHF9wjUEBW8pK2$PHFrUZL3vScBDC2YvXYMu~&8_+(t3u%W1Hs`L=y{n5=WRLRaI5jwV`
zOr8YHgh8=|BMAY4ZScm6>Iczwl9Q5ZNI53zkqjUoDB`jlgG_}davT@W|476?-ZH=L
zE&DLv*Q3a%yu`yQJpJdGRXzaD7{#aj>c~p;Zy$DHo@f6J9$doX(lK|?0pOKGd|U`8
zosP?v>FHLUUikDIJ$(cp&+qwj|MbsO4DfJEy$>-A9eWM4GeXF*wPjDAvN*lS%*O{l
zR^aLDt}lD?BeQQQ%CO3iwqI3;MDI$b!j#rQzABwd(P+Wb#M^p7_vZG=tX9s9;IjMPFUu(lB`9;_
zh63-gUtTQt{hM|C{AGRnqTk=+J$#=T_kA2MBT?ZRr=VAQ2oq
z%-*XmD0Yp7ba(5G1G21t*)9PvTjHvq5T39u)@tp7>qKbBRN
zKsR&NeCS-%i{rNZc9@&00VttRMyJGU0743$RlG2QE-=u1j{6nFRH|460!lEH0R@<_
z_sBbO&&=$D+lOBwJKfJ|_jbpU4gmF0*&~!-3{)jORI;9zg1(TcEeSmn=oIeCv&pj#
z%*Ou+KsB+{6MA@kLS66J#*J5?Km1S|^6EIL(cl-SRwew1%Id5FYR#myieK5iN9{mf
z(p_W6IHpP(KfsAeFb;5B7TP2aWeZbFDex)4yfD?};tSYK6TarR|9Ow`^m+X!_3ezO
zyTC}bkMXHyO8_&o61eK()0X29Akb-<(Mb>`q@qF&;h+vEFzQ
zYe(O$lXYV1UZy-ija1Y)CXqrZb5*XpnWuSFZT4s3W9D6b#uR0cr{=P!PUdFnF0hUdV*Vvuw6Nsww=|(BdzNloNarhtg-(9D*|6`8i
z;Oyred+CStON-U0v&`|N1fV{0dZPZU(x6v?$F$pmu=#*-KNq~ePAIMriR#hL6Lwrb
z%y)N
zZ9{#5-|H)%(i7KF9Ng&!CSWVKJ=c(G-Mz@-FToiS!7)ZbtROPRRYgnVX
z13LV*`sZ2Vq>)Vn1@_L{vV-{cg+Kq~zxi_iesk}A?(>$huzF9Xx*N4~&N*=x3^21$
zXu9DYB51~At+)60OhttG!my-(3<Mv35O%g!dfSOUTT!<`k@BQcxzsw2IkOpRFN&(>o63@f
zs&5`AcxLPt&wm&@vXlj~;lJ6Ez0f>KLq&KYh&|;qkN_e9a)TjkplS`yp6{DA3h5Mr
z++FsE7S0?Nil`X@cAc`00SC9WStn7VDe5}&emwy-X47TSTPC;PM`EdE(PiBLH`cNh
zyM?Y>=&k}ON896~)h?%8Tj(lA;9Mc`aJH&($sK?ee1wJ00dQ0IbeZR8r~25tf7*4l
z^Lk#qYrpreJ69-Zlm@Mlb@_mf@#+qlQ;ae~y6NT<;?y%s0xlg!PqA75_Ba<*p8J@K
zZ<4TXu@jD2v~hUyF=woNf+1>|L`vM#S^ah8N{6Lr?%cGWTV7-lnz4g}E;o@i}j
zfHSbbWXej`l+069?$D}brn_T?)^1VJyx6Wx@Tobumv*VNR`IInp%MbR5QA}fT!C8+b9kln2H)N
z(#s`^A<*b8ds;VJ@+3IfyQM)yR#-`g(rWq!Rkb)pTfaDQ=}nt0!85!*A3bT378+ZYl26JNRSdH@EfTxH(CMjG(hRuuCn6pjFeV
zSHN%G$x4Iifa#=GYIT_-jp~O*gLXO++s#=i`u<=yM44S74lCrYn>T@cu#L_RuxDoJ}%<-Kx*-3dl~85U7UBdXm>6
zM}wRJU3I8gZBJ5Gzs@qZ`Xa$g#cUq1gi339Wr5IXVUkc*jW!oN>`=7F8`H#7^N=PUwN#Hd2pS2QQIu-bAV{;>cdTHqBd7}s
z&dDmnks8HF=}|$%#}OkyL`AA~nYAtxmCbc_My-_yf#&B}LkDD+Pim~KYP;~t|8YE=
zx>Vmt=Hp<_-_P>*r(Wg-^C8#ye*o_}I34I+q44b3`V96X>zwE_wa(@yfG2AI+4?;G
zh510BMS*eE
zwsV=!NEx#Z|MHH%+AH<%KZ)l5^FL4CWNxXR$drmb97^ri%hVr=TK0=pQE}^jnqk1>RSJ2H
z73iqh1%&brexLEjz?;^4=Be|^xt3*&!?382hrPPp42yDDk97eBE6y_K5DPVMB;4RE
zry_tm@p;FWsA37BjSSdYjnzD6mG^Lzf_83%D8fafSxS+jtb~hd@F^t1ax0;G+>2IH
zKN^v-4ofLzZ#(7q@VY*|tZzTOEP|=rd!J`UD7)*Uw2Rc`k1i_f!)y(!$SI&{e$CBE
z%Pd98BDyQ0v2L0pB_^3*(uGAk=*xVOs~!M}+i_S;ifO-9_4=|R=ckH*EF|ewrtj9O
zGS~b~LG&sCu6laPAV*JbEDBwXoIqtp=2m7$I$+&PluqNY-5^OP+-%Xk#0%SKO2pzmdMp@(9oou2qBkox(4UyVA_PwsWzN?flmRFR>ei~!TNWwa^
zUH)m&U;K8gW0{*R)YeTFx<#;baJIEK>(h$>f>JAewg=+?!0DV6Aq!%|?y2|CJ#;D)
zmS8KRy18A(Kt|k*AKkz8^})Pw^BKCQLO8|uo%hHp=-<$pxs@9@h4<8#d%W+whtBN(
ziv%QN+9e5@J@UDw)hlQ#e>JyPHdYOb`waJVIl&A2v>wT98S3Kq+HJP;B&0a!_=
zd-
z&n(H+DH(Zvw1zGAC
z7{e-6Igi9D9;6n2^>gKn7%2lh;1!
zjbQ|9YLvixG%`JE@EzzV6&kQ$e7202h|q3fPMi9W9$w}(W1#ag0+9r&-`sk?5j|f3
z0*qSBByUbh_s9$@9T^(?`^Csj?>>c!sk5ssA7$?KKcPNelqDjk7Qd`^DtGL|Np>){
zsf6|Dr4~FF%{q$;3NV}U)!K1v9J6aFz|xq?;^bg(j2x}c0kIVAQT22M*R`i}
zYT{5eu;`-ADyD}Zq+vCCl*6G?CR63e$}5y3>C<6^$eB!Ts4~PJvQt}7%-m!`2CFhW
zH$t%Ta8kz?gyE`4#IR^}!&gC0o1f;12VtZ0Z+v<$OYFreke)24BqVK=I_EtN#mGry
zUGc(K=7b#uVUiV1s@M$IsEg-Mko}m=v9tKe#}2do)o(fYu)lbG!~`n+OR|x#0A%)K
zyuzh9!<}gaFQ=+8t52r)5t=-bI*-p7tM@N&;a~gnurbZ4*Prde>TI&TRWh!fKE)2>
zJjsFG^%uo`(yF)B=S)wyG)VVKN(rKiyU(5{vYwS;RTA;LQ>=mG)S1R6ElYY}ECY
z?luc}19lA+>AM`-s;C0GZRw4KlErst8guojsyDeQ5968ow9Gb`xcv)-jtfpT;VkZ3zd^z(dJVducK1z{5i+ER+K{RWSt|Kd-+TBeAuyww0DWj^E
z+*S=O0jiiBk=qR{1$Q?o*XwKC-_k89cYX8W_UX94c)XWNPHe@dZi0-i;-ss_SUs);
z)p%x3Nl0rg(xMj@E!>Gync90FT<+csYH9P9VnZsK%0S_IN%H@8o2A88*fjl7F*k#89%Z6|m6
zgW4EHbqZ-bm2asp$~RzlHOIr8QK$r7X&sMpXBu5yJ6BUbo5)FAGhJG3e{jbpah0|<
z6^HIT7MV5Vv%H=`$z_gAr>!oHEszb7mpU>UG+l0N41amE=iGNW&T)NBu(6%iMH!>)
zon3{A4YoOd?kvXz=ATmmKl$TNo$k1&0Z31IgHCBwAC8YlC~!G^m{G_gW6+#6ib+-G
z9a?K`$t7jFyO1op6=^gj9bC{sIh*Hslx%gT=0TIG@z7NkWAhAa7*iD9%2s>8McKB;
z!mv_b31zC^PDxnk_Dz(>)97P7m4(^pEmpW0RdCje&=K=MB^cnOS&fu5G3~+-=qKC>
zsWF4K5H^No^35|zydIJwGB@SGHaaX4m#6O_x$dM{KIRWY!bz
znaQ&gDY$vY>5fIbKtxC?<*?E$t5MddbCnfT)P^jwqQt9FYDSaJQDvez>J2p*g>!1^
zsixAH%XuTubCb)KE3=QCRHjgkL5jRWuBAj8a9kNuWkKhN2q6NoQG~D}>YVl$|jcd9uPP*RdQnE1Sb8`i)a6G}c;31iHzj
zPRCP`Vc$iSi?Typ)wT2*S9DPacZi?iCN6|Nt1oaIGX)qdr*iB0!h7j2qoT%T>H&=x
z7=Ew`1MMI7>LN;XU4gDk(HJg1-Rz+3pIA8c&HUtdWvHHoeCB?yTBhqEOu6A@J+GU1
z3IeYD;!l6RM*oj@@`^ghr`LRSA9{*+{?$LVm9M-FbhU`!Q51B&be?HHpenquw)Ha<
zdS1eTIvAH^m&Y5<$gZz0`lkJ0r%$pZz~}VW{Spn**`=nvOBo0=GI~E!$V@p)GP)R;
zgmQ>LpjNLAU7ix?+~+|o^B4BlRDFF`bdd4lTr^vj?-8M7q{-YPyLip$N@x}H3Bu#?L
znCb2gQ-n^4+>&|CYYAgji}nJSCp>%^U4FuCXH~<>=>;2@G#X-iR~A=M(2+3b0WMf6
zR|3k|Cu8TiGta_!7c(%&XJ!WpFlNeab*@v2bI0DpZq!ICMW&m3>Fl&$H{${vW;AnO
zWLJ81_6IuX(|J|#Y;~R01~;pbj#sgtM0n{wm!3?sE;P_|o)%d9J?@|N{>79LGFWCM
zj*@hk5Ms)Kvjc8(Hxg!yJl&49e1QkKBq;WYNIN6%n~`}&X6+?7DXSvY2m+uZMXTtu
zdl)K?u7yk~*cq_5%o@CPM$&vomdMr4>;gZ8kqi7lescfld^KCjEq>YYMS4$d<_@OA
zr;AaENQeyKJ#>$_xB3PzblPdbE|Ms-(sp@h_nEpk4O=}ncjA&PB7-GAgwktb`-ov9
z1p$Fxa5E}lV$H!T>$T=(6)j$6_{~*y-Qq=hv$FdSH`hC(eeal2v;)G!r1tgrd_s9d
zYo(N{+PgLMNhwR^(t4(>^tigmXFh)=8;-Pls9)6+2f&)u3{`@m5(MmfNm*^`GPX^?
zWIsXiJz|;Pz~!A3QmynA^BD)ZnkWgM!H&!c}OjAVsdCA8Jc@*Nhp95icts5p=UE?!Y88%jHNg
zHzyD1OoD#qRyXm35BV7fLM7#-mNu!GuY);@6G3G^nj4@1i$uWBG=eWqgOIy%|6FHf
z1_B73*7BfMYpSdNp^i!iBPA3VZNI0l*I=YFV);VKi4WAVNQUnFF5f6pZvl!tZ92a@
zZ;8>O6bXg4wK$K}ZB_7ANPGYo0Hhd~FwG8gyAe3n=W|DRu1*CR3G3uX*?kD1Z8T+=
zxncF}Nl3=na-;c?nNh;h#m`M1A$xT+(MUBP3@JV}WL=O@tYiiuZ&8be9;yhigIe_L
zunIejmBS~IsM^qCTEw0TM@SBn0W%e)($v{VwG2s;%-rS&E@WAef-w`Mm*pvJ)Ma~>
zLcw)mZ4w>~0EZmV#KeMilYRhGLUd&e$9{CmDs8_(_cM?Ikfcp
zTWjoaJ;`w^O$30QiAS54vTs#{SzYjXIia}>p}My)L`gB&f?!