From d07fa81d8cc15d593a9327e2540ca665a5411c89 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Wed, 17 Sep 2025 15:59:34 +0100 Subject: [PATCH 1/3] implemented initialize --- contract/src/systems/player.cairo | 220 +++++++++++++---------------- contract/src/systems/player2.cairo | 207 +++++++++++++++++++++++++++ 2 files changed, 302 insertions(+), 125 deletions(-) create mode 100644 contract/src/systems/player2.cairo diff --git a/contract/src/systems/player.cairo b/contract/src/systems/player.cairo index 464c5b2..c569f08 100644 --- a/contract/src/systems/player.cairo +++ b/contract/src/systems/player.cairo @@ -1,8 +1,9 @@ use starknet::ContractAddress; +use core::num::traits::Zero; #[starknet::interface] pub trait IPlayerSystem { - fn initialize(ref self: T, player_address: ContractAddress); + fn initialize(ref self: T); // Combat fn take_damage(ref self: T, player_address: ContractAddress, amount: u16); fn heal(ref self: T, player_address: ContractAddress, amount: u16); @@ -36,172 +37,141 @@ pub trait IPlayerSystem { fn has_ability_equipped(self: @T, player_address: ContractAddress, ability_id: u256) -> bool; } -#[dojo::contract] -pub mod player_system { - use starknet::{ContractAddress}; - use starknet::storage::{ - Map, StoragePointerWriteAccess, StoragePathEntry, StoragePointerReadAccess, - }; - use super::IPlayerSystem; +#[derive(Copy, Drop, Serde, Default, Introspect)] +pub enum PlayerStatus { + Alive, + Dead, + InGame, + #[default] + Waiting, +} + +#[derive(Copy, Drop, Serde, Default)] +#[dojo::model] +pub struct PlayerData { + #[key] + pub id: ContractAddress, + pub hp: u16, + pub max_hp: u16, + pub coins: u64, + pub gems: u64, + pub equipped_ability: u256, + pub active_towers: u8, + pub mana: u8, + pub max_mana: u8, +} + +#[derive(Copy, Drop, Serde, Default)] +#[dojo::model] +pub struct AC { + #[key] + pub player: ContractAddress, + #[key] + pub ability_id: u256, + pub ability_cooldown: u64, +} - #[storage] - struct Storage { - hp: Map, - max_hp: Map, - coins: Map, - gems: Map, - equipped_ability: Map, - active_towers: Map, - mana: Map, - max_mana: Map, - ability_cooldowns: Map< - (ContractAddress, u256), u64, - > // (player, ability_id) -> cooldown_until_timestamp +impl ContractAddressDefault of Default { + #[inline(always)] + fn default() -> ContractAddress { + Zero::zero() } +} + +#[dojo::contract] +pub mod PlayerSystem { + use starknet::{ContractAddress, get_caller_address}; + use super::IPlayerSystem; + use crate::models::player::{Player, PlayerTrait}; + use super::PlayerData; + use dojo::model::{Model, ModelStorage, ModelValueStorage}; + use dojo::world::WorldStorage; #[abi(embed_v0)] - pub impl PlayerSystemImpl of IPlayerSystem { - fn initialize(ref self: ContractState, player_address: ContractAddress) { - // Set initial game state values when a player joins - self.hp.entry(player_address).write(100); - self.max_hp.entry(player_address).write(100); - self.coins.entry(player_address).write(0); - self.gems.entry(player_address).write(0); - self.equipped_ability.entry(player_address).write(0); - self.active_towers.entry(player_address).write(0); - self.mana.entry(player_address).write(100); - self.max_mana.entry(player_address).write(100); + impl PlayerSystemImpl of IPlayerSystem { + fn initialize(ref self: ContractState) { + let caller = get_caller_address(); + let mut world = self.world_default(); + + let p: Player = world.read_model(caller); + p.assert_not_exists(); + let mut player: PlayerData = Default::default(); + + player.id = caller; + player.hp = 100; + player.max_hp = 100; + player.mana = 100; + player.max_mana = 100; + world.write_model(@player); } - // Combat - fn take_damage(ref self: ContractState, player_address: ContractAddress, amount: u16) { - let current_hp = self.hp.entry(player_address).read(); - let new_hp = if amount >= current_hp { - 0 - } else { - current_hp - amount - }; - self.hp.entry(player_address).write(new_hp); - } - - fn heal(ref self: ContractState, player_address: ContractAddress, amount: u16) { - let current_hp = self.hp.entry(player_address).read(); - let max_hp = self.max_hp.entry(player_address).read(); - let new_hp = core::cmp::min(current_hp + amount, max_hp); - self.hp.entry(player_address).write(new_hp); - } - + fn take_damage(ref self: ContractState, player_address: ContractAddress, amount: u16) {} + fn heal(ref self: ContractState, player_address: ContractAddress, amount: u16) {} fn is_alive(self: @ContractState, player_address: ContractAddress) -> bool { - self.hp.entry(player_address).read() > 0 + false } - // Currency - fn add_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) { - let current_coins = self.coins.entry(player_address).read(); - self.coins.entry(player_address).write(current_coins + amount); - } - - fn spend_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) { - let current_coins = self.coins.entry(player_address).read(); - assert(current_coins >= amount, 'Player: Not enough coins'); - self.coins.entry(player_address).write(current_coins - amount); - } - - fn add_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) { - let current_gems = self.gems.entry(player_address).read(); - self.gems.entry(player_address).write(current_gems + amount); - } - - fn spend_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) { - let current_gems = self.gems.entry(player_address).read(); - assert(current_gems >= amount, 'Player: Not enough gems'); - self.gems.entry(player_address).write(current_gems - amount); - } - + fn add_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) {} + fn spend_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) {} + fn add_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) {} + fn spend_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) {} // Equipment fn equip_ability( ref self: ContractState, player_address: ContractAddress, ability_id: u256, - ) { - self.equipped_ability.entry(player_address).write(ability_id); - } - - fn activate_tower(ref self: ContractState, player_address: ContractAddress) { - let current_towers = self.active_towers.entry(player_address).read(); - self.active_towers.entry(player_address).write(current_towers + 1); - } - - fn upgrade_max_hp(ref self: ContractState, player_address: ContractAddress, value: u16) { - let max_hp = self.max_hp.entry(player_address).read(); - - self.max_hp.entry(player_address).write(max_hp + value); - } - + ) {} + fn activate_tower(ref self: ContractState, player_address: ContractAddress) {} + // Upgrades + fn upgrade_max_hp(ref self: ContractState, player_address: ContractAddress, value: u16) {} // --- Getters --- fn get_hp(self: @ContractState, player_address: ContractAddress) -> u16 { - self.hp.entry(player_address).read() + 0 } - fn get_max_hp(self: @ContractState, player_address: ContractAddress) -> u16 { - self.max_hp.entry(player_address).read() + 0 } - fn get_coins(self: @ContractState, player_address: ContractAddress) -> u64 { - self.coins.entry(player_address).read() + 0 } - fn get_gems(self: @ContractState, player_address: ContractAddress) -> u64 { - self.gems.entry(player_address).read() + 0 } - fn get_equipped_ability(self: @ContractState, player_address: ContractAddress) -> u256 { - self.equipped_ability.entry(player_address).read() + 0 } - fn get_active_towers(self: @ContractState, player_address: ContractAddress) -> u8 { - self.active_towers.entry(player_address).read() + 0 } fn get_mana(self: @ContractState, player_address: ContractAddress) -> u8 { - self.mana.entry(player_address).read() + 0 } - fn get_max_mana(self: @ContractState, player_address: ContractAddress) -> u8 { - self.max_mana.entry(player_address).read() - } - - fn spend_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) { - let current_mana = self.mana.entry(player_address).read(); - assert(current_mana >= amount, 'Player: Not enough mana'); - self.mana.entry(player_address).write(current_mana - amount); + 0 } - - fn regenerate_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) { - let current_mana = self.mana.entry(player_address).read(); - let max_mana = self.max_mana.entry(player_address).read(); - let new_mana = core::cmp::min(current_mana + amount, max_mana); - self.mana.entry(player_address).write(new_mana); - } - + fn spend_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) {} + fn regenerate_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) {} fn get_ability_cooldown( self: @ContractState, player_address: ContractAddress, ability_id: u256, ) -> u64 { - self.ability_cooldowns.entry((player_address, ability_id)).read() + 0 } - fn set_ability_cooldown( ref self: ContractState, player_address: ContractAddress, ability_id: u256, cooldown_until: u64, - ) { - self.ability_cooldowns.entry((player_address, ability_id)).write(cooldown_until); - } - + ) {} fn has_ability_equipped( self: @ContractState, player_address: ContractAddress, ability_id: u256, ) -> bool { - let equipped_ability = self.equipped_ability.entry(player_address).read(); - equipped_ability == ability_id && ability_id != 0 + false + } + } + + #[generate_trait] + impl InternalImpl of InternalTrait { + fn world_default(self: @ContractState) -> WorldStorage { + self.world(@"stark_brawl") } } } diff --git a/contract/src/systems/player2.cairo b/contract/src/systems/player2.cairo new file mode 100644 index 0000000..464c5b2 --- /dev/null +++ b/contract/src/systems/player2.cairo @@ -0,0 +1,207 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IPlayerSystem { + fn initialize(ref self: T, player_address: ContractAddress); + // Combat + fn take_damage(ref self: T, player_address: ContractAddress, amount: u16); + fn heal(ref self: T, player_address: ContractAddress, amount: u16); + fn is_alive(self: @T, player_address: ContractAddress) -> bool; + // Currency + fn add_coins(ref self: T, player_address: ContractAddress, amount: u64); + fn spend_coins(ref self: T, player_address: ContractAddress, amount: u64); + fn add_gems(ref self: T, player_address: ContractAddress, amount: u64); + fn spend_gems(ref self: T, player_address: ContractAddress, amount: u64); + // Equipment + fn equip_ability(ref self: T, player_address: ContractAddress, ability_id: u256); + fn activate_tower(ref self: T, player_address: ContractAddress); + // Upgrades + fn upgrade_max_hp(ref self: T, player_address: ContractAddress, value: u16); + // --- Getters --- + fn get_hp(self: @T, player_address: ContractAddress) -> u16; + fn get_max_hp(self: @T, player_address: ContractAddress) -> u16; + fn get_coins(self: @T, player_address: ContractAddress) -> u64; + fn get_gems(self: @T, player_address: ContractAddress) -> u64; + fn get_equipped_ability(self: @T, player_address: ContractAddress) -> u256; + fn get_active_towers(self: @T, player_address: ContractAddress) -> u8; + + fn get_mana(self: @T, player_address: ContractAddress) -> u8; + fn get_max_mana(self: @T, player_address: ContractAddress) -> u8; + fn spend_mana(ref self: T, player_address: ContractAddress, amount: u8); + fn regenerate_mana(ref self: T, player_address: ContractAddress, amount: u8); + fn get_ability_cooldown(self: @T, player_address: ContractAddress, ability_id: u256) -> u64; + fn set_ability_cooldown( + ref self: T, player_address: ContractAddress, ability_id: u256, cooldown_until: u64, + ); + fn has_ability_equipped(self: @T, player_address: ContractAddress, ability_id: u256) -> bool; +} + +#[dojo::contract] +pub mod player_system { + use starknet::{ContractAddress}; + use starknet::storage::{ + Map, StoragePointerWriteAccess, StoragePathEntry, StoragePointerReadAccess, + }; + use super::IPlayerSystem; + + #[storage] + struct Storage { + hp: Map, + max_hp: Map, + coins: Map, + gems: Map, + equipped_ability: Map, + active_towers: Map, + mana: Map, + max_mana: Map, + ability_cooldowns: Map< + (ContractAddress, u256), u64, + > // (player, ability_id) -> cooldown_until_timestamp + } + + #[abi(embed_v0)] + pub impl PlayerSystemImpl of IPlayerSystem { + fn initialize(ref self: ContractState, player_address: ContractAddress) { + // Set initial game state values when a player joins + self.hp.entry(player_address).write(100); + self.max_hp.entry(player_address).write(100); + self.coins.entry(player_address).write(0); + self.gems.entry(player_address).write(0); + self.equipped_ability.entry(player_address).write(0); + self.active_towers.entry(player_address).write(0); + self.mana.entry(player_address).write(100); + self.max_mana.entry(player_address).write(100); + } + + // Combat + fn take_damage(ref self: ContractState, player_address: ContractAddress, amount: u16) { + let current_hp = self.hp.entry(player_address).read(); + let new_hp = if amount >= current_hp { + 0 + } else { + current_hp - amount + }; + self.hp.entry(player_address).write(new_hp); + } + + fn heal(ref self: ContractState, player_address: ContractAddress, amount: u16) { + let current_hp = self.hp.entry(player_address).read(); + let max_hp = self.max_hp.entry(player_address).read(); + let new_hp = core::cmp::min(current_hp + amount, max_hp); + self.hp.entry(player_address).write(new_hp); + } + + fn is_alive(self: @ContractState, player_address: ContractAddress) -> bool { + self.hp.entry(player_address).read() > 0 + } + + // Currency + fn add_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let current_coins = self.coins.entry(player_address).read(); + self.coins.entry(player_address).write(current_coins + amount); + } + + fn spend_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let current_coins = self.coins.entry(player_address).read(); + assert(current_coins >= amount, 'Player: Not enough coins'); + self.coins.entry(player_address).write(current_coins - amount); + } + + fn add_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let current_gems = self.gems.entry(player_address).read(); + self.gems.entry(player_address).write(current_gems + amount); + } + + fn spend_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let current_gems = self.gems.entry(player_address).read(); + assert(current_gems >= amount, 'Player: Not enough gems'); + self.gems.entry(player_address).write(current_gems - amount); + } + + // Equipment + fn equip_ability( + ref self: ContractState, player_address: ContractAddress, ability_id: u256, + ) { + self.equipped_ability.entry(player_address).write(ability_id); + } + + fn activate_tower(ref self: ContractState, player_address: ContractAddress) { + let current_towers = self.active_towers.entry(player_address).read(); + self.active_towers.entry(player_address).write(current_towers + 1); + } + + fn upgrade_max_hp(ref self: ContractState, player_address: ContractAddress, value: u16) { + let max_hp = self.max_hp.entry(player_address).read(); + + self.max_hp.entry(player_address).write(max_hp + value); + } + + // --- Getters --- + fn get_hp(self: @ContractState, player_address: ContractAddress) -> u16 { + self.hp.entry(player_address).read() + } + + fn get_max_hp(self: @ContractState, player_address: ContractAddress) -> u16 { + self.max_hp.entry(player_address).read() + } + + fn get_coins(self: @ContractState, player_address: ContractAddress) -> u64 { + self.coins.entry(player_address).read() + } + + fn get_gems(self: @ContractState, player_address: ContractAddress) -> u64 { + self.gems.entry(player_address).read() + } + + fn get_equipped_ability(self: @ContractState, player_address: ContractAddress) -> u256 { + self.equipped_ability.entry(player_address).read() + } + + fn get_active_towers(self: @ContractState, player_address: ContractAddress) -> u8 { + self.active_towers.entry(player_address).read() + } + + fn get_mana(self: @ContractState, player_address: ContractAddress) -> u8 { + self.mana.entry(player_address).read() + } + + fn get_max_mana(self: @ContractState, player_address: ContractAddress) -> u8 { + self.max_mana.entry(player_address).read() + } + + fn spend_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) { + let current_mana = self.mana.entry(player_address).read(); + assert(current_mana >= amount, 'Player: Not enough mana'); + self.mana.entry(player_address).write(current_mana - amount); + } + + fn regenerate_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) { + let current_mana = self.mana.entry(player_address).read(); + let max_mana = self.max_mana.entry(player_address).read(); + let new_mana = core::cmp::min(current_mana + amount, max_mana); + self.mana.entry(player_address).write(new_mana); + } + + fn get_ability_cooldown( + self: @ContractState, player_address: ContractAddress, ability_id: u256, + ) -> u64 { + self.ability_cooldowns.entry((player_address, ability_id)).read() + } + + fn set_ability_cooldown( + ref self: ContractState, + player_address: ContractAddress, + ability_id: u256, + cooldown_until: u64, + ) { + self.ability_cooldowns.entry((player_address, ability_id)).write(cooldown_until); + } + + fn has_ability_equipped( + self: @ContractState, player_address: ContractAddress, ability_id: u256, + ) -> bool { + let equipped_ability = self.equipped_ability.entry(player_address).read(); + equipped_ability == ability_id && ability_id != 0 + } + } +} From 9bdb00d63bd3e7ea099325cc2f63e526114f9fc3 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Wed, 17 Sep 2025 16:04:14 +0100 Subject: [PATCH 2/3] assert update --- contract/src/systems/player.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/src/systems/player.cairo b/contract/src/systems/player.cairo index c569f08..8eee60c 100644 --- a/contract/src/systems/player.cairo +++ b/contract/src/systems/player.cairo @@ -82,7 +82,7 @@ impl ContractAddressDefault of Default { pub mod PlayerSystem { use starknet::{ContractAddress, get_caller_address}; use super::IPlayerSystem; - use crate::models::player::{Player, PlayerTrait}; + use crate::models::player::{Player, AssertTrait}; use super::PlayerData; use dojo::model::{Model, ModelStorage, ModelValueStorage}; use dojo::world::WorldStorage; From 82b03f43e5df3f9142321d46def89a9f1627365c Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Tue, 23 Sep 2025 15:01:39 +0100 Subject: [PATCH 3/3] converted player.cairo starknet contract into dojo --- contract/src/systems/player.cairo | 229 +++++++++++++++++++++++++----- 1 file changed, 193 insertions(+), 36 deletions(-) diff --git a/contract/src/systems/player.cairo b/contract/src/systems/player.cairo index 8eee60c..bce8e5e 100644 --- a/contract/src/systems/player.cairo +++ b/contract/src/systems/player.cairo @@ -50,15 +50,15 @@ pub enum PlayerStatus { #[dojo::model] pub struct PlayerData { #[key] - pub id: ContractAddress, - pub hp: u16, - pub max_hp: u16, - pub coins: u64, - pub gems: u64, - pub equipped_ability: u256, - pub active_towers: u8, - pub mana: u8, - pub max_mana: u8, + id: ContractAddress, + hp: u16, + max_hp: u16, + coins: u64, + gems: u64, + equipped_ability: u256, + active_towers: u8, + mana: u8, + max_mana: u8, } #[derive(Copy, Drop, Serde, Default)] @@ -83,13 +83,15 @@ pub mod PlayerSystem { use starknet::{ContractAddress, get_caller_address}; use super::IPlayerSystem; use crate::models::player::{Player, AssertTrait}; - use super::PlayerData; + use super::{PlayerData, AC}; use dojo::model::{Model, ModelStorage, ModelValueStorage}; use dojo::world::WorldStorage; + use core::num::traits::SaturatingSub; + #[abi(embed_v0)] impl PlayerSystemImpl of IPlayerSystem { - fn initialize(ref self: ContractState) { + fn initialize(ref self: ContractState) { let caller = get_caller_address(); let mut world = self.world_default(); @@ -105,66 +107,204 @@ pub mod PlayerSystem { world.write_model(@player); } // Combat - fn take_damage(ref self: ContractState, player_address: ContractAddress, amount: u16) {} - fn heal(ref self: ContractState, player_address: ContractAddress, amount: u16) {} + fn take_damage(ref self: ContractState, player_address: ContractAddress, amount: u16) { + self.player_exists(player_address); + let mut world = self.world_default(); + let target = selector!("hp"); + let current_hp: u16 = world + .read_member(Model::::ptr_from_keys(player_address), target); + + let new_hp = current_hp.saturating_sub(amount); + world.write_member(Model::::ptr_from_keys(player_address), target, new_hp); + } + + fn heal(ref self: ContractState, player_address: ContractAddress, amount: u16) { + // let current_hp = self.hp.entry(player_address).read(); + // let max_hp = self.max_hp.entry(player_address).read(); + // let new_hp = core::cmp::min(current_hp + amount, max_hp); + // self.hp.entry(player_address).write(new_hp); + let mut world = self.world_default(); + self.player_exists(player_address); + let m = selector!("max_hp"); + let h = selector!("hp"); + let max_hp = world.read_member(Model::::ptr_from_keys(player_address), m); + let current_hp = world + .read_member(Model::::ptr_from_keys(player_address), h); + let new_hp = core::cmp::min(current_hp + amount, max_hp); + world.write_member(Model::::ptr_from_keys(player_address), h, new_hp); + } + fn is_alive(self: @ContractState, player_address: ContractAddress) -> bool { - false + let mut world = self.world_default(); + let h = selector!("hp"); + let hp = world.read_member(Model::::ptr_from_keys(player_address), h); + hp > 0 } + // Currency - fn add_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) {} - fn spend_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) {} - fn add_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) {} - fn spend_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) {} - // Equipment + fn add_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let mut world = self.world_default(); + self.player_exists(player_address); + let c = selector!("coins"); + let coins = world.read_member(Model::::ptr_from_keys(player_address), c); + world + .write_member( + Model::::ptr_from_keys(player_address), c, coins + amount, + ); + } + + fn spend_coins(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let mut world = self.world_default(); + self.player_exists(player_address); + let c = selector!("coins"); + let coins = world.read_member(Model::::ptr_from_keys(player_address), c); + assert!(amount <= coins, "amount {} greater than balance {}", amount, coins); + world + .write_member( + Model::::ptr_from_keys(player_address), c, coins - amount, + ); + } + + // // Equipment + // fn equip_ability( + // ref self: ContractState, player_address: ContractAddress, ability_id: u256, + // ) { + // self.equipped_ability.entry(player_address).write(ability_id); + // } + + fn add_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let mut world = self.world_default(); + self.player_exists(player_address); + let g = selector!("gems"); + let gems = world.read_member(Model::::ptr_from_keys(player_address), g); + world + .write_member(Model::::ptr_from_keys(player_address), g, gems + amount); + } + + fn spend_gems(ref self: ContractState, player_address: ContractAddress, amount: u64) { + let mut world = self.world_default(); + self.player_exists(player_address); + let g = selector!("gems"); + let gems = world.read_member(Model::::ptr_from_keys(player_address), g); + assert!(amount <= gems, "amount {} greater than gems {}", amount, gems); + world + .write_member(Model::::ptr_from_keys(player_address), g, gems - amount); + } + fn equip_ability( ref self: ContractState, player_address: ContractAddress, ability_id: u256, - ) {} - fn activate_tower(ref self: ContractState, player_address: ContractAddress) {} - // Upgrades - fn upgrade_max_hp(ref self: ContractState, player_address: ContractAddress, value: u16) {} + ) { + let mut world = self.world_default(); + self.player_exists(player_address); + let eq = selector!("equipped_ability"); + world.write_member(Model::::ptr_from_keys(player_address), eq, ability_id); + } + + fn activate_tower(ref self: ContractState, player_address: ContractAddress) { + let mut world = self.world_default(); + self.player_exists(player_address); + let k = Model::::ptr_from_keys(player_address); + let t = selector!("active_towers"); + let towers = world.read_member(k, t); + world.write_member(k, t, towers + 1); + } + + fn upgrade_max_hp(ref self: ContractState, player_address: ContractAddress, value: u16) { + let mut world = self.world_default(); + self.player_exists(player_address); + let k = Model::::ptr_from_keys(player_address); + let m = selector!("max_hp"); + let max_hp = world.read_member(k, m); + world.write_member(k, m, max_hp + value); + } + // --- Getters --- fn get_hp(self: @ContractState, player_address: ContractAddress) -> u16 { - 0 + let h = selector!("hp"); + self.get_data(h, player_address).try_into().unwrap() } + fn get_max_hp(self: @ContractState, player_address: ContractAddress) -> u16 { - 0 + let m = selector!("max_hp"); + self.get_data(m, player_address).try_into().unwrap() } + fn get_coins(self: @ContractState, player_address: ContractAddress) -> u64 { - 0 + let c = selector!("coins"); + self.get_data(c, player_address).try_into().unwrap() } + fn get_gems(self: @ContractState, player_address: ContractAddress) -> u64 { - 0 + let g = selector!("gems"); + self.get_data(g, player_address).try_into().unwrap() } + fn get_equipped_ability(self: @ContractState, player_address: ContractAddress) -> u256 { - 0 + let eq = selector!("equipped_ability"); + self.get_data(eq, player_address) } + fn get_active_towers(self: @ContractState, player_address: ContractAddress) -> u8 { - 0 + self.get_data(selector!("active_towers"), player_address).try_into().unwrap() } fn get_mana(self: @ContractState, player_address: ContractAddress) -> u8 { - 0 + self.get_data(selector!("mana"), player_address).try_into().unwrap() } + fn get_max_mana(self: @ContractState, player_address: ContractAddress) -> u8 { - 0 + self.get_data(selector!("max_mana"), player_address).try_into().unwrap() + } + + fn spend_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) { + let mut world = self.world_default(); + self.player_exists(player_address); + let m = selector!("mana"); + let k = Model::::ptr_from_keys(player_address); + let mana = world.read_member(k, m); + assert!(amount <= mana, "amount {} greater than mana {}", amount, mana); + world.write_member(k, m, mana - amount); + } + + fn regenerate_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) { + let mut world = self.world_default(); + self.player_exists(player_address); + let m = selector!("mana"); + let mm = selector!("max_mana"); + let k = Model::::ptr_from_keys(player_address); + let mana = world.read_member(k, m); + let max_mana = world.read_member(k, mm); + let new_mana = core::cmp::min(mana + amount, max_mana); + world.write_member(k, m, new_mana); } - fn spend_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) {} - fn regenerate_mana(ref self: ContractState, player_address: ContractAddress, amount: u8) {} + fn get_ability_cooldown( self: @ContractState, player_address: ContractAddress, ability_id: u256, ) -> u64 { - 0 + let mut world = self.world_default(); + let k = Model::::ptr_from_keys((player_address, ability_id)); + let ac = selector!("ability_cooldown"); + world.read_member(k, ac) } + fn set_ability_cooldown( ref self: ContractState, player_address: ContractAddress, ability_id: u256, cooldown_until: u64, - ) {} + ) { + let mut world = self.world_default(); + let k = Model::::ptr_from_keys((player_address, ability_id)); + let ac = selector!("ability_cooldown"); + world.write_member(k, ac, cooldown_until); + } + fn has_ability_equipped( self: @ContractState, player_address: ContractAddress, ability_id: u256, ) -> bool { - false + let k = selector!("equipped_ability"); + let equipped_ability = self.get_data(k, player_address); + equipped_ability == ability_id && ability_id != 0 } } @@ -173,5 +313,22 @@ pub mod PlayerSystem { fn world_default(self: @ContractState) -> WorldStorage { self.world(@"stark_brawl") } + + fn player_exists(self: @ContractState, player_address: ContractAddress) { + let mut world = self.world_default(); + let player: Player = world.read_model(player_address); + player.assert_exists(); + let m = selector!("max_hp"); + let k = Model::::ptr_from_keys(player_address); + let max_hp = world.read_member(k, m); + assert(max_hp > 0, 'Player does not exist.'); + } + + fn get_data( + self: @ContractState, selector: felt252, player_address: ContractAddress, + ) -> u256 { + let mut world = self.world_default(); + world.read_member(Model::::ptr_from_keys(player_address), selector).into() + } } }