use rand::{thread_rng, Rng}; use uuid::Uuid; use game::{Log}; use cryp::{Cryp, CrypEffect, Stat}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub struct Cast { pub id: Uuid, pub skill: Skill, pub source_team_id: Uuid, pub source_cryp_id: Uuid, pub target_cryp_id: Option, pub target_team_id: Uuid, } impl Cast { pub fn new(source_cryp_id: Uuid, source_team_id: Uuid, target_team_id: Option, skill: Skill) -> Cast { let (target_cryp_id, target_team_id) = match skill.self_targeting() { true => (Some(source_cryp_id), source_team_id), false => (None, target_team_id.unwrap()) }; return Cast { id: Uuid::new_v4(), source_cryp_id, source_team_id, target_cryp_id, target_team_id, skill, }; } pub fn new_tick(source: &mut Cryp, target: &mut Cryp, skill: Skill) -> Cast { let mut cast = Cast::new(source.id, source.account, Some(target.account), skill); cast.set_target(target.id); return cast; } pub fn set_resolution(&mut self, cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) -> &mut Cast { self.skill.resolve(cryp, target, log); self } pub fn set_target(&mut self, cryp_id: Uuid) -> &mut Cast { self.target_cryp_id = Some(cryp_id); self } pub fn used_cooldown(&self) -> bool { return self.skill.cd().is_some(); } } #[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] pub struct Resolution { pub base: u64, pub result: Option, } pub type Cooldown = Option; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Effect { // physical Stun, Block, Bleed, Leech, Airborne, Untouchable, Deadly, Vulnerable, Fury, Evasion, Blind, Snare, Empower, // magic Hex, Curse, Banish, Slow, Haste, Enslave, Mesmerise, Amplify, Silence, // magic immunity Shield, // effects over time Triage, Decay, Regen, Drain, SpeedDrain, SpeedIncrease, } impl Effect { pub fn immune(&self, skill: Skill) -> bool { match self { Effect::Block => match skill { Skill::Stun | Skill::TestStun | Skill::Attack => true, _ => false, }, Effect::Shield => match skill.cast_type() { Damage::Magic => true, Damage::Physical => false, } _ => false, } } pub fn prevents_casting(&self, skill: Skill) -> bool { match self { Effect::Stun => true, Effect::Silence => match skill.cast_type() { Damage::Magic => true, Damage::Physical => false, }, _ => false, } } pub fn modifications(&self) -> Vec { match self { Effect::Amplify => vec![Stat::SpellDmg], Effect::Empower => vec![Stat::PhysDmg], _ => vec![], } } // maybe increase by rng // roll little endian bits // and OR with base stat pub fn apply(&self, value: u64) -> u64 { match self { Effect::Amplify => value << 1, Effect::Empower => value << 1, _ => panic!("{:?} does not have a mod effect", self), } } pub fn source(&self) -> Source { match self { // physical Effect::Stun => Source::Debuff, Effect::Block => Source::Buff, Effect::Bleed => Source::Debuff, Effect::Leech => Source::Debuff, Effect::Airborne => Source::Buff, Effect::Untouchable => Source::Buff, Effect::Deadly => Source::Buff, Effect::Vulnerable => Source::Debuff, Effect::Fury => Source::Buff, Effect::Evasion => Source::Buff, Effect::Blind => Source::Debuff, Effect::Snare => Source::Debuff, Effect::Empower => Source::Buff, // magic Effect::Hex => Source::Debuff, Effect::Curse => Source::Debuff, Effect::Banish => Source::Debuff, // todo randomise Effect::Slow => Source::Debuff, Effect::Haste => Source::Buff, Effect::Enslave => Source::Debuff, Effect::Mesmerise => Source::Debuff, Effect::Amplify => Source::Buff, Effect::Silence => Source::Debuff, // magic immunity Effect::Shield => Source::Buff, // effects over time Effect::Triage => Source::Buff, Effect::Decay => Source::Debuff, Effect::Regen => Source::Buff, Effect::Drain => Source::Debuff, Effect::SpeedDrain => Source::Debuff, Effect::SpeedIncrease => Source::Buff, } } } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Damage { Physical, Magic, } // #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] // enum Style { // Offensive, // Defensive, // } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Source { Buff, Debuff, Stat, } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Skill { Attack, // ----------------- // Nature // ----------------- Block, // reduce dmg Parry, // avoid all dmg Snare, Paralyse, Strangle, // physical dot and disable Stun, Evade, // actively evade Evasion, // adds evasion to cryp // ----------------- // Technology // ----------------- Replicate, Swarm, Orbit, Repair, Scan, // track? // ----------------- // Nonviolence // ----------------- Heal, Triage, // hot TriageTick, Throw, // no dmg stun, adds vulnerable Charm, Calm, Rez, // ------------------- // Destruction // ------------------- Blast, Amplify, Decay, // dot DecayTick, // dot Drain, DrainTick, Curse, Plague, // aoe dot Ruin, // aoe // ----------------- // Purity // ----------------- Empower, Slay, Shield, Silence, Inquiry, Purify, Purge, // Precision, // ----------------- // Chaos // ----------------- Banish, Hex, Fear, Taunt, Pause, // speed slow // used by tests, no cd, no dmg TestTouch, TestStun, TestBlock, TestDrain, } impl Skill { pub fn cd(&self) -> Cooldown { match self { Skill::Attack => None, // ----------------- // Nature // ----------------- Skill::Block => Some(1), // reduce dmg Skill::Parry => Some(1), // avoid all dmg Skill::Snare => Some(2), Skill::Paralyse => Some(3), Skill::Strangle => Some(3), // Strangle Skill::Stun => Some(1), Skill::Evade => Some(2), Skill::Evasion => Some(3), // additional layer of dmg avoidance // ----------------- // Technology // ----------------- Skill::Replicate => Some(1), Skill::Swarm => Some(3), Skill::Orbit => Some(2), Skill::Repair => Some(1), Skill::Scan => Some(2), // track? // ----------------- // Preservation // ----------------- Skill::Heal => Some(1), Skill::Triage => Some(1), // hot Skill::TriageTick => None, Skill::Throw => Some(2), // no dmg stun, adds vulnerable Skill::Charm => Some(2), Skill::Calm => Some(2), Skill::Rez => Some(4), // ----------------- // Destruction // ----------------- Skill::Blast => Some(1), Skill::Amplify => Some(2), Skill::Decay => Some(1), // dot Skill::DecayTick => None, Skill::Drain => Some(2), Skill::DrainTick => None, Skill::Curse => Some(2), Skill::Plague => Some(2), // aoe dot Skill::Ruin => Some(3), // aoe // ----------------- // Purity // ----------------- // Skill::Precision => Some(1), Skill::Empower => Some(2), Skill::Slay => Some(1), Skill::Shield => Some(1), Skill::Silence => Some(2), Skill::Inquiry => Some(2), Skill::Purify => Some(1), Skill::Purge => Some(1), // ----------------- // Chaos // ----------------- Skill::Banish => Some(2), Skill::Hex => Some(1), Skill::Fear => Some(1), Skill::Taunt => Some(2), Skill::Pause => Some(2), // speed slow // ----------------- // Test // ----------------- Skill::TestTouch => None, Skill::TestStun => None, Skill::TestBlock => None, Skill::TestDrain => None, } } pub fn cast_type(&self) -> Damage { match self { Skill::Attack => Damage::Physical, // ----------------- // Nature // ----------------- Skill::Block => Damage::Physical, // reduce dmg Skill::Evade => Damage::Physical, Skill::Parry => Damage::Physical, // avoid all dmg Skill::Snare => Damage::Physical, Skill::Paralyse => Damage::Physical, Skill::Strangle => Damage::Physical, // Strangle Skill::Stun => Damage::Physical, Skill::Evasion => Damage::Physical, // additional layer of dmg avoidance // ----------------- // Technology // ----------------- Skill::Replicate => Damage::Physical, Skill::Swarm => Damage::Physical, Skill::Orbit => Damage::Physical, Skill::Repair => Damage::Physical, Skill::Scan => Damage::Physical, // track? // ----------------- // Preservation // ----------------- Skill::Heal => Damage::Physical, Skill::Triage => Damage::Physical, // hot Skill::TriageTick => Damage::Physical, // hot Skill::Throw => Damage::Physical, // no dmg stun, adds vulnerable Skill::Charm => Damage::Physical, Skill::Calm => Damage::Physical, Skill::Rez => Damage::Physical, // ----------------- // Destruction // ----------------- Skill::Blast => Damage::Magic, Skill::Amplify => Damage::Magic, Skill::Decay => Damage::Magic, // dot Skill::DecayTick => Damage::Magic, // hot Skill::Drain => Damage::Magic, Skill::DrainTick => Damage::Magic, // hot Skill::Curse => Damage::Magic, Skill::Plague => Damage::Magic, // aoe dot Skill::Ruin => Damage::Magic, // aoe // ----------------- // Purity // ----------------- // Skill::Precision => 1, Skill::Empower => Damage::Physical, Skill::Slay => Damage::Physical, Skill::Shield => Damage::Magic, Skill::Silence => Damage::Magic, Skill::Inquiry => Damage::Magic, Skill::Purify => Damage::Magic, Skill::Purge => Damage::Magic, // ----------------- // Chaos // ----------------- Skill::Banish => Damage::Magic, Skill::Hex => Damage::Magic, Skill::Fear => Damage::Magic, Skill::Taunt => Damage::Magic, Skill::Pause => Damage::Magic, // extend durations // Skill::Lag => 2, // // ----------------- // Test // ----------------- Skill::TestTouch => Damage::Physical, Skill::TestStun => Damage::Physical, Skill::TestBlock => Damage::Physical, Skill::TestDrain => Damage::Magic, } } pub fn speed(&self) -> u8 { match self { Skill::Attack => 5, // ----------------- // Nature // ----------------- Skill::Block => 10, // reduce dmg Skill::Evade => 10, Skill::Parry => 10, // avoid all dmg Skill::Snare => 10, Skill::Paralyse => 5, Skill::Strangle => 5, // Strangle Skill::Stun => 5, Skill::Evasion => 3, // additional layer of dmg avoidance // ----------------- // Technology // ----------------- Skill::Replicate => 1, Skill::Swarm => 3, Skill::Orbit => 2, Skill::Repair => 1, Skill::Scan => 2, // track? // ----------------- // Preservation // ----------------- Skill::Heal => 1, Skill::Triage => 1, // hot Skill::TriageTick => 1, // hot Skill::Throw => 2, // no dmg stun, adds vulnerable Skill::Charm => 2, Skill::Calm => 2, Skill::Rez => 4, // ----------------- // Destruction // ----------------- Skill::Blast => 1, Skill::Amplify => 2, Skill::Decay => 1, // dot Skill::DecayTick => 2, // hot Skill::Drain => 2, Skill::DrainTick => 2, // hot Skill::Curse => 2, Skill::Plague => 2, // aoe dot Skill::Ruin => 3, // aoe // ----------------- // Purity // ----------------- // Skill::Precision => 1, Skill::Empower => 2, Skill::Slay => 1, Skill::Shield => 1, Skill::Silence => 2, Skill::Inquiry => 2, Skill::Purify => 1, Skill::Purge => 1, // ----------------- // Chaos // ----------------- Skill::Banish => 2, Skill::Hex => 1, Skill::Fear => 1, Skill::Taunt => 2, Skill::Pause => 2, // extend durations // Skill::Lag => 2, // // ----------------- // Test // ----------------- Skill::TestTouch => 10, Skill::TestStun => 5, Skill::TestBlock => 10, Skill::TestDrain => 10, } } pub fn resolve(&self, cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let mut rng = thread_rng(); let base: u64 = rng.gen(); // let res = Resolution { base, result: None }; // println!("{:?}'s stats", self.name); // println!("{:064b} <- finalised", roll.result); // roll.result = roll.result & stat(); // println!("{:064b} & <- attribute roll", stat()); // println!("{:064b} = {:?}", roll.result, roll.result); // println!(""); // return Some(roll); let (immune, reason) = target.immune(*self); if immune { log.push(format!("{:?} -> {:?} | {:?} immune: {:?}", cryp.name, target.name, self, reason)); return; } match self { Skill::Attack => attack(cryp, target, log), // ----------------- // Nature // ----------------- Skill::Block => block(cryp, target, log), Skill::Evade => panic!("nyi"), // Skill::Parry => panic!("nyi"), // avoid all dmg Skill::Snare => snare(cryp, target, log), // TODO prevent physical moves Skill::Paralyse => panic!("nyi"), // no physical moves Skill::Strangle => panic!("nyi"), // no physical moves Skill::Stun => stun(cryp, target, log), Skill::Evasion => panic!("nyi"), // additional layer of dmg avoidance // ----------------- // Technology // ----------------- Skill::Replicate => panic!("nyi"), Skill::Swarm => panic!("nyi"), Skill::Orbit => panic!("nyi"), Skill::Repair => panic!("nyi"), Skill::Scan => panic!("nyi"), // track? // ----------------- // Preservation // ----------------- Skill::Heal => heal(cryp, target, log), Skill::Triage => triage(cryp, target, log), // hot Skill::TriageTick => triage_tick(cryp, target, log), // hot Skill::Throw => throw(cryp, target, log), // no dmg stun, adds vulnerable Skill::Charm => panic!("nyi"), // target casts random spell on teammate Skill::Calm => panic!("nyi"), // physical fear, taunt removal Skill::Rez => panic!("nyi"), // ----------------- // Destruction // ----------------- Skill::Blast => blast(cryp, target, log), Skill::Amplify => amplify(cryp, target, log), // increase magic dmg Skill::Decay => decay(cryp, target, log), // dot Skill::DecayTick => decay_tick(cryp, target, log), // hot Skill::Drain => drain(cryp, target, log), Skill::DrainTick => drain_tick(cryp, target, log), // hot Skill::Curse => curse(cryp, target, log), Skill::Plague => panic!("nyi"), // dot that spreads every turn Skill::Ruin => panic!("nyi"), // aoe version of blast // ----------------- // Purity // ----------------- // Skill::Precision => panic!("nyi"), Skill::Empower => empower(cryp, target, log), // increased phys dmg Skill::Slay => panic!("nyi"), // phys dmg mult by target magic dmg Skill::Shield => shield(cryp, target, log), // target is immune to magic dmg and fx Skill::Silence => silence(cryp, target, log), // target cannot cast spells Skill::Inquiry => panic!("nyi"), // Skill::Purify => purify(cryp, target, log), // dispel all debuffs Skill::Purge => purge(cryp, target, log), // dispel all buffs // ----------------- // Chaos // ----------------- Skill::Banish => banish(cryp, target, log), // TODO prevent all actions Skill::Hex => hex(cryp, target, log), // todo prevent casting Skill::Fear => panic!("nyi"), // cast random spell on self Skill::Taunt => panic!("nyi"), // target forced to attack Skill::Pause => panic!("nyi"), // speed slow // ----------------- // Test // ----------------- Skill::TestTouch => (), Skill::TestStun => stun(cryp, target, log), Skill::TestBlock => block(cryp, target, log), Skill::TestDrain => drain(cryp, target, log), }; } pub fn duration(&self) -> u8 { match self { Skill::Evade => 1, Skill::Stun => 2, Skill::Block => 1, Skill::Empower => 2, Skill::Decay => 3, Skill::Drain => 3, Skill::Triage => 3, Skill::Amplify => 2, Skill::Silence => 3, Skill::TestBlock => 1, Skill::TestStun => 2, _ => panic!("{:?} does not have a duration", self), } } pub fn self_targeting(&self) -> bool { match self { Skill::Block => true, Skill::TestBlock => true, _ => false, } } pub fn castable(&self, cryp: &Cryp) -> bool { !cryp.effects.iter().any(|e| e.effect.prevents_casting(*self)) } } fn attack(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { target.deal_phys_dmg(cryp.phys_dmg()); log.push(format!("{:?} -> {:?} | Attack for {:?}", cryp.name, target.name, cryp.phys_dmg)); } fn stun(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let stun = CrypEffect { effect: Effect::Stun, duration: Skill::Stun.duration(), tick: None }; target.effects.push(stun); log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, stun.effect, stun.duration)); } fn throw(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let stun = CrypEffect { effect: Effect::Stun, duration: Skill::Stun.duration(), tick: None }; let vulnerable = CrypEffect { effect: Effect::Vulnerable, duration: Skill::Stun.duration(), tick: None }; target.effects.push(stun); target.effects.push(vulnerable); log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, stun.effect, stun.duration)); log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, vulnerable.effect, vulnerable.duration)); } fn block(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Block, duration: Skill::Block.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn snare(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Snare, duration: Skill::Snare.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn empower(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Empower, duration: Skill::Empower.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn heal(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let (healing, overhealing) = target.heal(cryp.phys_dmg()); log.push(format!("{:?} -> {:?} | Heal for {:?} ({:?} OH)", cryp.name, target.name, healing, overhealing)); } fn triage(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Triage, duration: Skill::Triage.duration(), tick: Some(Cast::new_tick(cryp, target, Skill::TriageTick)), }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn triage_tick(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let amount = cryp.spell_dmg().wrapping_div(2); let (healing, overhealing) = target.heal(amount); log.push(format!("{:?} -> {:?} | Triage for {:?} ({:?} OH)", cryp.name, target.name, healing, overhealing)); } fn blast(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let amount = cryp.spell_dmg(); log.push(format!("{:?} -> {:?} | Blast for {:?}", cryp.name, target.name, amount)); target.deal_spell_dmg(amount); } fn amplify(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Amplify, duration: Skill::Amplify.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn decay(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Decay, duration: Skill::Decay.duration(), tick: Some(Cast::new_tick(cryp, target, Skill::DecayTick)), }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn decay_tick(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let amount = cryp.spell_dmg(); log.push(format!("{:?} -> {:?} | Decay for {:?}", cryp.name, target.name, amount)); target.deal_spell_dmg(amount); } fn hex(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Hex, duration: Skill::Hex.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn curse(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Curse, duration: Skill::Curse.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn drain(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Drain, duration: Skill::Drain.duration(), tick: Some(Cast::new_tick(cryp, target, Skill::DrainTick)), }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn drain_tick(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { // Damage part let (damage, _) = target.deal_spell_dmg(cryp.spell_dmg().wrapping_div(2)); log.push(format!("{:?} | Drain Damage {:?}", target.name, damage)); let (healing, overhealing) = target.heal(damage); log.push(format!("{:?} | Drain healing {:?} ({:?} OH)", cryp.name, healing, overhealing)); } fn shield(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Shield, duration: Skill::Shield.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn silence(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Silence, duration: Skill::Silence.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } fn purge(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { for (i, ce) in target.effects.clone().iter_mut().enumerate() { if ce.effect.source() == Source::Buff { target.effects.remove(i); log.push(format!("{:?} < {:?} purged", target.name, ce.effect)); } } } fn purify(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { for (i, ce) in target.effects.clone().iter_mut().enumerate() { if ce.effect.source() == Source::Debuff { target.effects.remove(i); log.push(format!("{:?} < {:?} purified", target.name, ce.effect)); } } } fn banish(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) { let effect = CrypEffect { effect: Effect::Banish, duration: Skill::Banish.duration(), tick: None }; target.effects.push(effect); log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration)); } #[cfg(test)] mod tests { use skill::*; #[test] fn heal_test() { let mut x = Cryp::new() .named(&"muji".to_string()) .level(8) .learn(Skill::Heal) .create(); let mut y = Cryp::new() .named(&"camel".to_string()) .level(8) .learn(Skill::Heal) .create(); x.deal_phys_dmg(5); let mut log = vec![]; heal(&mut y, &mut x, &mut log); } #[test] fn decay_test() { let mut x = Cryp::new() .named(&"muji".to_string()) .level(8) .create(); let mut y = Cryp::new() .named(&"camel".to_string()) .level(8) .create(); let mut log = vec![]; decay(&mut x, &mut y, &mut log); assert!(y.effects.iter().any(|e| e.effect == Effect::Decay)); y.reduce_effect_durations(&mut log); let decay = y.effects.iter().find(|e| e.effect == Effect::Decay); // assert!(y.hp() == y.stamina().saturating_sub(decay.unwrap().tick.unwrap().amount)); } #[test] fn triage_test() { let mut x = Cryp::new() .named(&"muji".to_string()) .level(8) .create(); let mut y = Cryp::new() .named(&"pretaliation".to_string()) .level(8) .create(); let mut log = vec![]; // ensure it doesn't have 0 sd x.spell_dmg.set(50); y.deal_phys_dmg(5); let prev_hp = y.hp(); triage(&mut x, &mut y, &mut log); assert!(y.effects.iter().any(|e| e.effect == Effect::Triage)); triage_tick(&mut x, &mut y, &mut log); assert!(y.hp() > prev_hp); } #[test] fn silence_test() { let mut x = Cryp::new() .named(&"muji".to_string()) .level(8) .create(); let mut log = vec![]; silence(&mut x.clone(), &mut x, &mut log); assert!(x.effects.iter().any(|e| e.effect == Effect::Silence)); assert!(!Skill::Decay.castable(&x)); } #[test] fn amplify_test() { let mut x = Cryp::new() .named(&"muji".to_string()) .level(8) .create(); x.spell_dmg.set(50); let mut log = vec![]; amplify(&mut x.clone(), &mut x, &mut log); assert!(x.effects.iter().any(|e| e.effect == Effect::Amplify)); assert_eq!(x.spell_dmg(), 100); } #[test] fn purify_test() { let mut x = Cryp::new() .named(&"muji".to_string()) .level(8) .create(); let mut log = vec![]; decay(&mut x.clone(), &mut x, &mut log); assert!(x.effects.iter().any(|e| e.effect == Effect::Decay)); purify(&mut x.clone(), &mut x, &mut log); assert!(!x.effects.iter().any(|e| e.effect == Effect::Decay)); } } // #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] // pub enum Skill { // Stoney, // Evasive, // } // impl Skill { // pub fn apply(&self, roll: Roll) -> Roll { // match self { // Skill::Stoney => stoney(self, roll), // Skill::Evasive => evasive(self, roll), // } // } // } // fn stoney(_s: &Skill, mut roll: Roll) -> Roll { // let effect = 0b11110000; // match roll.kind { // StatKind::Def => { // // println!("{:064b} | <- {:?}", effect, s); // roll.result = roll.result | effect; // roll // }, // _ => roll, // } // } // fn evasive(_s: &Skill, mut roll: Roll) -> Roll { // match roll.kind { // StatKind::Def => { // if roll.result.is_power_of_two() { // roll.result = u64::max_value() // } // roll // }, // _ => roll, // } // }