From 6e3675364e4ac6348b7382eabfdbe5568045ead5 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 23 Jan 2020 16:23:25 +1000 Subject: [PATCH] tick effect matching reimpl --- WORKLOG.md | 3 + bin/deploy.sh | 3 - core/src/construct.rs | 15 +++-- core/src/game.rs | 137 +++++++++++++++++------------------------- core/src/skill.rs | 19 ++++-- server/src/lib.rs | 1 + 6 files changed, 85 insertions(+), 93 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index f504676b..1db71156 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -5,6 +5,9 @@ _ntr_ * can't reset password without knowing password =\ * hard reload client on version change +electrify on death / stun +siphon stack removed check + * audio * animation effects * vbox combine / buy / equip etc diff --git a/bin/deploy.sh b/bin/deploy.sh index dcf11a59..41ae49c3 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -27,6 +27,3 @@ ssh -q "$TARGET" ls -lah "$CLIENT_DIST_DIR" echo "restarting mnml service" ssh -q -t "$TARGET" sudo service mnml restart && sleep 1 && systemctl --no-pager status mnml - -echo "restarting nginx service" -ssh -q -t "$TARGET" sudo service nginx restart && sleep 1 && systemctl --no-pager status nginx diff --git a/core/src/construct.rs b/core/src/construct.rs index 16572a8b..b759b303 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -65,7 +65,7 @@ impl ConstructSkill { #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum EffectMeta { CastOnHit(Skill), // maybe needs source/target - CastTick { source: Uuid, target: Uuid, skill: Skill, speed: usize, amount: usize }, + CastTick { source: Uuid, target: Uuid, skill: Skill, speed: usize, amount: usize, id: Uuid }, AddedDamage(usize), Multiplier(usize), } @@ -100,12 +100,19 @@ impl ConstructEffect { pub fn get_skill(&self) -> Option { match self.meta { - Some(EffectMeta::CastTick { source: _, target: _, skill, speed: _, amount: _ }) => Some(skill), + Some(EffectMeta::CastTick { source: _, target: _, skill, speed: _, amount: _, id: _ }) => Some(skill), Some(EffectMeta::CastOnHit(s)) => Some(s), _ => None, } - } + + pub fn get_tick_id(&self) -> Option { + match self.meta { + Some(EffectMeta::CastTick { source: _, target: _, skill: _, speed: _, amount: _, id }) => Some(id), + _ => None, + } + } + } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] @@ -561,7 +568,7 @@ impl Construct { fn tick_damage(&self, effect: Effect) -> usize { match self.effects.iter().find_map(|ce| match ce.effect == effect { true => match ce.meta { - Some(EffectMeta::CastTick { source: _, target: _, skill: _, speed: _, amount }) => Some(amount), + Some(EffectMeta::CastTick { source: _, target: _, skill: _, speed: _, amount, id: _ }) => Some(amount), _ => None, }, false => None, diff --git a/core/src/game.rs b/core/src/game.rs index 5364013b..12c3bfc5 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -428,8 +428,12 @@ impl Game { .cloned() .filter_map(|e| e.meta) .filter_map(move |m| match m { - EffectMeta::CastTick { source, target, skill, speed, amount: _ } => - Some(Cast::new(source, c.account, target, skill).set_speed(speed)), + EffectMeta::CastTick { source, target, skill, speed, amount: _, id } => + Some( + Cast::new(source, c.account, target, skill) + .set_speed(speed) + .set_id(id) + ), _ => None, }) ) @@ -506,6 +510,20 @@ impl Game { fn resolve(&mut self, cast: Cast) -> &mut Game { if self.finished() { return self } + // match tick skills with the effect on the target + // if no match is found the effect must have been removed during this turn + // and the skill should no longer resolve + if cast.skill.is_tick() { + let effect_match = self.construct(cast.target).effects.iter() + .filter_map(|ce| ce.get_tick_id()) + .find(|id| cast.id == *id) + .is_some(); + + if !effect_match { + return self; + } + } + // If the skill is disabled for source nothing else will happen if let Some(effects) = self.construct(cast.source).disabled(cast.skill) { self.add_resolution(&cast, &Event::Disable { construct: cast.source, effects }); @@ -1054,6 +1072,7 @@ mod tests { .learn(Skill::Block) .learn(Skill::Counter) .learn(Skill::Siphon) + .learn(Skill::Purify) .learn(Skill::Amplify) .learn(Skill::Stun) .learn(Skill::Ruin) @@ -1069,6 +1088,7 @@ mod tests { .learn(Skill::Block) .learn(Skill::Counter) .learn(Skill::Siphon) + .learn(Skill::Purify) .learn(Skill::Amplify) .learn(Skill::Stun) .learn(Skill::Block); @@ -1874,85 +1894,6 @@ mod tests { return; } - // #[test] - // fn tick_removal_test() { - // let mut game = create_test_game(); - - // let x_player = game.players[0].clone(); - // let y_player = game.players[1].clone(); - - // let x_construct = x_player.constructs[0].clone(); - // let y_construct = y_player.constructs[0].clone(); - - // // make the purify construct super fast so it beats out decay - // game.construct_by_id(y_construct.id).unwrap().speed.force(10000000); - - // game.construct_by_id(x_construct.id).unwrap().learn_mut(Skill::Decay); - // while game.construct_by_id(x_construct.id).unwrap().skill_on_cd(Skill::Decay).is_some() { - // game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); - // } - - // game.construct_by_id(x_construct.id).unwrap().learn_mut(Skill::Siphon); - // while game.construct_by_id(x_construct.id).unwrap().skill_on_cd(Skill::Siphon).is_some() { - // game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); - // } - - // game.construct_by_id(y_construct.id).unwrap().learn_mut(Skill::Purify); - // while game.construct_by_id(y_construct.id).unwrap().skill_on_cd(Skill::Purify).is_some() { - // game.construct_by_id(y_construct.id).unwrap().reduce_cooldowns(); - // } - - // // apply buff - // game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Decay).unwrap(); - // game.player_ready(x_player.id).unwrap(); - // game.player_ready(y_player.id).unwrap(); - // game = game.resolve_phase_start(); - // assert!(game.construct_by_id(y_construct.id).unwrap().affected(Effect::Decay)); - - // let Resolution { source: _, target: _, Resolution, stages: _ } = game.Resolutions.last().unwrap().pop().unwrap(); - // match Resolution { - // Resolution::Damage { amount: _, skill, mitigation: _, colour: _ } => assert_eq!(skill, Skill::DecayTick), - // _ => panic!("not decay"), - // }; - - // game.Resolutions.clear(); - - // // remove - // game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap(); - // game.player_ready(x_player.id).unwrap(); - // game.player_ready(y_player.id).unwrap(); - // game = game.resolve_phase_start(); - - // while let Some(Resolution { source: _, target: _, Resolution, stages: _ }) = game.Resolutions.last().unwrap().pop() { - // match Resolution { - // Resolution::Damage { amount: _, skill: _, mitigation: _, colour: _ } => - // panic!("{:?} damage Resolution", Resolution), - // _ => (), - // } - // }; - - // game.add_skill(y_player.id, x_construct.id, y_construct.id, Skill::Siphon).unwrap(); - // game.player_ready(x_player.id).unwrap(); - // game.player_ready(y_player.id).unwrap(); - // game = game.resolve_phase_start(); - - // game.Resolutions.clear(); - - // game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap(); - // game.player_ready(x_player.id).unwrap(); - // game.player_ready(y_player.id).unwrap(); - // game = game.resolve_phase_start(); - - // while let Some(Resolution { source: _, target: _, Resolution, stages: _ }) = game.Resolutions.last().unwrap().pop() { - // match Resolution { - // Resolution::Damage { amount: _, skill: _, mitigation: _, colour: _ } => - // panic!("{:#?} {:#?} damage Resolution", game.Resolutions, Resolution), - // _ => (), - // } - // }; - - // } - #[test] fn upkeep_test() { let mut game = create_2v2_test_game(); @@ -2524,4 +2465,38 @@ mod tests { assert_eq!(siphon_tick_dmg, siphon_dmg); assert_eq!(siphon_tick_speed, siphon_speed); } + + #[test] + fn tick_removal_test() { + let mut game = create_test_game(); + let player_id = game.players[0].id; + let opponent_id = game.players[1].id; + let source = game.players[0].constructs[0].id; + let target = game.players[1].constructs[0].id; + + game.add_skill(player_id, source, target, Skill::Siphon).unwrap(); + + game.player_ready(player_id).unwrap(); + game.player_ready(opponent_id).unwrap(); + + game = game.resolve_phase_start(); + + game.add_skill(player_id, source, target, Skill::Purify).unwrap(); + + game.player_ready(player_id).unwrap(); + game.player_ready(opponent_id).unwrap(); + + game = game.resolve_phase_start(); + + // println!("{:#?}", game.resolutions); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + // There should be no damage events on the target + assert!(resolutions.iter().any(|r| match r.event { + Event::Damage { construct: _, colour: _, amount: _, mitigation: _, display: _ } => true, + _ => false, + }) == false); + } } diff --git a/core/src/skill.rs b/core/src/skill.rs index 765b6930..5cdb1076 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -41,6 +41,15 @@ impl Cast { } } + // used for ticks to match + // a cast with an effect + pub fn set_id(self, id: Uuid) -> Cast { + Cast { + id, + ..self + } + } + pub fn resolve(self, game: &mut Game) { match self.skill { Skill::Attack => attack(self, game, Attack::Base), @@ -1134,7 +1143,7 @@ fn siphon(cast: Cast, game: &mut Game, values: Siphon) { Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Siphon, duration: values.duration(), meta: - Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::SiphonTick, speed: cast.speed, amount }) }, + Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::SiphonTick, speed: cast.speed, amount }) }, } ); @@ -1729,7 +1738,7 @@ fn decay(cast: Cast, game: &mut Game, values: Decay) { Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Decay, duration: values.decay_duration(), meta: - Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::DecayTick, speed: cast.speed, amount }) }, + Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::DecayTick, speed: cast.speed, amount }) }, } ); @@ -1837,10 +1846,10 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Electrocute, duration: values.duration(), meta: - Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, + Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, }, ); - + if !game.affected(cast.target, Effect::Electrocuted) { game.action(cast, Action::Damage { @@ -2362,7 +2371,7 @@ fn triage(cast: Cast, game: &mut Game, values: Triage) { Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Triage, duration: values.duration(), meta: - Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::TriageTick, speed: cast.speed, amount }) }, + Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::TriageTick, speed: cast.speed, amount }) }, } ); diff --git a/server/src/lib.rs b/server/src/lib.rs index b8e9060c..0d955a53 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -109,6 +109,7 @@ pub fn start() { #[cfg(unix)] setup_logger().unwrap(); dotenv::from_path(Path::new("/etc/mnml/gs.conf")).ok(); + info!("starting server"); let pool = pg::create_pool(); let http_pool = pool.clone();