From b7768e58bdece9d3f134480b5dc3892664d0a418 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 13 Dec 2019 20:15:01 +1000 Subject: [PATCH 1/3] counterattack immunity --- core/src/effect.rs | 8 +++++++- core/src/game.rs | 8 ++++---- core/src/skill.rs | 13 +++++++------ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/core/src/effect.rs b/core/src/effect.rs index d65a518c..f0605c57 100644 --- a/core/src/effect.rs +++ b/core/src/effect.rs @@ -110,6 +110,12 @@ impl Effect { Skill::TriageTick, ].contains(&skill), + Effect::Countered => [ + Skill::CounterAttack, + Skill::CounterAttackPlus, + Skill::CounterAttackPlusPlus, + ].contains(&skill), + _ => false, } } @@ -200,7 +206,7 @@ impl Effect { } // Old colour matching system for buffs / debuffs - // Had issues as some effects will be considered as both a buff and debuff e.g. invert, + // Had issues as some effects will be considered as both a buff and debuff e.g. invert, // Ended up being confusing with mismatch skills that have red / blue e.g. amplify, haste, hybrid /* pub fn colour(&self) -> Option { match self { diff --git a/core/src/game.rs b/core/src/game.rs index f53b6700..91b8eb1b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -1915,8 +1915,7 @@ mod tests { assert!(game.players[1].constructs[0].is_ko() == false); } - // refer fixme.md (infinite counterattack loop) - /*#[test] + #[test] fn multi_counter_test() { let mut game = create_2v2_test_game(); let player_id = game.players[0].id; @@ -1929,13 +1928,14 @@ mod tests { game.new_resolve(Cast::new(target, target_player_id, target, Skill::Counter)); game.new_resolve(Cast::new(source, player_id, target, Skill::Attack)); + println!("{:#?}", game.resolutions); + assert!(game.players[0].constructs[0].is_ko() == false); assert!(game.players[1].constructs[0].is_ko() == false); - }*/ + } #[test] fn intercept_test() { - let mut game = create_2v2_test_game(); let player_id = game.players[0].id; diff --git a/core/src/skill.rs b/core/src/skill.rs index e2a55471..d81527ea 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -1407,6 +1407,13 @@ fn counter_plus_plus(cast: Cast, game: &mut Game) { } fn counter_attack(cast: Cast, game: &mut Game) { + // effect has to be first so that the loop doesn't occur + game.action(cast, + Action::Effect { + construct: cast.target, + effect: ConstructEffect { effect: Effect::Countered, duration: 1, meta: None }, // immunity to additional hits + } + ); game.action(cast, Action::Damage { construct: cast.target, @@ -1414,12 +1421,6 @@ fn counter_attack(cast: Cast, game: &mut Game) { amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(cast.skill.multiplier()), }, ); - game.action(cast, - Action::Effect { - construct: cast.target, - effect: ConstructEffect { effect: Effect::Countered, duration: 1, meta: None }, // immunity to additional hits - } - ); } fn decay(cast: Cast, game: &mut Game) { From a052e515edcd28970dbfe2e639b046f95beee1fd Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 13 Dec 2019 20:18:16 +1000 Subject: [PATCH 2/3] comment --- core/src/game.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index 91b8eb1b..b45fafc8 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -536,6 +536,7 @@ impl Game { return self; } + // maybe this should be done with a status immunity if self.construct(cast.target).affected(Effect::Reflect) && cast.skill.colours().contains(&Colour::Blue) && !cast.skill.is_tick() { self.add_resolution(&cast, &Event::Reflection { construct: cast.target }); @@ -1928,8 +1929,6 @@ mod tests { game.new_resolve(Cast::new(target, target_player_id, target, Skill::Counter)); game.new_resolve(Cast::new(source, player_id, target, Skill::Attack)); - println!("{:#?}", game.resolutions); - assert!(game.players[0].constructs[0].is_ko() == false); assert!(game.players[1].constructs[0].is_ko() == false); } From 3e3e4040d3ac8b1cba9dbfd8e9bd382488040437 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 13 Dec 2019 23:48:02 +1000 Subject: [PATCH 3/3] cooldowns done as a reaction --- core/fixme.md | 1 - core/src/construct.rs | 10 +++++++--- core/src/game.rs | 32 ++++++++++++++++++-------------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/core/fixme.md b/core/fixme.md index d9ba3be1..8223a821 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -2,6 +2,5 @@ check silence skill multiplier game ready not auto starting resolve phase -infinite counter loop cooldowns set after cast cooldowns reduced after 1 complete cast diff --git a/core/src/construct.rs b/core/src/construct.rs index 2377252c..abab88e2 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -435,9 +435,13 @@ impl Construct { } pub fn skill_set_cd(&mut self, skill: Skill) -> &mut Construct { - let i = self.skills.iter().position(|s| s.skill == skill).unwrap(); - self.skills.remove(i); - self.skills.push(ConstructSkill::new(skill)); + // tests force resolve some skills + // which cause the game to attempt to put them on cd + // even though the construct doesn't know the skill + if let Some(i) = self.skills.iter().position(|s| s.skill == skill) { + self.skills.remove(i); + self.skills.push(ConstructSkill::new(skill)); + } self } diff --git a/core/src/game.rs b/core/src/game.rs index b45fafc8..dd80a286 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -579,7 +579,10 @@ impl Game { let casts = match event { Event::Damage { construct, colour: _, amount: _, mitigation: _, display: _ } => self.construct_by_id(construct).unwrap().damage_trigger_casts(&cast, &event), - // Event::Cast {} => set_cooldown() + Event::Cast { construct, skill, player: _, target: _, direction: _ } => { + self.construct_by_id(construct).unwrap().skill_set_cd(skill); + vec![] + } Event::Ko { construct } => self.construct_by_id(construct).unwrap().on_ko(&cast, &event), _ => vec![], @@ -719,25 +722,26 @@ impl Game { fn progress_durations(&mut self) -> &mut Game { let last = self.resolutions.len() - 1; + + let casters = self.resolutions[last].iter() + .filter_map(|r| match r.event { + Event::Cast { construct: caster, player: _, direction: _, skill, target: _ } => + match skill.base_cd().is_some() { + true => Some(caster), + false => None, + }, + _ => None, + }) + .collect::>(); + for player in self.players.iter_mut() { for construct in player.constructs.iter_mut() { if construct.is_ko() { continue; } - let cooldown = self.resolutions[last].iter() - .find_map(|r| match r.event { - Event::Cast { construct: caster, player: _, direction: _, skill, target: _ } => - match caster == construct.id && skill.base_cd().is_some() { - true => Some(r.skill), - false => None, - }, - _ => None, - }); - - if let Some(skill) = cooldown { - construct.skill_set_cd(skill); - } else { + // cooldowns are set at the end of a resolution + if !casters.contains(&construct.id) { construct.reduce_cooldowns(); };