use rand::{thread_rng, Rng}; use uuid::Uuid; use util::{IntPct}; use item::{Item}; use game::{Game, Colour, Value, Action}; use construct::{Construct, ConstructEffect, EffectMeta, Stat}; use effect::{Effect, Cooldown}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub struct Cast { pub id: Uuid, pub player: Uuid, pub source: Uuid, pub target: Uuid, pub skill: Skill, pub speed: usize, } fn start() {} impl Cast { pub fn new(source: Uuid, player: Uuid, target: Uuid, skill: Skill) -> Cast { return Cast { id: Uuid::new_v4(), source, player, target, skill, speed: 0, }; } pub fn target(self) -> Uuid { self.target } pub fn new_tick(source: &mut Construct, target: &mut Construct, skill: Skill) -> Cast { Cast { id: Uuid::new_v4(), source: source.id, player: source.account, target: target.id, skill, speed: source.skill_speed(skill), } } pub fn used_cooldown(&self) -> bool { return self.skill.base_cd().is_some(); } pub fn actions(&self) -> Vec { let mut rng = thread_rng(); let mut actions = vec![]; if self.skill.cast_animation() { actions.push(Action::Cast); } actions.push(Action::Hit); let mut rest = match self.skill { Skill::Attack => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], }, ], Skill::Block => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Block, duration: 1, meta: Some(EffectMeta::Multiplier(35)), tick: None }, }, ], Skill::Buff => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Buff, duration: 3, meta: Some(EffectMeta::Multiplier(130)), tick: None }, }, ], Skill::Debuff => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Slow, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }, }, ], Skill::Stun => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }, }, ], Skill::Amplify => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }, }, ], Skill::AmplifyPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }, }, ], Skill::AmplifyPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None }, }, ], Skill::Absorb => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::Absorption)), tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::AbsorbPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlus)), tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::AbsorbPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlusPlus)), tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::Absorption => vec![ Action::Remove { construct: self.source, effect: Effect::Absorb, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Absorption, duration: 3, meta: None, tick: None }, }, ], Skill::AbsorptionPlus => vec![ Action::Remove { construct: self.source, effect: Effect::Absorb, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Absorption, duration: 4, meta: None, tick: None }, }, ], Skill::AbsorptionPlusPlus => vec![ Action::Remove { construct: self.source, effect: Effect::Absorb, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Absorption, duration: 5, meta: None, tick: None }, }, ], // fn absorb(source: &mut Construct, target: &mut Construct, skill: Skill) { // game.event(Event::new(source, target).event(target.effect_remove(skill, skill.effect()[0]))); // let blue_amount = source.blue_power().pct(skill.multiplier()); // target.recharge(skill, 0, blue_amount) // .into_iter() // .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); // } // fn absorption(source: &mut Construct, target: &mut Construct, reflect_skill: Skill, amount: usize, skill: Skill) { // let absorb = skill.effect()[0].set_meta(EffectMeta::AddedDamage(amount)); // game.event(Event::new(source, target) // .event(target.effect_remove(reflect_skill, absorb)) // .stages(EventStages::PostOnly)); // let absorb_index = target.effects.iter().position(|e| e.effect == Effect::Absorb).expect("No absorb"); // let ce = target.effects.remove(absorb_index); // game.event(Event::new(source, target) // .event(Event::Remove { skill, effect: Some(ce.effect), construct_effects: target.effects.clone() }) // .stages(EventStages::PostOnly)); // } Skill::Banish | Skill::BanishPlus | Skill::BanishPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![Value::Stat { construct: self.target, stat: Stat::RedLife, mult: self.skill.multiplier() }], }, Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.target, stat: Stat::BlueLife, mult: self.skill.multiplier() }], }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None } } ], Skill::Bash | Skill::BashPlus | Skill::BashPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![ Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }, Value::Cooldowns { construct: self.source, mult: 45 }, ], }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None } }, Action::IncreaseCooldowns { construct: self.target, turns: 1, }, ], Skill::Blast | Skill::BlastPlus | Skill::BlastPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], }, ], Skill::Break => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Vulnerable, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None, }, }, ], Skill::BreakPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(175)), tick: None, }, }, ], Skill::BreakPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None, }, }, ], Skill::Curse => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Curse, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }, }, ], Skill::CursePlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Curse, duration: 2, meta: Some(EffectMeta::Multiplier(175)), tick: None }, }, ], Skill::CursePlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Curse, duration: 3, meta: Some(EffectMeta::Multiplier(200)), tick: None }, }, ], Skill::Chaos | Skill::ChaosPlus | Skill::ChaosPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![ Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }, Value::Stat { construct: self.source, stat: Stat::RedPower, mult: rng.gen_range(0, 30) }, ], }, Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![ Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }, Value::Stat { construct: self.source, stat: Stat::BluePower, mult: rng.gen_range(0, 30) }, ], }, ], Skill::Counter => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None }, }, ], Skill::CounterPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None }, }, ], Skill::CounterPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None }, }, ], Skill::CounterAttack | Skill::CounterAttackPlus | Skill::CounterAttackPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], }, ], Skill::Decay => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Decay, duration: 2, meta: Some(EffectMeta::Skill(Skill::DecayTick)), tick: None }, }, ], Skill::DecayPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(35)), tick: None }, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Decay, duration: 4, meta: Some(EffectMeta::Skill(Skill::DecayTickPlus)), tick: None }, }, ], Skill::DecayPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Wither, duration: 4, meta: Some(EffectMeta::Multiplier(20)), tick: None }, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Decay, duration: 4, meta: Some(EffectMeta::Skill(Skill::DecayTickPlusPlus)), tick: None }, }, ], Skill::DecayTick | Skill::DecayTickPlus | Skill::DecayTickPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], }, ], Skill::Electrify=> vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::Skill(Skill::Electrocute)), tick: None }, }, ], Skill::ElectrifyPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::Skill(Skill::ElectrocutePlus)), tick: None }, }, ], Skill::ElectrifyPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::Skill(Skill::ElectrocutePlusPlus)), tick: None }, }, ], Skill::Electrocute => vec![ Action::Remove { construct: self.source, effect: Effect::Electric, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Electric, duration: 2, meta: Some(EffectMeta::Skill(Skill::ElectrocuteTick)), tick: None }, }, ], Skill::ElectrocutePlus => vec![ Action::Remove { construct: self.source, effect: Effect::Electric, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Electric, duration: 3, meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlus)), tick: None }, }, ], Skill::ElectrocutePlusPlus => vec![ Action::Remove { construct: self.source, effect: Effect::Electric, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Electric, duration: 4, meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlusPlus)), tick: None }, }, ], Skill::ElectrocuteTick | Skill::ElectrocuteTickPlus | Skill::ElectrocuteTickPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], }, ], Skill::Heal | Skill::HealPlus | Skill::HealPlusPlus => vec![ Action::Heal { construct: self.target, colour: Colour::Green, values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], }, ], Skill::Haste => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Haste, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None }, }, ], Skill::HastePlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Haste, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }, }, ], Skill::HastePlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Haste, duration: 3, meta: Some(EffectMeta::Multiplier(225)), tick: None }, }, ], Skill::Hybrid => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Hybrid, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None }, }, ], Skill::HybridPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Hybrid, duration: 4, meta: Some(EffectMeta::Multiplier(175)), tick: None }, }, ], Skill::HybridPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Hybrid, duration: 5, meta: Some(EffectMeta::Multiplier(200)), tick: None }, }, ], Skill::Intercept | Skill::InterceptPlus | Skill::InterceptPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Intercept, duration: 1, meta: None, tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], colour: Colour::Red, }, ], Skill::Invert => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Invert, duration: 2, meta: None, tick: None }, }, ], Skill::InvertPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Invert, duration: 3, meta: None, tick: None }, }, ], Skill::InvertPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Invert, duration: 4, meta: None, tick: None }, }, ], Skill::Link | Skill::LinkPlus | Skill::LinkPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }, }, Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![ Value::Effects { construct: self.target, mult: self.skill.multiplier() }, ], }, ], Skill::Purge => vec![ Action::RemoveAll { construct: self.target, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Purge, duration: 2, meta: None, tick: None } }, ], Skill::PurgePlus => vec![ Action::RemoveAll { construct: self.target, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Purge, duration: 3, meta: None, tick: None } }, ], Skill::PurgePlusPlus => vec![ Action::RemoveAll { construct: self.target, }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Purge, duration: 4, meta: None, tick: None } }, ], Skill::Purify => vec![ Action::RemoveAll { construct: self.target, }, Action::Heal { construct: self.target, colour: Colour::Green, values: vec![ Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }, Value::Removals { construct: self.target, mult: self.skill.multiplier() }, ], }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Pure, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None } }, ], Skill::PurifyPlus => vec![ Action::RemoveAll { construct: self.target, }, Action::Heal { construct: self.target, colour: Colour::Green, values: vec![ Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }, Value::Removals { construct: self.target, mult: self.skill.multiplier() }, ], }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Pure, duration: 2, meta: Some(EffectMeta::Multiplier(175)), tick: None } }, ], Skill::PurifyPlusPlus => vec![ Action::RemoveAll { construct: self.target, }, Action::Heal { construct: self.target, colour: Colour::Green, values: vec![ Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }, Value::Removals { construct: self.target, mult: self.skill.multiplier() }, ], }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Pure, duration: 2, meta: Some(EffectMeta::Multiplier(200)), tick: None } }, ], Skill::Recharge | Skill::RechargePlus | Skill::RechargePlusPlus => vec![ Action::Heal { construct: self.target, colour: Colour::Red, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], }, Action::Heal { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], }, ], Skill::Reflect | Skill::ReflectPlus | Skill::ReflectPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Reflect, duration: 1, meta: None, tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::Restrict | Skill::RestrictPlus | Skill::RestrictPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Restrict, duration: 2, meta: None, tick: None } }, Action::Damage { construct: self.target, colour: Colour::Red, values: vec![Value::ColourSkills { construct: self.source, colour: Colour::Red, mult: self.skill.multiplier() }], }, ], Skill::Ruin | Skill::RuinPlus | Skill::RuinPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.target, stat: Stat::BluePower, mult: self.skill.multiplier() }], }, Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None } } ], Skill::Siphon => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Siphon, duration: 2, meta: Some(EffectMeta::Skill(Skill::SiphonTick)), tick: None }, }, ], Skill::SiphonPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Siphon, duration: 3, meta: Some(EffectMeta::Skill(Skill::SiphonTickPlus)), tick: None }, }, ], Skill::SiphonPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Siphon, duration: 4, meta: Some(EffectMeta::Skill(Skill::SiphonTickPlusPlus)), tick: None }, }, ], Skill::SiphonTick | Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Blue, values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], }, Action::Heal { construct: self.target, colour: Colour::Green, values: vec![Value::DamageReceived { construct: self.target, colour: Colour::Blue, mult: 100 }], }, ], Skill::Slay | Skill::SlayPlus | Skill::SlayPlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], }, Action::Heal { construct: self.target, colour: Colour::Green, values: vec![Value::DamageReceived { construct: self.target, colour: Colour::Red, mult: 50 }], }, ], Skill::Sleep => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::SleepPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::SleepPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], colour: Colour::Blue, }, ], Skill::Silence | Skill::SilencePlus | Skill::SilencePlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Silence, duration: 2, meta: None, tick: None }, }, Action::Damage { construct: self.target, colour: Colour::Red, values: vec![ Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }, Value::ColourSkills { construct: self.target, colour: Colour::Blue, mult: self.skill.multiplier() }, ], }, ], Skill::Strike | Skill::StrikePlus | Skill::StrikePlusPlus => vec![ Action::Damage { construct: self.target, colour: Colour::Red, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], }, ], Skill::Sustain | Skill::SustainPlus | Skill::SustainPlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Sustain, duration: 1, meta: None, tick: None }, }, Action::Heal { construct: self.target, values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], colour: Colour::Red, }, ], Skill::Triage => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Triage, duration: 2, meta: Some(EffectMeta::Skill(Skill::TriageTick)), tick: None }, }, ], Skill::TriagePlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Triage, duration: 3, meta: Some(EffectMeta::Skill(Skill::TriageTickPlus)), tick: None }, }, ], Skill::TriagePlusPlus => vec![ Action::Effect { construct: self.target, effect: ConstructEffect { effect: Effect::Triage, duration: 4, meta: Some(EffectMeta::Skill(Skill::TriageTickPlusPlus)), tick: None }, }, ], Skill::TriageTick | Skill::TriageTickPlus | Skill::TriageTickPlusPlus => vec![ Action::Heal { construct: self.target, colour: Colour::Green, values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], }, ], // _ => unimplemented!(), _ => vec![], // for client testing }; actions.append(&mut rest); return actions; } } fn end() {} // pub fn dev_resolve(a_id: Uuid, b_id: Uuid, skill: Skill) { // let mut resolutions =vec![]; // let mut a = Construct::new(); // a.id = a_id; // let mut b = Construct::new(); // b.id = b_id; // if skill.aoe() { // Send an aoe skill event for anims // game.event(Event::new(&a, &b).event(Event::AoeSkill { skill }).stages(EventStages::StartEnd)); // } // return cast_actions(skill, &mut a, &mut b, resolutions); // } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Skill { Attack, Debuff, Buff, Block, // reduce damage Stun, // Boost -- sounds nice // Evade, // actively evade // Nightmare, // Sleep, Amplify, #[serde(rename = "Amplify+")] AmplifyPlus, #[serde(rename = "Amplify++")] AmplifyPlusPlus, Absorb, #[serde(rename = "Absorb+")] AbsorbPlus, #[serde(rename = "Absorb++")] AbsorbPlusPlus, Banish, #[serde(rename = "Banish+")] BanishPlus, #[serde(rename = "Banish++")] BanishPlusPlus, Bash, #[serde(rename = "Bash+")] BashPlus, #[serde(rename = "Bash++")] BashPlusPlus, Blast, #[serde(rename = "Blast+")] BlastPlus, #[serde(rename = "Blast++")] BlastPlusPlus, Chaos, #[serde(rename = "Chaos+")] ChaosPlus, #[serde(rename = "Chaos++")] ChaosPlusPlus, Sustain, #[serde(rename = "Sustain+")] SustainPlus, #[serde(rename = "Sustain++")] SustainPlusPlus, Electrify, #[serde(rename = "Electrify+")] ElectrifyPlus, #[serde(rename = "Electrify++")] ElectrifyPlusPlus, Curse, #[serde(rename = "Curse+")] CursePlus, #[serde(rename = "Curse++")] CursePlusPlus, Decay, #[serde(rename = "Decay+")] DecayPlus, #[serde(rename = "Decay++")] DecayPlusPlus, Haste, #[serde(rename = "Haste+")] HastePlus, #[serde(rename = "Haste++")] HastePlusPlus, Heal, #[serde(rename = "Heal+")] HealPlus, #[serde(rename = "Heal++")] HealPlusPlus, Hybrid, #[serde(rename = "Hybrid+")] HybridPlus, #[serde(rename = "Hybrid++")] HybridPlusPlus, Invert, #[serde(rename = "Invert+")] InvertPlus, #[serde(rename = "Invert++")] InvertPlusPlus, Counter, #[serde(rename = "Counter+")] CounterPlus, #[serde(rename = "Counter++")] CounterPlusPlus, Purge, #[serde(rename = "Purge+")] PurgePlus, #[serde(rename = "Purge++")] PurgePlusPlus, Purify, #[serde(rename = "Purify+")] PurifyPlus, #[serde(rename = "Purify++")] PurifyPlusPlus, Reflect, #[serde(rename = "Reflect+")] ReflectPlus, #[serde(rename = "Reflect++")] ReflectPlusPlus, Recharge, #[serde(rename = "Recharge+")] RechargePlus, #[serde(rename = "Recharge++")] RechargePlusPlus, Ruin, #[serde(rename = "Ruin+")] RuinPlus, #[serde(rename = "Ruin++")] RuinPlusPlus, Link, #[serde(rename = "Link+")] LinkPlus, #[serde(rename = "Link++")] LinkPlusPlus, Silence, #[serde(rename = "Silence+")] SilencePlus, #[serde(rename = "Silence++")] SilencePlusPlus, Slay, #[serde(rename = "Slay+")] SlayPlus, #[serde(rename = "Slay++")] SlayPlusPlus, Sleep, #[serde(rename = "Sleep+")] SleepPlus, #[serde(rename = "Sleep++")] SleepPlusPlus, Restrict, #[serde(rename = "Restrict+")] RestrictPlus, #[serde(rename = "Restrict++")] RestrictPlusPlus, Strike, #[serde(rename = "Strike+")] StrikePlus, #[serde(rename = "Strike++")] StrikePlusPlus, Siphon, #[serde(rename = "Siphon+")] SiphonPlus, #[serde(rename = "Siphon++")] SiphonPlusPlus, Intercept, #[serde(rename = "Intercept+")] InterceptPlus, #[serde(rename = "Intercept++")] InterceptPlusPlus, Break, #[serde(rename = "Break+")] BreakPlus, #[serde(rename = "Break++")] BreakPlusPlus, Triage, #[serde(rename = "Triage+")] TriagePlus, #[serde(rename = "Triage++")] TriagePlusPlus, Absorption, #[serde(rename = "Absorption+")] AbsorptionPlus, #[serde(rename = "Absorption++")] AbsorptionPlusPlus, CounterAttack, #[serde(rename = "CounterAttack+")] CounterAttackPlus, #[serde(rename = "CounterAttack++")] CounterAttackPlusPlus, Electrocute, #[serde(rename = "Electrocute+")] ElectrocutePlus, #[serde(rename = "Electrocute++")] ElectrocutePlusPlus, ElectrocuteTick, #[serde(rename = "ElectrocuteTick+")] ElectrocuteTickPlus, #[serde(rename = "ElectrocuteTick++")] ElectrocuteTickPlusPlus, DecayTick, // dot #[serde(rename = "DecayTick+")] DecayTickPlus, #[serde(rename = "DecayTick++")] DecayTickPlusPlus, HasteStrike, HybridBlast, SiphonTick, #[serde(rename = "SiphonTick+")] SiphonTickPlus, #[serde(rename = "SiphonTick++")] SiphonTickPlusPlus, TriageTick, #[serde(rename = "TriageTick+")] TriageTickPlus, #[serde(rename = "TriageTick++")] TriageTickPlusPlus, } impl Skill { pub fn multiplier(&self) -> usize { match self { // Attack Base Skill::Attack => 80, // Base Skill::Blast => 105, // BB Skill::BlastPlus => 125, // BB Skill::BlastPlusPlus => 145, // BB Skill::Chaos => 40, // BR Skill::ChaosPlus => 50, // BR Skill::ChaosPlusPlus => 65, // BR Skill::Heal => 115, //GG Skill::HealPlus => 135, //GG Skill::HealPlusPlus => 160, //GG Skill::SiphonTick => 25, // GB Skill::SiphonTickPlus => 27, Skill::SiphonTickPlusPlus => 30, Skill::Slay => 40, // RG Skill::SlayPlus => 50, Skill::SlayPlusPlus => 65, Skill::Strike => 90, //RR Skill::StrikePlus => 110, Skill::StrikePlusPlus => 140, // Block Base Skill::ElectrocuteTick => 80, Skill::ElectrocuteTickPlus => 90, Skill::ElectrocuteTickPlusPlus => 100, Skill::CounterAttack => 115, Skill::CounterAttackPlus => 130, Skill::CounterAttackPlusPlus => 160, Skill::Purify => 45, //Green dmg (heal) Skill::PurifyPlus => 60, Skill::PurifyPlusPlus => 85, Skill::Reflect => 45, //Recharge blue life (heal) Skill::ReflectPlus => 70, Skill::ReflectPlusPlus => 100, Skill::Recharge => 70, //Recharge red and blue life (heal) Skill::RechargePlus => 90, Skill::RechargePlusPlus => 110, Skill::Sustain => 110, // Recharge red life (heal) Skill::SustainPlus => 130, Skill::SustainPlusPlus => 150, // Stun Base Skill::Sleep => 160, //Green dmg (heal) Skill::SleepPlus => 200, Skill::SleepPlusPlus => 240, Skill::Banish => 50, //Green dmg (heal) Skill::BanishPlus => 65, Skill::BanishPlusPlus => 80, Skill::Bash => 45, Skill::BashPlus => 55, Skill::BashPlusPlus => 70, Skill::Link => 25, Skill::LinkPlus => 35, Skill::LinkPlusPlus => 45, Skill::Ruin => 40, Skill::RuinPlus => 55, Skill::RuinPlusPlus => 70, // Debuff Base Skill::DecayTick => 33, Skill::DecayTickPlus => 37, Skill::DecayTickPlusPlus => 45, Skill::Silence => 55, // Deals more per blue skill on target Skill::SilencePlus => 65, Skill::SilencePlusPlus => 80, Skill::Restrict => 40, // Deals more per red skill on target Skill::RestrictPlus => 55, Skill::RestrictPlusPlus => 70, // Buff base Skill::HybridBlast => 50, Skill::HasteStrike => 60, Skill::Absorb=> 95, Skill::AbsorbPlus => 110, Skill::AbsorbPlusPlus => 120, Skill::Intercept => 85, Skill::InterceptPlus => 100, Skill::InterceptPlusPlus => 125, Skill::TriageTick => 75, Skill::TriageTickPlus => 90, Skill::TriageTickPlusPlus => 110, _ => 100, } } pub fn effect(&self) -> Vec { match self { // Modifiers Skill::Amplify => vec![ConstructEffect { effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }], Skill::AmplifyPlus => vec![ConstructEffect { effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }], Skill::AmplifyPlusPlus => vec![ConstructEffect { effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None }], Skill::Banish => vec![ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None }], Skill::BanishPlus => vec![ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None }], Skill::BanishPlusPlus => vec![ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None }], Skill::Block => vec![ConstructEffect { effect: Effect::Block, duration: 1, meta: Some(EffectMeta::Multiplier(35)), tick: None }], Skill::Buff => vec![ConstructEffect { effect: Effect::Buff, duration: 3, meta: Some(EffectMeta::Multiplier(130)), tick: None }], Skill::Electrify => vec![ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::Skill(Skill::Electrocute)), tick: None }], Skill::ElectrifyPlus => vec![ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::Skill(Skill::ElectrocutePlus)), tick: None }], Skill::ElectrifyPlusPlus => vec![ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::Skill(Skill::ElectrocutePlusPlus)), tick: None }], Skill::Electrocute => vec![ConstructEffect { effect: Effect::Electrocute, duration: 2, meta: Some(EffectMeta::Skill(Skill::ElectrocuteTick)), tick: None }], Skill::ElectrocutePlus => vec![ConstructEffect { effect: Effect::Electrocute, duration: 3, meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlus)), tick: None }], Skill::ElectrocutePlusPlus => vec![ConstructEffect { effect: Effect::Electrocute, duration: 4, meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlusPlus)), tick: None }], Skill::Sustain => vec![ConstructEffect { effect: Effect::Sustain, duration: 1, meta: None, tick: None }], Skill::SustainPlus => vec![ConstructEffect { effect: Effect::Sustain, duration: 1, meta: None, tick: None }], Skill::SustainPlusPlus => vec![ConstructEffect { effect: Effect::Sustain, duration: 1, meta: None, tick: None }], Skill::Curse => vec![ConstructEffect { effect: Effect::Curse, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }], Skill::CursePlus => vec![ConstructEffect { effect: Effect::Curse, duration: 2, meta: Some(EffectMeta::Multiplier(175)), tick: None }], Skill::CursePlusPlus => vec![ConstructEffect { effect: Effect::Curse, duration: 3, meta: Some(EffectMeta::Multiplier(200)), tick: None }], Skill::Debuff => vec![ConstructEffect { effect: Effect::Slow, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }], Skill::Decay => vec![ConstructEffect { effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }, ConstructEffect { effect: Effect::Decay, duration: 3, meta: Some(EffectMeta::Skill(Skill::DecayTick)), tick: None }], Skill::DecayPlus => vec![ConstructEffect { effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(35)), tick: None }, ConstructEffect { effect: Effect::Decay, duration: 3, meta: Some(EffectMeta::Skill(Skill::DecayTickPlus)), tick: None }], Skill::DecayPlusPlus => vec![ConstructEffect { effect: Effect::Wither, duration: 4, meta: Some(EffectMeta::Multiplier(20)), tick: None }, ConstructEffect { effect: Effect::Decay, duration: 4, meta: Some(EffectMeta::Skill(Skill::DecayTickPlusPlus)), tick: None }], Skill::Haste => vec![ConstructEffect { effect: Effect::Haste, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None }], Skill::HastePlus => vec![ConstructEffect { effect: Effect::Haste, duration: 4, meta: Some(EffectMeta::Multiplier(175)), tick: None }], Skill::HastePlusPlus => vec![ConstructEffect { effect: Effect::Haste, duration: 5, meta: Some(EffectMeta::Multiplier(225)), tick: None }], Skill::Absorb => vec![ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::Absorption)), tick: None }], Skill::AbsorbPlus => vec![ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlus)), tick: None }], Skill::AbsorbPlusPlus => vec![ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlusPlus)), tick: None }], Skill::Absorption => vec![ConstructEffect { effect: Effect::Absorption, duration: 3, meta: None, tick: None }], Skill::AbsorptionPlus => vec![ConstructEffect { effect: Effect::Absorption, duration: 4, meta: None, tick: None }], Skill::AbsorptionPlusPlus => vec![ConstructEffect { effect: Effect::Absorption, duration: 5, meta: None, tick: None }], Skill::Hybrid => vec![ConstructEffect { effect: Effect::Hybrid, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None }], Skill::HybridPlus => vec![ConstructEffect { effect: Effect::Hybrid, duration: 4, meta: Some(EffectMeta::Multiplier(175)), tick: None }], Skill::HybridPlusPlus => vec![ConstructEffect { effect: Effect::Hybrid, duration: 5, meta: Some(EffectMeta::Multiplier(200)), tick: None }], Skill::Invert => vec![ConstructEffect { effect: Effect::Invert, duration: 2, meta: None, tick: None }], Skill::InvertPlus => vec![ConstructEffect { effect: Effect::Invert, duration: 3, meta: None, tick: None }], Skill::InvertPlusPlus => vec![ConstructEffect { effect: Effect::Invert, duration: 4, meta: None, tick: None }], Skill::Counter => vec![ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None }], Skill::CounterPlus => vec![ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None }], Skill::CounterPlusPlus => vec![ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None }], Skill::Reflect => vec![ConstructEffect { effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::ReflectPlus => vec![ConstructEffect { effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::ReflectPlusPlus => vec![ConstructEffect { effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::Break => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }, ConstructEffect { effect: Effect::Vulnerable, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None }], Skill::BreakPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }, ConstructEffect { effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(175)), tick: None }], Skill::BreakPlusPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }, ConstructEffect { effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None }], Skill::Ruin => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }], Skill::RuinPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }], Skill::RuinPlusPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }], Skill::Purge => vec![ConstructEffect { effect: Effect::Purge, duration: 2, meta: None, tick: None }], Skill::PurgePlus => vec![ConstructEffect { effect: Effect::Purge, duration: 3, meta: None, tick: None }], Skill::PurgePlusPlus => vec![ConstructEffect { effect: Effect::Purge, duration: 4, meta: None, tick: None }], Skill::Link => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }], Skill::LinkPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }], Skill::LinkPlusPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None }], Skill::Silence => vec![ConstructEffect { effect: Effect::Silence, duration: 2, meta: None, tick: None }], Skill::SilencePlus => vec![ConstructEffect { effect: Effect::Silence, duration: 2, meta: None, tick: None }], Skill::SilencePlusPlus => vec![ConstructEffect { effect: Effect::Silence, duration: 2, meta: None, tick: None }], Skill::Siphon => vec![ConstructEffect { effect: Effect::Siphon, duration: 2, meta: Some(EffectMeta::Skill(Skill::SiphonTick)), tick: None }], Skill::SiphonPlus => vec![ConstructEffect { effect: Effect::Siphon, duration: 3, meta: Some(EffectMeta::Skill(Skill::SiphonTickPlus)), tick: None }], Skill::SiphonPlusPlus => vec![ConstructEffect { effect: Effect::Siphon, duration: 4, meta: Some(EffectMeta::Skill(Skill::SiphonTickPlusPlus)), tick: None }], Skill::Sleep => vec![ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }], Skill::SleepPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 3, meta: None, tick: None }], Skill::SleepPlusPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 4, meta: None, tick: None }], Skill::Restrict => vec![ConstructEffect { effect: Effect::Restrict, duration: 2, meta: None, tick: None }], Skill::RestrictPlus => vec![ConstructEffect { effect: Effect::Restrict, duration: 2, meta: None, tick: None }], Skill::RestrictPlusPlus => vec![ConstructEffect { effect: Effect::Restrict, duration: 2, meta: None, tick: None }], Skill::Bash => vec![ConstructEffect { effect: Effect::Stun, duration: 2, meta: Some(EffectMeta::Skill(Skill::Bash)), tick: None }], Skill::BashPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 2, meta: Some(EffectMeta::Skill(Skill::BashPlus)), tick: None }], Skill::BashPlusPlus => vec![ConstructEffect { effect: Effect::Stun, duration: 2, meta: Some(EffectMeta::Skill(Skill::BashPlusPlus)), tick: None }], Skill::Stun => vec![ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None }], Skill::Intercept => vec![ConstructEffect { effect: Effect::Intercept, duration: 1, meta: None, tick: None }], Skill::InterceptPlus => vec![ConstructEffect { effect: Effect::Intercept, duration: 1, meta: None, tick: None }], Skill::InterceptPlusPlus => vec![ConstructEffect { effect: Effect::Intercept, duration: 1, meta: None, tick: None }], Skill::Triage => vec![ConstructEffect { effect: Effect::Triage, duration: 2, meta: Some(EffectMeta::Skill(Skill::TriageTick)), tick: None }], Skill::TriagePlus => vec![ConstructEffect { effect: Effect::Triage, duration: 3, meta: Some(EffectMeta::Skill(Skill::TriageTickPlus)), tick: None }], Skill::TriagePlusPlus => vec![ConstructEffect { effect: Effect::Triage, duration: 4, meta: Some(EffectMeta::Skill(Skill::TriageTickPlusPlus)), tick: None }], Skill::Purify => vec![ConstructEffect { effect: Effect::Pure, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }], Skill::PurifyPlus => vec![ConstructEffect { effect: Effect::Pure, duration: 2, meta: Some(EffectMeta::Multiplier(175)), tick: None }], Skill::PurifyPlusPlus => vec![ConstructEffect { effect: Effect::Pure, duration: 2, meta: Some(EffectMeta::Multiplier(200)), tick: None }], _ => { panic!("{:?} no skill effect", self); }, } } pub fn base_cd(&self) -> Cooldown { match self { Skill::Attack => None, Skill::Block => None, // reduce damage Skill::Buff => None, Skill::Debuff => Some(1), Skill::Stun => Some(2), Skill::Strike=> None, Skill::StrikePlus => None, Skill::StrikePlusPlus => None, Skill::Counter| Skill::CounterPlus | Skill::CounterPlusPlus => None, // avoid all damage Skill::Restrict | Skill::RestrictPlus | Skill::RestrictPlusPlus => Some(2), Skill::Bash | Skill::BashPlus | Skill::BashPlusPlus => Some(2), Skill::Heal=> None, Skill::HealPlus => None, Skill::HealPlusPlus => None, Skill::Triage=> None, // hot Skill::TriagePlus => None, // hot Skill::TriagePlusPlus => None, // hot Skill::Break | // no damage stun, adds vulnerable Skill::BreakPlus | Skill::BreakPlusPlus => Some(1), Skill::Blast | Skill::BlastPlus | Skill::BlastPlusPlus => None, Skill::Chaos | Skill::ChaosPlus | Skill::ChaosPlusPlus => None, Skill::Amplify | Skill::AmplifyPlus | Skill::AmplifyPlusPlus => Some(1), Skill::Hybrid | Skill::HybridPlus | Skill::HybridPlusPlus => Some(1), Skill::Invert | Skill::InvertPlus | Skill::InvertPlusPlus => Some(2), Skill::Decay => None, // dot Skill::DecayPlus => None, Skill::DecayPlusPlus => None, Skill::Siphon| Skill::SiphonPlus | Skill::SiphonPlusPlus => None, Skill::Curse | Skill::CursePlus | Skill::CursePlusPlus => Some(1), Skill::Link | Skill::LinkPlus | Skill::LinkPlusPlus => Some(1), Skill::Silence | Skill::SilencePlus | Skill::SilencePlusPlus => Some(2), Skill::Purify | Skill::PurifyPlus | Skill::PurifyPlusPlus => None, Skill::Purge | Skill::PurgePlus | Skill::PurgePlusPlus => Some(1), Skill::Banish | Skill::BanishPlus | Skill::BanishPlusPlus => Some(1), Skill::Haste | Skill::HastePlus | Skill::HastePlusPlus => Some(1), Skill::Reflect | Skill::ReflectPlus | Skill::ReflectPlusPlus => None, Skill::Recharge | Skill::RechargePlus | Skill::RechargePlusPlus => None, Skill::Ruin | Skill::RuinPlus | Skill::RuinPlusPlus => Some(2), Skill::Slay=> None, Skill::SlayPlus => None, Skill::SlayPlusPlus => None, Skill::Sleep | Skill::SleepPlus | Skill::SleepPlusPlus => Some(2), Skill::Sustain | Skill::SustainPlus | Skill::SustainPlusPlus => Some(1), Skill::Intercept => Some(1), Skill::InterceptPlus => Some(1), Skill::InterceptPlusPlus => Some(1), Skill::Electrify | Skill::ElectrifyPlus | Skill::ElectrifyPlusPlus => None, Skill::Absorb | Skill::AbsorbPlus | Skill::AbsorbPlusPlus => Some(1), //----------- // Never cast directly //--------- // Trigger Skill::HybridBlast | Skill::HasteStrike | Skill::CounterAttack| Skill::CounterAttackPlus | Skill::CounterAttackPlusPlus | // counter Skill::Electrocute| Skill::ElectrocutePlus | Skill::ElectrocutePlusPlus | Skill::Absorption| Skill::AbsorptionPlus | Skill::AbsorptionPlusPlus | // Ticks Skill::ElectrocuteTick| Skill::ElectrocuteTickPlus | Skill::ElectrocuteTickPlusPlus | Skill::DecayTick| Skill::DecayTickPlus | Skill::DecayTickPlusPlus | Skill::SiphonTick| Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus | Skill::TriageTick| Skill::TriageTickPlus | Skill::TriageTickPlusPlus => None, } } fn cast_animation(&self) -> bool { match self { Skill::HybridBlast | Skill::HasteStrike | Skill::CounterAttack| Skill::CounterAttackPlus | Skill::CounterAttackPlusPlus | // counter Skill::Electrocute| Skill::ElectrocutePlus | Skill::ElectrocutePlusPlus | Skill::Absorption| Skill::AbsorptionPlus | Skill::AbsorptionPlusPlus | Skill::ElectrocuteTick| Skill::ElectrocuteTickPlus | Skill::ElectrocuteTickPlusPlus | Skill::DecayTick| Skill::DecayTickPlus | Skill::DecayTickPlusPlus | Skill::SiphonTick| Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus | Skill::TriageTick| Skill::TriageTickPlus | Skill::TriageTickPlusPlus => false, _ => true, } } pub fn ko_castable(&self) -> bool { match self { Skill::ElectrocuteTick | Skill::ElectrocuteTickPlus | Skill::ElectrocuteTickPlusPlus | Skill::DecayTick | Skill::DecayTickPlus | Skill::DecayTickPlusPlus | Skill::SiphonTick | Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus | Skill::TriageTick | Skill::TriageTickPlus | Skill::TriageTickPlusPlus => true, _ => false, } } pub fn is_tick(&self) -> bool { match self { Skill::ElectrocuteTick | Skill::ElectrocuteTickPlus | Skill::ElectrocuteTickPlusPlus | Skill::DecayTick | Skill::DecayTickPlus | Skill::DecayTickPlusPlus | Skill::SiphonTick | Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus | Skill::TriageTick | Skill::TriageTickPlus | Skill::TriageTickPlusPlus => true, _ => false, } } pub fn speed(&self) -> usize { match self { Skill::SiphonTick | Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus => Skill::Siphon.speed(), Skill::DecayTick | Skill::DecayTickPlus | Skill::DecayTickPlusPlus => Skill::Decay.speed(), Skill::TriageTick | Skill::TriageTickPlus | Skill::TriageTickPlusPlus => Skill::Triage.speed(), Skill::ElectrocuteTick | Skill::ElectrocuteTickPlus | Skill::ElectrocuteTickPlusPlus => Skill::Electrify.speed(), _ => Item::from(*self).speed(), } } pub fn aoe(&self) -> bool { match self { Skill::Ruin | Skill::RuinPlus | Skill::RuinPlusPlus => true, _ => false, } } pub fn defensive(&self) -> bool { match self { Skill::Amplify| Skill::AmplifyPlus | Skill::AmplifyPlusPlus | Skill::Block | Skill::Sustain | Skill::SustainPlus | Skill::SustainPlusPlus | Skill::Electrify | Skill::ElectrifyPlus | Skill::ElectrifyPlusPlus | Skill::Haste | Skill::HastePlus | Skill::HastePlusPlus | Skill::Heal | Skill::HealPlus | Skill::HealPlusPlus | Skill::Absorb | Skill::AbsorbPlus | Skill::AbsorbPlusPlus | Skill::Invert | Skill::InvertPlus | Skill::InvertPlusPlus | Skill::Intercept | Skill::InterceptPlus | Skill::InterceptPlusPlus | Skill::Counter | Skill::CounterPlus | Skill::CounterPlusPlus | Skill::Purify | Skill::PurifyPlus | Skill::PurifyPlusPlus | Skill::Recharge | Skill::RechargePlus | Skill::RechargePlusPlus | Skill::Reflect | Skill::ReflectPlus | Skill::ReflectPlusPlus | Skill::Triage | Skill::TriagePlus | Skill::TriagePlusPlus => true, _ => false, } } fn components(&self) -> Vec { let mut components = Item::from(*self).components(); components.sort_unstable(); return components; } pub fn colours(&self) -> Vec { let mut components = self.components(); let colour_items = [Item::Red, Item::Green, Item::Blue]; components.dedup(); return components.iter() .filter(|i| colour_items.contains(i)) .map(|i| i.into_colour()) .collect::>(); } fn base(&self) -> Skill { let bases = [Item::Attack, Item::Stun, Item::Buff, Item::Debuff, Item::Block]; match self.components() .iter() .find(|i| bases.contains(i)) { Some(i) => i.into_skill().unwrap(), None => panic!("{:?} has no base item", self), } } } // #[cfg(test)] mod tests { use skill::*; #[test] fn attack_actions_test() { let cast = Cast::new(Uuid::new_v4(), Uuid::new_v4(), Uuid::new_v4(), Skill::Attack); let actions = cast.actions(); match actions[0] { Action::Cast => (), _ => panic!("{:?}", actions), }; match actions[1] { Action::Hit => (), _ => panic!("{:?}", actions), }; match actions[2] { Action::Damage { construct: _, values: _, colour } => { assert_eq!(colour, Colour::Red); }, _ => panic!("{:?}", actions), }; } // #[test] // fn heal_test() { // let mut x = Construct::new() // .named(&"muji".to_string()) // .learn(Skill::Heal); // let mut y = Construct::new() // .named(&"camel".to_string()) // .learn(Skill::Heal); // x.deal_red_damage(Skill::Attack, 5); // heal(&mut y, &mut x, vec![], Skill::Heal); // } // #[test] // fn decay_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"camel".to_string()); // decay(&mut x, &mut y, vec![], Skill::Decay); // assert!(y.effects.iter().any(|e| e.effect == Effect::Decay)); // y.reduce_effect_durations(); // let _decay = y.effects.iter().find(|e| e.effect == Effect::Decay); // // assert!(y.green_life() == y.green_life().saturating_sub(decay.unwrap().tick.unwrap().amount)); // } // #[test] // fn block_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"camel".to_string()); // // ensure it doesn't have 0 pd // x.red_power.force(100); // y.green_life.force(500); // block(&mut y.clone(), &mut y, vec![], Skill::Block); // assert!(y.effects.iter().any(|e| e.effect == Effect::Block)); // attack(&mut x, &mut y, vec![], Skill::Attack); // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Damage { amount, mitigation: _, colour: _, skill: _ } => // assert!(amount < x.red_power().pct(Skill::Attack.multiplier())), // _ => panic!("not damage"), // }; // } // #[test] // fn sustain_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"camel".to_string()); // x.red_power.force(10000000000000); // multiplication of int max will cause overflow // y.green_life.force(1024); // make tests more flexible if we change stats // sustain(&mut y.clone(), &mut y, vec![], Skill::Sustain); // assert!(y.affected(Effect::Sustain)); // ruin(&mut x, &mut y, vec![], Skill::Ruin); // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Immunity { skill: _, immunity } => assert!(immunity.contains(&Effect::Sustain)), // _ => panic!("not immune cluthc"), // }; // attack(&mut x, &mut y, vec![], Skill::Attack); // assert!(y.green_life() == 1); // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Damage { amount, mitigation: _, colour: _, skill: _ } => assert_eq!(amount, 1023), // _ => panic!("not damage"), // }; // } // #[test] // fn invert_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"camel".to_string()); // // give red shield but reduce to 0 // y.red_life.force(64); // y.red_life.reduce(64); // x.red_power.force(512); // invert(&mut y.clone(), &mut y, vec![], Skill::Invert); // assert!(y.affected(Effect::Invert)); // // heal should deal green damage // heal(&mut x, &mut y, vec![], Skill::Heal); // assert!(y.green_life() < 1024); // // attack should heal and recharge red shield // attack(&mut x, &mut y, vec![], Skill::Attack); // // match resolutions.remove(0).event { // // Event::Inversion { skill } => assert_eq!(skill, Skill::Attack), // // _ => panic!("not inversion"), // //}; // match resolutions.remove(0).event { // Event::Heal { skill: _, overhealing: _, amount } => assert!(amount > 0), // _ => panic!("not healing from inversion"), // }; // match resolutions.remove(0).event { // Event::Recharge { skill: _, red, blue: _ } => assert!(red > 0), // _ => panic!("not recharge from inversion"), // }; // } // #[test] // fn reflect_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"camel".to_string()); // reflect(&mut y.clone(), &mut y, vec![], Skill::Reflect); // assert!(y.affected(Effect::Reflect)); // let mut vec![]; // cast_actions(Skill::Blast, &mut x, &mut y, resolutions); // assert!(x.green_life() < 1024); // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Reflection { skill } => assert_eq!(skill, Skill::Blast), // _ => panic!("not reflection"), // }; // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Damage { amount, mitigation: _, colour: _, skill: _ } => assert!(amount > 0), // _ => panic!("not damage"), // }; // } // #[test] // fn siphon_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"camel".to_string()); // x.blue_power.force(256); // x.green_power.force(220); // x.green_life.force(1024); // y.blue_life.force(0); // x.green_life.reduce(512); // cast_actions(Skill::Siphon, &mut x, &mut y, vec![]); // assert!(y.affected(Effect::Siphon)); // assert!(x.green_life() == (512 + 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier()))); // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Effect { effect, skill: _, duration: _, construct_effects: _ } => assert_eq!(effect, Effect::Siphon), // _ => panic!("not siphon"), // }; // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Damage { amount, skill: _, mitigation: _, colour: _} => assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()) // + 220.pct(Skill::SiphonTick.multiplier())), // _ => panic!("not damage siphon"), // }; // let Event { source: _, target, event, stages: _ } = resolutions.remove(0); // match event { // Event::Heal { amount, skill: _, overhealing: _ } => { // assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier())); // assert_eq!(target.id, x.id); // }, // _ => panic!("not healing"), // }; // } // #[test] // fn triage_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"pretaliation".to_string()); // // ensure it doesn't have 0 sd // x.blue_power.force(50); // // remove all mitigation // y.red_life.force(0); // y.blue_life.force(0); // y.deal_red_damage(Skill::Attack, 5); // let prev_hp = y.green_life(); // triage(&mut x, &mut y, vec![], Skill::Triage); // assert!(y.effects.iter().any(|e| e.effect == Effect::Triage)); // assert!(y.green_life() > prev_hp); // } // #[test] // fn recharge_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"pretaliation".to_string()); // y.red_life.force(50); // y.blue_life.force(50); // y.deal_red_damage(Skill::Attack, 5); // y.deal_blue_damage(Skill::Blast, 5); // recharge(&mut x, &mut y, vec![], Skill::Recharge); // resolutions.remove(0); // let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0); // match event { // Event::Recharge { red, blue, skill: _ } => { // assert!(red == 5); // assert!(blue == 5); // } // _ => panic!("result was not recharge"), // } // } // #[test] // fn silence_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // silence(&mut x.clone(), &mut x, vec![], Skill::Silence); // assert!(x.effects.iter().any(|e| e.effect == Effect::Silence)); // assert!(x.disabled(Skill::Silence).is_some()); // } // #[test] // fn amplify_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // x.blue_power.force(50); // amplify(&mut x.clone(), &mut x, vec![], Skill::Amplify); // assert!(x.effects.iter().any(|e| e.effect == Effect::Amplify)); // assert_eq!(x.blue_power(), 75); // } // #[test] // fn purify_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // decay(&mut x.clone(), &mut x, vec![], Skill::Decay); // assert!(x.effects.iter().any(|e| e.effect == Effect::Decay)); // purify(&mut x.clone(), &mut x, vec![], Skill::Purify); // assert!(!x.effects.iter().any(|e| e.effect == Effect::Decay)); // } // #[test] // fn bash_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"pretaliation".to_string()) // .learn(Skill::Stun); // let stun_cd = y.skills.iter().find(|cs| cs.skill == Skill::Stun).unwrap().cd.unwrap(); // bash(&mut x, &mut y, vec![], Skill::Bash); // assert!(!x.effects.iter().any(|e| e.effect == Effect::Stun)); // assert!(y.skills.iter().any(|cs| cs.skill == Skill::Stun && cs.cd.unwrap() == stun_cd + 1)); // } // #[test] // fn purge_test() { // let mut x = Construct::new() // .named(&"muji".to_string()); // let mut y = Construct::new() // .named(&"pretaliation".to_string()) // .learn(Skill::Heal) // .learn(Skill::HealPlus); // purge(&mut x, &mut y, vec![], Skill::Purge); // // 2 turns at lvl 1 // assert!(y.effects.iter().any(|e| e.effect == Effect::Purge && e.duration == 2)); // assert!(y.disabled(Skill::Heal).is_some()); // } } // Skill::Strike => game.event( // Event::Damage { // colour: Colour::Red, // amount: SkillPower { construct: cast.source, skill: Skill::Strike } // }, // Event::LifeSteal { // amount: CastDamage { id: cast.id, colour: Colour::Red, target: cast.source }, // }, // ), // Skill::Attack => game.event(Event::Damage { // colour: Colour::Red, // amount: Stat { construct: cast.source, stat: Stat::RedPower, pct: ATTACK_RED_POWER_PCT } // }), // Skill::Bash => game.event(Event::Damage { // colour: Colour::Red, // amounts: vec![ // Stat { construct: cast.source, stat: Stat::RedPower, pct: ATTACK_RED_POWER_PCT }, // Cooldowns { construct: cast.source }, // ], // }) // // we clone the current state of the target and source // // so we can modify them during the resolution // // no more than 1 mutable ref allowed on game // let mut source = game.construct_by_id(cast.source).unwrap().clone(); // let mut target = game.construct_by_id(target_id).unwrap().clone(); // // bail out on ticks that have been removed // if skill.is_tick() && target.effects.iter().find(|ce| match ce.tick { // Some(t) => t.id == cast.id, // None => false, // }).is_none() { // return; // } // if let Some(_disable) = source.disabled(skill) { // game.event(Event::new(source, target).event(Event::Disable { disable, skill }).stages(EventStages::PostOnly)); // return; // } // if target.is_ko() { // game.event(Event::new(source, target).event(Event::TargetKo { skill }).stages(EventStages::PostOnly)); // return; // } // if target.affected(Effect::Reflect) && skill.colours().contains(&Colour::Blue) && !skill.is_tick() { // // guard against overflow // if source.affected(Effect::Reflect) { // } // game.event(Event::new(source, target).event(Event::Reflection { skill })); // return cast_actions(skill, &mut source.clone(), source, resolutions); // } // // haste_strike_check(game) // if source.affected(Effect::Haste) { // match skill { // Skill::Slay | // Skill::SlayPlus | // Skill::SlayPlusPlus | // Skill::Chaos | // Skill::ChaosPlus | // Skill::ChaosPlusPlus | // Skill::Strike | // Skill::StrikePlus | // Skill::StrikePlusPlus => { // let amount = source.speed().pct(Skill::HasteStrike.multiplier()); // target.deal_red_damage(Skill::HasteStrike, amount) // .into_iter() // .for_each(|e| game.event(Event::new(source, target).event(e))); // }, // _ => (), // } // } // if source.affected(Effect::Hybrid) { // match skill { // Skill::Blast| // Skill::BlastPlus | // Skill::BlastPlusPlus | // Skill::Chaos | // Skill::ChaosPlus | // Skill::ChaosPlusPlus | // Skill::Siphon | // Skill::SiphonPlus | // Skill::SiphonPlusPlus => { // let amount = source.green_power().pct(Skill::HybridBlast.multiplier()); // target.deal_blue_damage(Skill::HybridBlast, amount) // .into_iter() // .for_each(|e| game.event(Event::new(source, target).event(e))); // }, // _ => (), // } // } // match self.category() == EffectCategory::Red { // true => { // if let Some(evasion) = target.evade(*self) { // game.event(evasion); // return Event; // } // }, // false => (), // } // for Event { source: event_source, target: event_target, event, stages: _ } in resolutions.clone() { // let mut source = game.construct_by_id(event_source.id).unwrap().clone(); // let mut target = game.construct_by_id(event_target.id).unwrap().clone(); // match event { // Event::Damage { amount, skill, mitigation, colour: c } => { // if target.affected(Effect::Electric) && !skill.is_tick() { // let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter() // .find(|e| e.effect == Effect::Electric).unwrap().clone(); // match meta { // Some(EffectMeta::Skill(s)) => { // // Gurad against reflect overflow // if !(source.affected(Effect::Reflect) && target.affected(Effect::Reflect)) { // // Check reflect don't bother if electrocute is procing on death // if source.affected(Effect::Reflect) && !target.is_ko() { // game.event(Event::new(&target, &source) // .event(Event::Reflection { skill: s }).stages(EventStages::EndPost)); // electrocute(&mut source, &mut target, resolutions, s); // } else { // electrocute(&mut target, &mut source, resolutions, s); // } // } // }, // _ => panic!("no electrify skill"), // }; // } // if target.affected(Effect::Absorb) && !target.is_ko() { // let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter() // .find(|e| e.effect == Effect::Absorb).unwrap().clone(); // match meta { // Some(EffectMeta::Skill(s)) => { // absorption(&mut source, &mut target, resolutions, skill, amount + mitigation, s); // }, // _ => panic!("no absorb skill"), // }; // } // if c == Colour::Red { // if target.affected(Effect::Counter) && !target.is_ko() { // let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter() // .find(|e| e.effect == Effect::Counter).unwrap().clone(); // match meta { // Some(EffectMeta::Skill(s)) => { // counter_attack(&mut target, &mut source, resolutions, s); // }, // _ => panic!("no counter skill"), // }; // } // } // if target.is_ko() && event_target.green == 0 { // // Make sure target ko is from this event // target.effects.clear(); // game.event(Event::new(&source, &target).event(Event::Ko()).stages(EventStages::PostOnly)); // } // }, // _ => (), // }; // game.update_construct(&mut source); // game.update_construct(&mut target); // };