Skip to content

Commit

Permalink
add match action and turn logic
Browse files Browse the repository at this point in the history
  • Loading branch information
dubzn committed Dec 21, 2023
1 parent 49b3774 commit a977af7
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 46 deletions.
8 changes: 4 additions & 4 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ mod systems {
#[cfg(test)]
mod tests {
mod setup;
// mod test_character_system;
// mod test_skill_system;
// mod test_map_system;
mod test_character_system;
mod test_skill_system;
mod test_map_system;
mod test_match_system;
// mod test_turn_system;
mod test_turn_system;
}

16 changes: 3 additions & 13 deletions src/models/states/match_state.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ struct MatchState {
id: u32,
turn: u32,
player_turn: felt252,
// TODO: remove players_len & characters_len
// use the new Models MatchPlayer & MatchPlayerCharacter
players_len: u32,
characters_len: u32,
map_id: u32,
winner: felt252,
}
Expand Down Expand Up @@ -38,6 +34,7 @@ struct MatchPlayerCharacterLen {
#[key]
player: felt252,
characters_len: u32,
remain_characters: u32,
}

#[derive(Model, Copy, Drop, Serde)]
Expand All @@ -49,6 +46,7 @@ struct MatchPlayerCharacter {
#[key]
id: u32,
character_id: u32,
dead: bool,
}

trait MatchTrait {
Expand All @@ -58,14 +56,6 @@ trait MatchTrait {
impl MatchImpl of MatchTrait {
#[inline(always)]
fn new(match_id: u32, map_id: u32) -> MatchState {
MatchState {
id: match_id,
turn: 0,
player_turn: 0,
players_len: 0,
characters_len: 0,
map_id,
winner: 0
}
MatchState { id: match_id, turn: 0, player_turn: 0, map_id, winner: 0 }
}
}
10 changes: 10 additions & 0 deletions src/store.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ trait StoreTrait {
fn get_match_players(ref self: Store, match_id: u32) -> Array<MatchPlayer>;
fn set_match_player(ref self: Store, match_player: MatchPlayer);
fn set_match_player_len(ref self: Store, match_players_len: MatchPlayerLen);
fn get_match_player_characters_len(
ref self: Store, match_id: u32, player: felt252
) -> MatchPlayerCharacterLen;
fn get_match_player_characters_states(
ref self: Store, match_id: u32, player: felt252
) -> Array<CharacterState>;
Expand Down Expand Up @@ -195,6 +198,13 @@ impl StoreImpl of StoreTrait {
characters
}


fn get_match_player_characters_len(
ref self: Store, match_id: u32, player: felt252
) -> MatchPlayerCharacterLen {
get!(self.world, (match_id, player).into(), (MatchPlayerCharacterLen))
}

// Entities

fn get_character(ref self: Store, character_id: u32) -> Character {
Expand Down
100 changes: 74 additions & 26 deletions src/systems/action_system.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ mod action_system {

use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

use debug::PrintTrait;

#[storage]
struct Storage {}

Expand Down Expand Up @@ -70,33 +72,52 @@ mod action_system {
let skill = store.get_skill(skill_id, player_character_id, level);

// fijarse que tenga el skill el que ataca
let skill_type: SkillType = skill.skill_type.try_into().expect('char doesnt possess that skill');
let skill_type: SkillType = skill
.skill_type
.try_into()
.expect('char doesnt possess that skill');

match skill_type {
SkillType::MeeleAttack => attack(
world,
player_character,
player_character_state,
skill,
receiver_character,
receiver_character_state
),
SkillType::RangeAttack => attack(
world,
player_character,
player_character_state,
skill,
receiver_character,
receiver_character_state
),
SkillType::Fireball => attack(
world,
player_character,
player_character_state,
skill,
receiver_character,
receiver_character_state
),
SkillType::MeeleAttack => {
attack(
world,
player_character,
player_character_state,
skill,
receiver_character,
receiver_character_state
);
check_and_update_game_state_winner(
ref store, match_id, player, receiver_character_id, receiver
);
},
SkillType::RangeAttack => {
attack(
world,
player_character,
player_character_state,
skill,
receiver_character,
receiver_character_state
);
check_and_update_game_state_winner(
ref store, match_id, player, receiver_character_id, receiver
);
},
SkillType::Fireball => {
attack(
world,
player_character,
player_character_state,
skill,
receiver_character,
receiver_character_state
);

check_and_update_game_state_winner(
ref store, match_id, player, receiver_character_id, receiver
);
},
SkillType::Heal => heal(
world,
player_character,
Expand All @@ -116,6 +137,34 @@ mod action_system {
}
}

fn check_and_update_game_state_winner(
ref store: Store,
match_id: u32,
attacker: felt252,
receiver_character_id: u32,
receiver: felt252
) {
let receiver_state = store.get_character_state(match_id, receiver_character_id, receiver);

if receiver_state.remain_hp.is_zero() {
let mut match_player_characters_len = store
.get_match_player_characters_len(match_id, receiver);
if match_player_characters_len.remain_characters == 1 {
match_player_characters_len.remain_characters = 0;
store.set_match_player_character_len(match_player_characters_len);

// Set attacker as winner
let mut match_state = store.get_match_state(match_id);
match_state.winner = attacker;
store.set_match_state(match_state);
// TODO: Register stadistics
} else {
match_player_characters_len.remain_characters -= 1;
store.set_match_player_character_len(match_player_characters_len);
}
}
}

fn attack(
world: IWorldDispatcher,
attacker: Character,
Expand All @@ -141,7 +190,6 @@ mod action_system {
} else {
receiver_state.remain_hp - (attacker.attack + skill.power)
};
// TODO: revisar
set!(world, (receiver_state));
}

Expand Down
6 changes: 4 additions & 2 deletions src/systems/match_system.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ mod match_system {
match_id: match_count,
player: p.player,
id: i,
character_id: character.character_id
character_id: character.character_id,
dead: false
};
store.set_match_player_character(match_player_character);

Expand Down Expand Up @@ -116,7 +117,8 @@ mod match_system {
MatchPlayerCharacterLen {
match_id: match_count,
player: *players[i],
characters_len: characters_per_player.get(*players[i])
characters_len: characters_per_player.get(*players[i]),
remain_characters: characters_per_player.get(*players[i])
}
);
i += 1;
Expand Down
121 changes: 120 additions & 1 deletion src/tests/test_match_system.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,125 @@ fn test_player_attack_twice_same_turn() {
);
}

#[test]
#[available_gas(1_000_000_000)]
fn test_end_match_set_correct_winner() {
// [Setup]
let (world, systems) = setup::spawn_game();
let mut store = StoreTrait::new(world);

let PLAYER_1 = '0x1';
let PLAYER_2 = '0x2';

// [Create]
systems.character_system.init(world);
systems.skill_system.init(world);
systems.map_system.init(world);

// [Mint]
systems.character_system.mint(world, CharacterType::Warrior, PLAYER_1, 1);
systems.character_system.mint(world, CharacterType::Archer, PLAYER_1, 1);
systems.character_system.mint(world, CharacterType::Warrior, PLAYER_2, 1);
systems.character_system.mint(world, CharacterType::Archer, PLAYER_2, 1);

let player_characters = array![
PlayerCharacter { player: PLAYER_1, character_id: CharacterType::Warrior.into() },
PlayerCharacter { player: PLAYER_1, character_id: CharacterType::Archer.into() },
PlayerCharacter { player: PLAYER_2, character_id: CharacterType::Warrior.into() },
PlayerCharacter { player: PLAYER_2, character_id: CharacterType::Archer.into() },
];

systems.match_system.init(world, player_characters);
let MATCH_ID = 0;
let match_state = store.get_match_state(MATCH_ID);

let mut cs_player_1_warrior = store
.get_character_state(match_state.id, CharacterType::Warrior.into(), PLAYER_1);
let mut cs_player_1_archer = store
.get_character_state(match_state.id, CharacterType::Archer.into(), PLAYER_1);
let mut cs_player_2_warrior = store
.get_character_state(match_state.id, CharacterType::Warrior.into(), PLAYER_2);
let mut cs_player_2_archer = store
.get_character_state(match_state.id, CharacterType::Archer.into(), PLAYER_2);

cs_player_1_warrior.x = 1;
cs_player_1_warrior.y = 1;

cs_player_1_archer.x = 2;
cs_player_1_archer.y = 2;

cs_player_2_warrior.x = 2;
cs_player_2_warrior.y = 1;
cs_player_2_warrior.remain_hp = 10;

cs_player_2_archer.x = 1;
cs_player_2_archer.y = 2;
cs_player_2_archer.remain_hp = 10;

store.set_character_state(cs_player_1_warrior);
store.set_character_state(cs_player_1_archer);
store.set_character_state(cs_player_2_warrior);
store.set_character_state(cs_player_2_archer);

// Check remainder characters for player 2
let remain_characters_player_2 = store.get_match_player_characters_len(MATCH_ID, PLAYER_2).remain_characters;
assert(remain_characters_player_2 == 2, 'it should be remain 2 character');

// [Attack]
systems
.action_system
.action(
world,
MATCH_ID,
PLAYER_1,
CharacterType::Warrior.into(),
SkillType::MeeleAttack.into(),
1,
PLAYER_2,
CharacterType::Warrior.into()
);

// Player 2 warrior should be dead
let cs_player_2_warrior = store
.get_character_state(match_state.id, CharacterType::Warrior.into(), PLAYER_2);
assert(cs_player_2_warrior.remain_hp.is_zero(), 'warrior should be dead');

// Game shouldnt be over yet
let match_state = store.get_match_state(MATCH_ID);
assert(match_state.winner.is_zero(), 'winner should be 0 (not setted)');

// Check remainder characters for player 2
let remain_characters_player_2 = store.get_match_player_characters_len(MATCH_ID, PLAYER_2).remain_characters;
assert(remain_characters_player_2 == 1, 'it should be remain 1 character');

// [Attack]
systems
.action_system
.action(
world,
MATCH_ID,
PLAYER_1,
CharacterType::Archer.into(),
SkillType::RangeAttack.into(),
1,
PLAYER_2,
CharacterType::Archer.into()
);

// Player 2 warrior should be dead
let cs_player_2_archer = store
.get_character_state(match_state.id, CharacterType::Warrior.into(), PLAYER_2);
assert(cs_player_2_archer.remain_hp.is_zero(), 'warrior should be dead');

// Game shouldnt be over yet
let match_state = store.get_match_state(MATCH_ID);
assert(match_state.winner == PLAYER_1, 'winner should be 0x1');

// Check remainder characters for player 2
let remain_characters_player_2 = store.get_match_player_characters_len(MATCH_ID, PLAYER_2).remain_characters;
assert(remain_characters_player_2 == 0, 'it should be remain 0 character');
}

#[test]
#[available_gas(1_000_000_000)]
#[should_panic(expected: ('wait for your turn', 'ENTRYPOINT_FAILED'))]
Expand Down Expand Up @@ -338,4 +457,4 @@ fn test_init_match_with_one_player() {
];

systems.match_system.init(world, player_characters);
}
}
3 changes: 3 additions & 0 deletions src/tests/test_turn_system.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,17 @@ fn test_end_turn() {

// Actual turn is for player 1
assert(match_state.player_turn == PLAYER_1, 'turn should be player 0x1');
assert(match_state.turn == 0, 'turn should be number 0');
systems.turn_system.end_turn(world, MATCH_ID, PLAYER_1);

// End turn, so player 2 turn
let match_state = store.get_match_state(MATCH_ID);
assert(match_state.player_turn == PLAYER_2, 'turn should be player 0x2');
assert(match_state.turn == 1, 'turn should be number 1');
systems.turn_system.end_turn(world, MATCH_ID, PLAYER_2);

// It should be player 1 again
let match_state = store.get_match_state(MATCH_ID);
assert(match_state.turn == 2, 'turn should be number 2');
assert(match_state.player_turn == PLAYER_1, 'turn should be player 0x1');
}

0 comments on commit a977af7

Please sign in to comment.