diff --git a/server/src/cryp.rs b/server/src/cryp.rs index c8d4cefd..0dae62e0 100644 --- a/server/src/cryp.rs +++ b/server/src/cryp.rs @@ -297,16 +297,8 @@ impl Cryp { self.available_skills().len() == 0 } - pub fn is_inverted(&self) -> bool { - self.effects.iter().any(|s| s.effect == Effect::Invert) - } - - pub fn is_reflecting(&self) -> bool { - self.effects.iter().any(|s| s.effect == Effect::Reflect) - } - - pub fn is_clutch(&self) -> bool { - self.effects.iter().any(|s| s.effect == Effect::Clutch) + pub fn affected(&self, effect: Effect) -> bool { + self.effects.iter().any(|s| s.effect == effect) } pub fn available_skills(&self) -> Vec<&CrypSkill> { @@ -443,7 +435,7 @@ impl Cryp { fn reduce_hp(&mut self, amount: u64) { self.hp.reduce(amount); - if self.is_clutch() && self.hp() == 0 { + if self.affected(Effect::Clutch) && self.hp() == 0 { self.hp.value = 1; } } @@ -480,7 +472,7 @@ impl Cryp { let modified_healing = healing_mods.iter().fold(amount, |acc, m| m.apply(acc)); - match self.is_inverted() { + match self.affected(Effect::Invert) { false => { let current_hp = self.hp(); self.hp.increase(modified_healing); @@ -526,7 +518,7 @@ impl Cryp { let modified_damage = red_damage_mods.iter().fold(amount, |acc, m| m.apply(acc)); - match self.is_inverted() { + match self.affected(Effect::Invert) { false => { // calculate amount of damage red_shield will not absorb // eg 50 red_shield 25 damage -> 0 remainder 25 mitigation @@ -585,7 +577,7 @@ impl Cryp { // println!("{:?}", blue_damage_mods); let modified_damage = blue_damage_mods.iter().fold(amount, |acc, m| m.apply(acc)); - match self.is_inverted() { + match self.affected(Effect::Invert) { false => { let remainder = modified_damage.saturating_sub(self.blue_shield.value); let mitigation = modified_damage.saturating_sub(remainder); diff --git a/server/src/game.rs b/server/src/game.rs index 9175dd9f..bc690b5d 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -48,6 +48,11 @@ impl Team { return required; } + fn taunting(&self) -> Option<&Cryp> { + self.cryps.iter() + .find(|c| c.affected(Effect::Taunt)) + } + pub fn set_cryps(&mut self, mut cryps: Vec) -> &mut Team { cryps.sort_unstable_by_key(|c| c.id); self.cryps = cryps; @@ -378,13 +383,11 @@ impl Game { } fn get_targets(&self, skill: Skill, source: &Cryp, target_cryp_id: Uuid) -> Vec { - // match self.teams.iter_mut().find(|t| t.cryps.iter().any(|c| c.id == id)) { - // Some(team) => team.cryps.iter_mut().find(|c| c.id == id), - // None => None, - // } + let target_team = self.teams.iter().find(|t| t.id == source.account).unwrap(); - // let target_team = self.teams.iter_mut().find(|t| t.cryps.iter().any(|c| c.id == id)).unwrap(); - // let target = team.cryps.iter_mut().find(|c| c.id == id).unwrap(); + if let Some(t) = target_team.taunting() { + return vec![t.id]; + } match source.skill_is_aoe(skill) { true => self.cryp_aoe_targets(target_cryp_id), @@ -882,7 +885,7 @@ mod tests { use cryp::*; fn create_test_game() -> Game { - let x = Cryp::new() + let mut x = Cryp::new() .named(&"pronounced \"creeep\"".to_string()) .learn(Skill::Attack) .learn(Skill::TestStun) @@ -894,7 +897,7 @@ mod tests { .learn(Skill::Stun) .learn(Skill::Block); - let y = Cryp::new() + let mut y = Cryp::new() .named(&"lemongrass tea".to_string()) .learn(Skill::Attack) .learn(Skill::TestStun) @@ -913,11 +916,13 @@ mod tests { .set_team_size(1); let x_team_id = Uuid::new_v4(); + x.account = x_team_id; let mut x_team = Team::new(x_team_id); x_team .set_cryps(vec![x]); let y_team_id = Uuid::new_v4(); + y.account = y_team_id; let mut y_team = Team::new(y_team_id); y_team .set_cryps(vec![y]); @@ -932,22 +937,22 @@ mod tests { } fn create_2v2_test_game() -> Game { - let i = Cryp::new() + let mut i = Cryp::new() .named(&"pretaliate".to_string()) .learn(Skill::Attack) .learn(Skill::TestTouch); - let j = Cryp::new() + let mut j = Cryp::new() .named(&"poy sian".to_string()) .learn(Skill::Attack) .learn(Skill::TestTouch); - let x = Cryp::new() + let mut x = Cryp::new() .named(&"pronounced \"creeep\"".to_string()) .learn(Skill::Attack) .learn(Skill::TestTouch); - let y = Cryp::new() + let mut y = Cryp::new() .named(&"lemongrass tea".to_string()) .learn(Skill::Attack) .learn(Skill::TestTouch); @@ -959,11 +964,15 @@ mod tests { .set_team_size(2); let i_team_id = Uuid::new_v4(); + i.account = i_team_id; + j.account = i_team_id; let mut i_team = Team::new(i_team_id); i_team .set_cryps(vec![i,j]); let x_team_id = Uuid::new_v4(); + x.account = x_team_id; + y.account = x_team_id; let mut x_team = Team::new(x_team_id); x_team .set_cryps(vec![x,y]); @@ -1131,14 +1140,59 @@ mod tests { assert!(game.skill_phase_finished()); game = game.resolve_phase_start(); - assert!(game.resolved.len() == 2); - let Resolution { source: _, target: _, event } = game.resolved.pop().unwrap(); - match event { - Event::Effect { effect, duration } => { - assert!(effect == Effect::Ruin); - assert!(duration == 1); + let ruins = game.resolved + .into_iter() + .filter(|r| { + let Resolution { source, target: _, event } = r; + match source.id == x_cryp.id { + true => match event { + Event::Effect { effect, duration } => { + assert!(*effect == Effect::Ruin); + assert!(*duration == 1); + true + } + _ => panic!("ruin result not effect {:?}", event), + } + false => false, + } + }) + .count(); + + assert!(ruins == 2); + } + + #[test] + fn taunt_test() { + let mut game = create_2v2_test_game(); + + let i_team = game.teams[0].clone(); + let x_team = game.teams[1].clone(); + + let i_cryp = i_team.cryps[0].clone(); + let j_cryp = i_team.cryps[1].clone(); + let x_cryp = x_team.cryps[0].clone(); + let y_cryp = x_team.cryps[1].clone(); + + game.cryp_by_id(x_cryp.id).unwrap().learn_mut(Skill::Taunt); + + while game.cryp_by_id(x_cryp.id).unwrap().skill_on_cd(Skill::Taunt).is_some() { + game.cryp_by_id(x_cryp.id).unwrap().reduce_cooldowns(); + } + + game.add_skill(i_team.id, i_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); + game.add_skill(i_team.id, j_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); + game.add_skill(x_team.id, x_cryp.id, Some(i_cryp.id), Skill::Taunt).unwrap(); + game.add_skill(x_team.id, y_cryp.id, Some(i_cryp.id), Skill::TestTouch).unwrap(); + + assert!(game.skill_phase_finished()); + game = game.resolve_phase_start(); + + assert!(game.resolved.len() == 4); + while let Some(r) = game.resolved.pop() { + let Resolution { source , target, event: _ } = r; + if [i_cryp.id, j_cryp.id].contains(&source.id) { + assert!(target.id == x_cryp.id); } - _ => panic!("ruin result not effect"), } } diff --git a/server/src/skill.rs b/server/src/skill.rs index 5bce31f5..4aa38627 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -109,6 +109,7 @@ pub enum Effect { Reflect, Empower, + Taunt, Invert, Strangle, @@ -242,6 +243,7 @@ impl Effect { Effect::Blind => Category::RedDebuff, Effect::Snare => Category::RedDebuff, Effect::Clutch => Category::RedBuff, + Effect::Taunt => Category::RedBuff, Effect::Empower => Category::RedBuff, Effect::Strangle => Category::RedDebuff, Effect::Strangling => Category::RedBuff, @@ -291,6 +293,7 @@ impl Effect { Effect::Vulnerable => 2, Effect::Snare => 2, + Effect::Taunt => 1, Effect::Empower => 2, Effect::Invert => 1, @@ -531,7 +534,7 @@ impl Skill { Skill::Reflect => Category::Blue, Skill::Ruin => Category::Blue, Skill::Slay => Category::Blue, - Skill::Taunt => Category::Blue, + Skill::Taunt => Category::Red, Skill::Toxic => Category::Blue, @@ -600,9 +603,9 @@ impl Skill { return results; } - if target.is_reflecting() { + if target.affected(Effect::Reflect) { // guard against overflow - if source.is_reflecting() { + if source.affected(Effect::Reflect) { return results; } return self.resolve(target, source); @@ -667,13 +670,13 @@ impl Skill { Skill::Reflect => reflect(source, target, results), Skill::Ruin => ruin(source, target, results), Skill::Slay => unimplemented!(), - Skill::Taunt => unimplemented!(), + Skill::Taunt => taunt(source, target, results), Skill::Toxic => unimplemented!(), // ----------------- // Test // ----------------- - Skill::TestTouch => results, + Skill::TestTouch => touch(source, target, results), Skill::TestStun => stun(source, target, results), Skill::TestBlock => block(source, target, results), Skill::TestParry => parry(source, target, results), @@ -705,6 +708,11 @@ impl Skill { } } +fn touch(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Resolutions { + results.push(Resolution::new(source, target).event(target.deal_red_damage(Skill::TestTouch, 0))); + return results; +} + fn attack(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Resolutions { let amount = source.red_damage(); results.push(Resolution::new(source, target).event(target.deal_red_damage(Skill::Attack, amount))); @@ -723,6 +731,12 @@ fn clutch(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Res return results; } +fn taunt(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Resolutions { + let effect = CrypEffect { effect: Effect::Taunt, duration: Effect::Taunt.duration(), tick: None }; + results.push(Resolution::new(source, target).event(target.add_effect(Skill::Taunt, effect))); + return results; +} + fn throw(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Resolutions { let stun = CrypEffect { effect: Effect::Stun, duration: Effect::Stun.duration(), tick: None }; let vulnerable = CrypEffect { effect: Effect::Vulnerable, duration: Effect::Vulnerable.duration(), tick: None }; @@ -1028,7 +1042,7 @@ mod tests { x.red_damage.force(u64::max_value()); clutch(&mut y.clone(), &mut y, vec![]); - assert!(y.is_clutch()); + assert!(y.affected(Effect::Clutch)); let mut results = attack(&mut x, &mut y, vec![]); assert!(y.hp() == 1); @@ -1054,7 +1068,7 @@ mod tests { x.red_damage.force(256 + 64); invert(&mut y.clone(), &mut y, vec![]); - assert!(y.is_inverted()); + assert!(y.affected(Effect::Invert)); // heal should deal green damage heal(&mut x, &mut y, vec![]); @@ -1080,7 +1094,7 @@ mod tests { .named(&"camel".to_string()); reflect(&mut y.clone(), &mut y, vec![]); - assert!(y.is_reflecting()); + assert!(y.affected(Effect::Reflect)); let mut results = Skill::Attack.resolve(&mut x, &mut y); diff --git a/server/src/vbox.rs b/server/src/vbox.rs index ed7534d0..d34d964d 100644 --- a/server/src/vbox.rs +++ b/server/src/vbox.rs @@ -204,7 +204,7 @@ impl Var { Var::Strangle => Some(Skill::Strangle), Var::Strike => Some(Skill::Strike), Var::Clutch => Some(Skill::Clutch), - // Var::Taunt => Some(Skill::Taunt), + Var::Taunt => Some(Skill::Taunt), Var::Throw => Some(Skill::Throw), // Var::Toxic => Some(Skill::Toxic), Var::Triage => Some(Skill::Triage), @@ -252,6 +252,7 @@ impl From for Var { Skill::Blast => Var::Blast, Skill::Block => Var::Block, Skill::Curse => Var::Curse, + Skill::Decay => Var::Decay, Skill::Empower => Var::Empower, Skill::Haste => Var::Haste, Skill::Heal => Var::Heal, @@ -260,20 +261,20 @@ impl From for Var { Skill::Parry => Var::Parry, Skill::Purge => Var::Purge, Skill::Purify => Var::Purify, + Skill::Recharge => Var::Recharge, + Skill::Reflect => Var::Reflect, + Skill::Ruin => Var::Ruin, Skill::Shield => Var::Shield, Skill::Silence => Var::Silence, Skill::Siphon => Var::Siphon, Skill::Slow => Var::Slow, Skill::Snare => Var::Snare, - Skill::Strike => Var::Strike, Skill::Strangle => Var::Strangle, + Skill::Strike => Var::Strike, Skill::Stun => Var::Stun, + Skill::Taunt => Var::Taunt, Skill::Throw => Var::Throw, Skill::Triage => Var::Triage, - Skill::Decay => Var::Decay, - Skill::Reflect => Var::Reflect, - Skill::Recharge => Var::Recharge, - Skill::Ruin => Var::Ruin, Skill::TestTouch => Var::TestTouch, Skill::TestStun => Var::TestStun,