use rand::{thread_rng, Rng}; use uuid::Uuid; use util::{IntPct}; use item::{Item}; use game::{Game, Colour, Value, Action}; use 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, } 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 set_speed(self, speed: usize) -> Cast { Cast { speed, ..self } } pub fn resolve(self, game: &mut Game) { match self.skill { Skill::Attack => attack(self, game, Attack::Base), Skill::Block => block(self, game, Block::Base), Skill::Buff => buff(self, game, Buff::Base), Skill::Debuff => debuff(self, game, Debuff::Base), Skill::Stun => stun(self, game, Stun::Base), Skill::Amplify => amplify(self, game, Amplify::Base), Skill::AmplifyPlus => amplify(self, game, Amplify::Plus), Skill::AmplifyPlusPlus => amplify(self, game, Amplify::PlusPlus), Skill::Absorb => absorb(self, game, Absorb::Base), Skill::AbsorbPlus => absorb(self, game, Absorb::Plus), Skill::AbsorbPlusPlus => absorb(self, game, Absorb::PlusPlus), Skill::Absorption => absorption(self, game, Absorption::Base), Skill::AbsorptionPlus => absorption(self, game, Absorption::Plus), Skill::AbsorptionPlusPlus => absorption(self, game, Absorption::PlusPlus), Skill::Banish => banish(self, game, Banish::Base), Skill::BanishPlus => banish(self, game, Banish::Plus), Skill::BanishPlusPlus => banish(self, game, Banish::PlusPlus), Skill::Bash => bash(self, game, Bash::Base), Skill::BashPlus => bash(self, game, Bash::Plus), Skill::BashPlusPlus => bash(self, game, Bash::PlusPlus), Skill::Blast => blast(self, game, Blast::Base), Skill::BlastPlus => blast(self, game, Blast::Plus), Skill::BlastPlusPlus => blast(self, game, Blast::PlusPlus), Skill::Break => break_fn(self, game, Break::Base), Skill::BreakPlus => break_fn(self, game, Break::Plus), Skill::BreakPlusPlus => break_fn(self, game, Break::PlusPlus), Skill::Curse => curse(self, game, Curse::Base), Skill::CursePlus => curse(self, game, Curse::Plus), Skill::CursePlusPlus => curse(self, game, Curse::PlusPlus), Skill::Chaos => chaos(self, game, Chaos::Base), Skill::ChaosPlus => chaos(self, game, Chaos::Plus), Skill::ChaosPlusPlus => chaos(self, game, Chaos::PlusPlus), Skill::Counter => counter(self, game, Counter::Base), Skill::CounterPlus => counter(self, game, Counter::Plus), Skill::CounterPlusPlus => counter(self, game, Counter::PlusPlus), Skill::CounterAttack => counter_attack(self, game, CounterAttack::Base), Skill::CounterAttackPlus => counter_attack(self, game, CounterAttack::Plus), Skill::CounterAttackPlusPlus => counter_attack(self, game, CounterAttack::PlusPlus), Skill::Decay => decay(self, game, Decay::Base), Skill::DecayPlus => decay(self, game, Decay::Plus), Skill::DecayPlusPlus => decay(self, game, Decay::PlusPlus), Skill::DecayTick => decay_tick(self, game), Skill::Electrify => electrify(self, game, Electrify::Base), Skill::ElectrifyPlus => electrify(self, game, Electrify::Plus), Skill::ElectrifyPlusPlus => electrify(self, game, Electrify::PlusPlus), Skill::Electrocute => electrocute(self, game, Electrocute::Base), Skill::ElectrocutePlus => electrocute(self, game, Electrocute::Plus), Skill::ElectrocutePlusPlus => electrocute(self, game, Electrocute::PlusPlus), Skill::ElectrocuteTick => electrocute_tick(self, game), Skill::Heal => heal(self, game, Heal::Base), Skill::HealPlus => heal(self, game, Heal::Plus), Skill::HealPlusPlus => heal(self, game, Heal::PlusPlus), Skill::Haste => haste(self, game, Haste::Base), Skill::HastePlus => haste(self, game, Haste::Plus), Skill::HastePlusPlus => haste(self, game, Haste::PlusPlus), Skill::HasteStrike => strike(self, game, Strike::Haste), Skill::Hybrid => hybrid(self, game, Hybrid::Base), Skill::HybridPlus => hybrid(self, game, Hybrid::Plus), Skill::HybridPlusPlus => hybrid(self, game, Hybrid::PlusPlus), Skill::HybridBlast => blast(self, game, Blast::Hybrid), Skill::Intercept => intercept(self, game, Intercept::Base), Skill::InterceptPlus => intercept(self, game, Intercept::Plus), Skill::InterceptPlusPlus => intercept(self, game, Intercept::PlusPlus), Skill::Invert => invert(self, game, Invert::Base), Skill::InvertPlus => invert(self, game, Invert::Plus), Skill::InvertPlusPlus => invert(self, game, Invert::PlusPlus), Skill::Link => link(self, game, Link::Base), Skill::LinkPlus => link(self, game, Link::Plus), Skill::LinkPlusPlus => link(self, game, Link::PlusPlus), Skill::Purge => purge(self, game, Purge::Base), Skill::PurgePlus => purge(self, game, Purge::Plus), Skill::PurgePlusPlus => purge(self, game, Purge::PlusPlus), Skill::Purify => purify(self, game, Purify::Base), Skill::PurifyPlus => purify(self, game, Purify::Plus), Skill::PurifyPlusPlus => purify(self, game, Purify::PlusPlus), Skill::Recharge => recharge(self, game, Recharge::Base), Skill::RechargePlus => recharge(self, game, Recharge::Plus), Skill::RechargePlusPlus => recharge(self, game, Recharge::PlusPlus), Skill::Reflect => reflect(self, game, Reflect::Base), Skill::ReflectPlus => reflect(self, game, Reflect::Plus), Skill::ReflectPlusPlus => reflect(self, game, Reflect::PlusPlus), Skill::Restrict => restrict(self, game, Restrict::Base), Skill::RestrictPlus => restrict(self, game, Restrict::Plus), Skill::RestrictPlusPlus => restrict(self, game, Restrict::PlusPlus), Skill::Ruin => ruin(self, game, Ruin::Base), Skill::RuinPlus => ruin(self, game, Ruin::Plus), Skill::RuinPlusPlus => ruin(self, game, Ruin::PlusPlus), Skill::Siphon => siphon(self, game, Siphon::Base), Skill::SiphonPlus => siphon(self, game, Siphon::Plus), Skill::SiphonPlusPlus => siphon(self, game, Siphon::PlusPlus), Skill::SiphonTick => siphon_tick(self, game), Skill::Slay => slay(self, game, Slay::Base), Skill::SlayPlus => slay(self, game, Slay::Plus), Skill::SlayPlusPlus => slay(self, game, Slay::PlusPlus), Skill::Sleep => sleep(self, game, Sleep::Base), Skill::SleepPlus => sleep(self, game, Sleep::Plus), Skill::SleepPlusPlus => sleep(self, game, Sleep::PlusPlus), Skill::Silence => silence(self, game, Silence::Base), Skill::SilencePlus => silence(self, game, Silence::Plus), Skill::SilencePlusPlus => silence(self, game, Silence::PlusPlus), Skill::Strike => strike(self, game, Strike::Base), Skill::StrikePlus => strike(self, game, Strike::Plus), Skill::StrikePlusPlus => strike(self, game, Strike::PlusPlus), Skill::Sustain => sustain(self, game, Sustain::Base), Skill::SustainPlus => sustain(self, game, Sustain::Plus), Skill::SustainPlusPlus => sustain(self, game, Sustain::PlusPlus), Skill::Triage => triage(self, game, Triage::Base), Skill::TriagePlus => triage(self, game, Triage::Plus), Skill::TriagePlusPlus => triage(self, game, Triage::PlusPlus), Skill::TriageTick => triage_tick(self, game), }; } } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Skill { Attack, Debuff, Buff, Block, Stun, 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, DecayTick, // dot 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, SiphonTick, 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, TriageTick, 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, HasteStrike, HybridBlast, } impl Skill { 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::DecayTick| Skill::SiphonTick| Skill::TriageTick => None, } } pub fn cast_animation(&self) -> bool { match self { Skill::CounterAttack| Skill::CounterAttackPlus | Skill::CounterAttackPlusPlus | // counter Skill::Electrocute| Skill::ElectrocutePlus | Skill::ElectrocutePlusPlus | Skill::Absorption| Skill::AbsorptionPlus | Skill::AbsorptionPlusPlus | Skill::ElectrocuteTick | Skill::DecayTick | Skill::SiphonTick | Skill::TriageTick => false, _ => true, } } pub fn ko_castable(&self) -> bool { match self { Skill::ElectrocuteTick | Skill::DecayTick | Skill::SiphonTick | Skill::TriageTick => true, _ => false, } } pub fn is_tick(&self) -> bool { match self { Skill::ElectrocuteTick | Skill::DecayTick | Skill::SiphonTick | Skill::TriageTick => true, _ => false, } } pub fn speed(&self) -> usize { match self { Skill::SiphonTick => Skill::Siphon.speed(), Skill::DecayTick => Skill::Decay.speed(), Skill::TriageTick => Skill::Triage.speed(), Skill::ElectrocuteTick => 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::Hybrid | Skill::HybridPlus | Skill::HybridPlusPlus | 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, } } pub fn additional_skill(&self, effect: Effect) -> Option { match effect { Effect::Haste => match self { Skill::Slay | Skill::SlayPlus | Skill::SlayPlusPlus | Skill::Chaos | Skill::ChaosPlus | Skill::ChaosPlusPlus | Skill::Strike | Skill::StrikePlus | Skill::StrikePlusPlus => Some(Skill::HasteStrike), _ => None, }, Effect::Hybrid => match self { Skill::Blast| Skill::BlastPlus | Skill::BlastPlusPlus | Skill::Chaos | Skill::ChaosPlus | Skill::ChaosPlusPlus | Skill::Siphon | Skill::SiphonPlus | Skill::SiphonPlusPlus => Some(Skill::HybridBlast), _ => None, }, _ => None, } } 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), } } pub fn description(self) -> String { match self { Skill::Attack => Attack::Base.description(), Skill::Block => Block::Base.description(), Skill::Buff => Buff::Base.description(), Skill::Debuff => Debuff::Base.description(), Skill::Stun => Stun::Base.description(), Skill::Amplify => Amplify::Base.description(), Skill::AmplifyPlus => Amplify::Plus.description(), Skill::AmplifyPlusPlus => Amplify::PlusPlus.description(), Skill::Absorb => Absorb::Base.description(), Skill::AbsorbPlus => Absorb::Plus.description(), Skill::AbsorbPlusPlus => Absorb::PlusPlus.description(), Skill::Banish => Banish::Base.description(), Skill::BanishPlus => Banish::Plus.description(), Skill::BanishPlusPlus => Banish::PlusPlus.description(), Skill::Bash => Bash::Base.description(), Skill::BashPlus => Bash::Plus.description(), Skill::BashPlusPlus => Bash::PlusPlus.description(), Skill::Blast => Blast::Base.description(), Skill::BlastPlus => Blast::Plus.description(), Skill::BlastPlusPlus => Blast::PlusPlus.description(), Skill::Break => Break::Base.description(), Skill::BreakPlus => Break::Plus.description(), Skill::BreakPlusPlus => Break::PlusPlus.description(), Skill::Curse => Curse::Base.description(), Skill::CursePlus => Curse::Plus.description(), Skill::CursePlusPlus => Curse::PlusPlus.description(), Skill::Chaos => Chaos::Base.description(), Skill::ChaosPlus => Chaos::Plus.description(), Skill::ChaosPlusPlus => Chaos::PlusPlus.description(), Skill::Counter => Counter::Base.description(), Skill::CounterPlus => Counter::Plus.description(), Skill::CounterPlusPlus => Counter::PlusPlus.description(), Skill::Decay => Decay::Base.description(), Skill::DecayPlus => Decay::Plus.description(), Skill::DecayPlusPlus => Decay::PlusPlus.description(), Skill::Electrify => Electrify::Base.description(), Skill::ElectrifyPlus => Electrify::Plus.description(), Skill::ElectrifyPlusPlus => Electrify::PlusPlus.description(), Skill::Heal => Heal::Base.description(), Skill::HealPlus => Heal::Plus.description(), Skill::HealPlusPlus => Heal::PlusPlus.description(), Skill::Haste => Haste::Base.description(), Skill::HastePlus => Haste::Plus.description(), Skill::HastePlusPlus => Haste::PlusPlus.description(), Skill::Hybrid => Hybrid::Base.description(), Skill::HybridPlus => Hybrid::Plus.description(), Skill::HybridPlusPlus => Hybrid::PlusPlus.description(), Skill::Intercept => Intercept::Base.description(), Skill::InterceptPlus => Intercept::Plus.description(), Skill::InterceptPlusPlus => Intercept::PlusPlus.description(), Skill::Invert => Invert::Base.description(), Skill::InvertPlus => Invert::Plus.description(), Skill::InvertPlusPlus => Invert::PlusPlus.description(), Skill::Link => Link::Base.description(), Skill::LinkPlus => Link::Plus.description(), Skill::LinkPlusPlus => Link::PlusPlus.description(), Skill::Purge => Purge::Base.description(), Skill::PurgePlus => Purge::Plus.description(), Skill::PurgePlusPlus => Purge::PlusPlus.description(), Skill::Purify => Purify::Base.description(), Skill::PurifyPlus => Purify::Plus.description(), Skill::PurifyPlusPlus => Purify::PlusPlus.description(), Skill::Recharge => Recharge::Base.description(), Skill::RechargePlus => Recharge::Plus.description(), Skill::RechargePlusPlus => Recharge::PlusPlus.description(), Skill::Reflect => Reflect::Base.description(), Skill::ReflectPlus => Reflect::Plus.description(), Skill::ReflectPlusPlus => Reflect::PlusPlus.description(), Skill::Restrict => Restrict::Base.description(), Skill::RestrictPlus => Restrict::Plus.description(), Skill::RestrictPlusPlus => Restrict::PlusPlus.description(), Skill::Ruin => Ruin::Base.description(), Skill::RuinPlus => Ruin::Plus.description(), Skill::RuinPlusPlus => Ruin::PlusPlus.description(), Skill::Siphon => Siphon::Base.description(), Skill::SiphonPlus => Siphon::Plus.description(), Skill::SiphonPlusPlus => Siphon::PlusPlus.description(), Skill::Slay => Slay::Base.description(), Skill::SlayPlus => Slay::Plus.description(), Skill::SlayPlusPlus => Slay::PlusPlus.description(), Skill::Sleep => Sleep::Base.description(), Skill::SleepPlus => Sleep::Plus.description(), Skill::SleepPlusPlus => Sleep::PlusPlus.description(), Skill::Silence => Silence::Base.description(), Skill::SilencePlus => Silence::Plus.description(), Skill::SilencePlusPlus => Silence::PlusPlus.description(), Skill::Strike => Strike::Base.description(), Skill::StrikePlus => Strike::Plus.description(), Skill::StrikePlusPlus => Strike::PlusPlus.description(), Skill::Sustain => Sustain::Base.description(), Skill::SustainPlus => Sustain::Plus.description(), Skill::SustainPlusPlus => Sustain::PlusPlus.description(), Skill::Triage => Triage::Base.description(), Skill::TriagePlus => Triage::Plus.description(), Skill::TriagePlusPlus => Triage::PlusPlus.description(), // Trigger Skill::HybridBlast | Skill::HasteStrike | Skill::CounterAttack| Skill::CounterAttackPlus | Skill::CounterAttackPlusPlus | Skill::Electrocute| Skill::ElectrocutePlus | Skill::ElectrocutePlusPlus | Skill::Absorption| Skill::AbsorptionPlus | Skill::AbsorptionPlusPlus | // Ticks Skill::ElectrocuteTick| Skill::DecayTick| Skill::SiphonTick| Skill::TriageTick => { warn!("trigger skill description called"); format!("no trigger description") } } } } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Attack { Base } impl Attack { fn dmg_multiplier(self) -> usize { match self { Attack::Base => 80 } } fn description(self) -> String { format!("Deal {:?}% RedPower as red damage.", self.dmg_multiplier()) } } fn attack(cast: Cast, game: &mut Game, values: Attack) { game.action( cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.dmg_multiplier()), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Blast { Base, Plus, PlusPlus, Hybrid } impl Blast { fn dmg_multi(self) -> usize { match self { Blast::Base => 105, Blast::Plus => 125, Blast::PlusPlus => 145, Blast::Hybrid => 50, } } fn description(self) -> String { format!("Deals {:?}% BluePower as blue damage.", self.dmg_multi()) } } fn blast(cast: Cast, game: &mut Game, values: Blast) { let amount = match values { Blast::Hybrid => game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.dmg_multi()), _ => game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.dmg_multi()) }; game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Chaos { Base, Plus, PlusPlus } impl Chaos { fn dmg_multi(self) -> usize { match self { Chaos::Base => 40, Chaos::Plus => 50, Chaos::PlusPlus => 65 } } fn description(self) -> String { format!("Hits twice for red and blue damage. Damage {:?}% RedPower and BluePower. Randomly deals 0 to 30% more damage.", self.dmg_multi()) } } fn chaos(cast: Cast, game: &mut Game, values: Chaos) { let mut rng = thread_rng(); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.dmg_multi().pct(rng.gen_range(100, 130))) } ); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.dmg_multi().pct(rng.gen_range(100, 130))) }, ); } enum Heal { Base, Plus, PlusPlus } impl Heal { fn heal_multiplier(self) -> usize { match self { Heal::Base => 115, Heal::Plus => 135, Heal::PlusPlus => 160 } } fn description(self) -> String { format!("Heals target for {:?}% GreenPower.", self.heal_multiplier()) } } fn heal(cast: Cast, game: &mut Game, values: Heal) { game.action(cast, Action::Heal { construct: cast.target, colour: Colour::Green, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.heal_multiplier()), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Siphon { Base, Plus, PlusPlus } impl Siphon { fn blue_dmg_multi(self) -> usize { match self { Siphon::Base => 25, Siphon::Plus => 27, Siphon::PlusPlus => 30 } } fn green_dmg_multi(self) -> usize { match self { Siphon::Base => 25, Siphon::Plus => 27, Siphon::PlusPlus => 30 } } fn duration(self) -> u8 { match self { Siphon::Base => 2, Siphon::Plus => 3, Siphon::PlusPlus => 4 } } fn description(self) -> String { format!( "Deals {:?}% BluePower + {:?}% GreenPower as blue damage each turn. Construct heals self for 100% of damage dealt to target construct GreenLife. Lasts {:?}T.", self.blue_dmg_multi(), self.green_dmg_multi(), self.duration()) } } fn siphon(cast: Cast, game: &mut Game, values: Siphon) { let amount = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.blue_dmg_multi()) + game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.green_dmg_multi()); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Siphon, duration: values.duration(), meta: Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::SiphonTick, speed: cast.speed, amount }) }, } ); // should only reapply the dot if they have already been hit by the dmg // from either this or the tick if game.affected(cast.target, Effect::Siphoned) { return; } game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, } ); game.action(cast, Action::Heal { construct: cast.source, colour: Colour::Green, amount: game.value(Value::DamageReceived { construct: cast.target }).pct(100), }, ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Siphoned, duration: 1, meta: None }, // immunity to additional ticks } ); } fn siphon_tick(cast: Cast, game: &mut Game) { game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Siphon }), } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Siphoned, duration: 1, meta: None }, // immunity to additional ticks } ); game.action(cast, Action::Heal { construct: cast.source, colour: Colour::Green, amount: game.value(Value::DamageReceived { construct: cast.target }).pct(100), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Slay { Base, Plus, PlusPlus } impl Slay { fn red_dmg_multi(self) -> usize { match self { Slay::Base => 40, Slay::Plus => 50, Slay::PlusPlus => 65 } } fn green_dmg_multi(self) -> usize { match self { Slay::Base => 40, Slay::Plus => 50, Slay::PlusPlus => 65 } } fn self_heal_multi(self) -> usize { match self { Slay::Base => 50, Slay::Plus => 60, Slay::PlusPlus => 75 } } fn description(self) -> String { format!("Deals {:?}% RedPower + {:?}% GreenPower as red damage. Construct heals self for {:?}% of damage dealt to target construct GreenLife.", self.red_dmg_multi(), self.green_dmg_multi(), self.self_heal_multi()) } } fn slay(cast: Cast, game: &mut Game, values: Slay) { let amount = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.red_dmg_multi()) + game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.green_dmg_multi()); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount, } ); game.action(cast, Action::Heal { construct: cast.source, colour: Colour::Green, amount: game.value(Value::DamageReceived { construct: cast.target }).pct(values.self_heal_multi()), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Strike { Base, Plus, PlusPlus, Haste } impl Strike { fn dmg_multi(self) -> usize { match self { Strike::Base => 90, Strike::Plus => 110, Strike::PlusPlus => 140, Strike::Haste => 60, } } fn description(self) -> String { format!("Strike the target with speed dealing {:?}% RedPower as red damage.", self.dmg_multi()) } } fn strike(cast: Cast, game: &mut Game, values: Strike) { let amount = match values { Strike::Haste => game.value(Value::Stat { construct: cast.source, stat: Stat::Speed }).pct(values.dmg_multi()), _ => game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.dmg_multi()) }; game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Block { Base } impl Block { fn damage_reduction(self) -> usize { match self { Block::Base => 35 } } fn duration(self) -> u8 { match self { Block::Base => 1 } } fn description(self) -> String { format!("Reduce red and blue damage taken by {:?}%. Block lasts {:?}T", 100 - self.damage_reduction(), self.duration()) } } fn block(cast: Cast, game: &mut Game, values: Block) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Block, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.damage_reduction())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Buff { Base } impl Buff { fn multiplier(self) -> usize { // RedPower / BluePower / Speed match self { Buff::Base => 130 } } fn duration(self) -> u8 { match self { Buff::Base => 3 } } fn description(self) -> String { format!("Increase target construct RedPower BluePower SpeedStat by {:?}%. Buff lasts {:?}T", self.multiplier() - 100, self.duration()) } } fn buff(cast: Cast, game: &mut Game, values: Buff) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Buff, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.multiplier())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Debuff { Base } impl Debuff { fn multiplier(self) -> usize { // Speed match self { Debuff::Base => 50 } } fn duration(self) -> u8 { match self { Debuff::Base => 3 } } fn description(self) -> String { format!("Slows the target reducing SpeedStat by {:?}%. Debuff lasts {:?}T", 100 - self.multiplier(), self.duration()) } } fn debuff(cast: Cast, game: &mut Game, values: Debuff) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Slow, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.multiplier())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Stun { Base } impl Stun { fn duration(self) -> u8 { match self { Stun::Base => 2 } } fn description(self) -> String { format!("Stun target construct for {:?}T.", self.duration()) } } fn stun(cast: Cast, game: &mut Game, values: Stun) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Stun, duration: values.duration(), meta: None }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Amplify { Base, Plus, PlusPlus } impl Amplify { fn multiplier(self) -> usize { // Blue and Red Power match self { Amplify::Base => 150, Amplify::Plus => 175, Amplify::PlusPlus => 200 } } fn duration(self) -> u8 { match self { Amplify::Base => 2, Amplify::Plus => 3, Amplify::PlusPlus => 4 } } fn description(self) -> String { format!("Increase RedPower BluePower by {:?}%. Lasts {:?}T.", self.multiplier() - 100, self.duration()) } } fn amplify(cast: Cast, game: &mut Game, values: Amplify) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Amplify, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.multiplier())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Absorb { Base, Plus, PlusPlus } impl Absorb { fn blue_heal_multi(self) -> usize { // Blue and Red Power match self { Absorb::Base => 95, Absorb::Plus => 110, Absorb::PlusPlus => 140 } } fn duration(self) -> u8 { match self { Absorb::Base => 1, Absorb::Plus => 1, Absorb::PlusPlus => 1 } } fn absorption_skill(self) -> Skill { match self { Absorb::Base => Skill::Absorption, Absorb::Plus => Skill::AbsorptionPlus, Absorb::PlusPlus => Skill::AbsorptionPlusPlus } } fn description(self) -> String { format!( "Gain Absorb for {:?}T. Taking damage replaces Absorb with Absorption. Absorption increases RedPower and BluePower based on damage taken. Absorption lasts {:?}T. Recharges BlueLife based on {:?}% BluePower.", self.duration(), match self { Absorb::Base => Absorption::Base.duration(), Absorb::Plus => Absorption::Plus.duration(), Absorb::PlusPlus => Absorption::PlusPlus.duration(), }, self.blue_heal_multi()) } } fn absorb(cast: Cast, game: &mut Game, values: Absorb) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Absorb, duration: values.duration(), meta: Some(EffectMeta::CastOnHit(values.absorption_skill())) }, } ); game.action(cast, Action::Heal { construct: cast.target, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.blue_heal_multi()), colour: Colour::Blue, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Absorption { Base, Plus, PlusPlus } impl Absorption { fn duration(self) -> u8 { match self { Absorption::Base => 3, Absorption::Plus => 4, Absorption::PlusPlus => 5 } } } fn absorption(cast: Cast, game: &mut Game, values: Absorption) { game.action(cast, Action::Remove { construct: cast.target, effect: Effect::Absorb, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Absorption, duration: values.duration(), meta: Some(EffectMeta::AddedDamage(0)) }, } ); game.action(cast, Action::SetEffectMeta { construct: cast.target, effect: Effect::Absorption, amount: game.value(Value::DamageReceived { construct: cast.source }).pct(100), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Banish { Base, Plus, PlusPlus } impl Banish { fn life_multiplier(self) -> usize { match self { Banish::Base => 40, Banish::Plus => 55, Banish::PlusPlus => 80 } } fn duration(self) -> u8 { match self { Banish::Base => 2, Banish::Plus => 2, Banish::PlusPlus => 2 } } fn description(self) -> String { format!("Banish target for {:?}T. Deal {:?}% target RedLife and BlueLife as red and blue damage respectively. Banished constructs are immune to all skills and effects.", self.duration(), self.life_multiplier()) } } fn banish(cast: Cast, game: &mut Game, values: Banish) { game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount: game.value(Value::Stat { construct: cast.target, stat: Stat::RedLife }).pct(values.life_multiplier()), } ); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount: game.value(Value::Stat { construct: cast.target, stat: Stat::BlueLife }).pct(values.life_multiplier()), } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Banish, duration: values.duration(), meta: None } } ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Bash { Base, Plus, PlusPlus } impl Bash { fn damage_multiplier(self) -> usize { match self { Bash::Base => 45, Bash::Plus => 55, Bash::PlusPlus => 70 } } fn duration(self) -> u8 { match self { Bash::Base => 2, Bash::Plus => 2, Bash::PlusPlus => 2 } } fn description(self) -> String { format!("Bash the target increasing the cooldowns of target skills by 1T. Stuns target for {:?}T. Deals {:?}% RedPower as red damage and 45% more damage per cooldown increased.", self.duration(), self.damage_multiplier()) } } fn bash(cast: Cast, game: &mut Game, values: Bash) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Stun, duration: values.duration(), meta: None } } ); game.action(cast, Action::IncreaseCooldowns { construct: cast.target, turns: 1, }, ); let cds = game.value(Value::Cooldowns { construct: cast.source }); let red_power = game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }); let amount = red_power.pct(values.damage_multiplier().pct(100 + 45usize.saturating_mul(cds))); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount, } ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Break { Base, Plus, PlusPlus } impl Break { fn stun_duration(self) -> u8 { match self { Break::Base => 1, Break::Plus => 1, Break::PlusPlus => 2 } } fn vulnerable_duration(self) -> u8 { match self { Break::Base => 3, Break::Plus => 4, Break::PlusPlus => 5 } } fn vulnerable_multiplier(self) -> usize { match self { Break::Base => 150, Break::Plus => 175, Break::PlusPlus => 200 } } fn description(self) -> String { format!("Stun the target for {:?}T and applies Vulnerable increasing red damage taken by {:?}% for {:?}T.", self.stun_duration(), self.vulnerable_multiplier() - 100, self.vulnerable_duration()) } } fn break_fn(cast: Cast, game: &mut Game, values: Break) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Stun, duration: values.stun_duration(), meta: None }, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Vulnerable, duration: values.vulnerable_duration(), meta: Some(EffectMeta::Multiplier(values.vulnerable_multiplier())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Curse { Base, Plus, PlusPlus } impl Curse { fn curse_duration(self) -> u8 { match self { Curse::Base => 2, Curse::Plus => 2, Curse::PlusPlus => 3 } } fn curse_multi(self) -> usize { match self { Curse::Base => 150, Curse::Plus => 175, Curse::PlusPlus => 200 } } fn description(self) -> String { format!("Increases red and blue damage taken by {:?}%. Lasts {:?}T.", self.curse_multi() - 100, self.curse_duration()) } } fn curse(cast: Cast, game: &mut Game, values: Curse) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Curse, duration: values.curse_duration(), meta: Some(EffectMeta::Multiplier(values.curse_multi())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Counter { Base, Plus, PlusPlus } impl Counter { fn duration(self) -> u8 { match self { Counter::Base => 1, Counter::Plus => 1, Counter::PlusPlus => 2 } } fn counter_skill(self) -> Skill { match self { Counter::Base => Skill::CounterAttack, Counter::Plus => Skill::CounterAttackPlus, Counter::PlusPlus => Skill::CounterAttackPlusPlus } } fn description(self) -> String { format!("Applies counter for {:?}T. Red damage taken during counter will trigger a counter attack. Counter attack deals {:?}% RedPower as red damage.", self.duration(), match self { Counter::Base => CounterAttack::Base.dmg_multi(), Counter::Plus => CounterAttack::Plus.dmg_multi(), Counter::PlusPlus => CounterAttack::PlusPlus.dmg_multi(), } ) } } fn counter(cast: Cast, game: &mut Game, values: Counter) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Counter, duration: values.duration(), meta: Some(EffectMeta::CastOnHit(values.counter_skill())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum CounterAttack { Base, Plus, PlusPlus } impl CounterAttack { fn dmg_multi(self) -> usize { match self { CounterAttack::Base => 115, CounterAttack::Plus => 130, CounterAttack::PlusPlus => 160 } } } fn counter_attack(cast: Cast, game: &mut Game, values: CounterAttack) { // effect has to be first so that the loop doesn't occur game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Countered, duration: 1, meta: None }, // immunity to additional hits } ); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.dmg_multi()), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Decay { Base, Plus, PlusPlus } impl Decay { fn decay_dmg_multiplier(self) -> usize { match self { Decay::Base => 33, Decay::Plus => 37, Decay::PlusPlus => 45, } } fn decay_duration(self) -> u8 { match self { Decay::Base => 3, Decay::Plus => 4, Decay::PlusPlus => 5, } } fn wither_multiplier(self) -> usize { match self { Decay::Base => 50, Decay::Plus => 35, Decay::PlusPlus => 20, } } fn wither_duration(self) -> u8 { match self { Decay::Base => 3, Decay::Plus => 4, Decay::PlusPlus => 5, } } fn description(self) -> String { format!("Reduces healing taken by {:?}% for {:?}T. Deals blue damage {:?}% BluePower each turn for {:?}T.", 100 - self.wither_multiplier(), self.wither_duration(), self.decay_dmg_multiplier(), self.decay_duration()) } } fn decay(cast: Cast, game: &mut Game, values: Decay) { let amount = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.decay_dmg_multiplier()); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Decay, duration: values.decay_duration(), meta: Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::DecayTick, speed: cast.speed, amount }) }, } ); if game.affected(cast.target, Effect::Decayed) { return; } game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Wither, duration: values.wither_duration(), meta: Some(EffectMeta::Multiplier(values.wither_multiplier())) }, } ); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Decayed, duration: 1, meta: None }, // immunity to additional ticks }, ); } fn decay_tick(cast: Cast, game: &mut Game) { let amount = game.value(Value::TickDamage { construct: cast.target, effect: Effect::Decay }); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Decayed, duration: 1, meta: None }, // immunity to additional ticks }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Electrify { Base, Plus, PlusPlus } impl Electrify { fn electrocute(self) -> Skill { match self { Electrify::Base => Skill::Electrocute, Electrify::Plus => Skill::ElectrocutePlus, Electrify::PlusPlus => Skill::ElectrocutePlusPlus, } } fn duration(self) -> u8 { match self { Electrify::Base => 1, Electrify::Plus => 1, Electrify::PlusPlus => 2 } } fn description(self) -> String { let electro = match self { Electrify::Base => Electrocute::Base, Electrify::Plus => Electrocute::Plus, Electrify::PlusPlus => Electrocute::PlusPlus }; format!("Applies electrify for {:?}T. If a construct with electrify takes direct damage they will apply an electrocute debuff to the caster. Electrocute deals {:?}% BluePower as BlueDamage per turn for {:?}T.", self.duration(), electro.damage_multiplier(), electro.duration()) } } fn electrify(cast: Cast, game: &mut Game, values: Electrify) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Electric, duration: 1, meta: Some(EffectMeta::CastOnHit(values.electrocute())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Electrocute { Base, Plus, PlusPlus } impl Electrocute { fn damage_multiplier(self) -> usize { match self { Electrocute::Base => 80, Electrocute::Plus => 90, Electrocute::PlusPlus => 100 } } fn duration(self) -> u8 { match self { Electrocute::Base => 2, Electrocute::Plus => 3, Electrocute::PlusPlus => 4 } } } fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { let amount = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.damage_multiplier()); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Electrocute, duration: values.duration(), meta: Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, }, ); if !game.affected(cast.target, Effect::Electrocuted) { game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, }, ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Electrocuted, duration: 1, meta: None }, // immunity to additional ticks }, ); } game.action(cast, Action::Remove { construct: cast.source, effect: Effect::Electric, } ); } fn electrocute_tick(cast: Cast, game: &mut Game) { game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Electrocute }), }, ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Electrocuted, duration: 1, meta: None }, // immunity to additional ticks }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Haste { Base, Plus, PlusPlus } impl Haste { fn speed_multi(self) -> usize { match self { Haste::Base => 150, Haste::Plus => 175, Haste::PlusPlus => 225 } } fn duration(self) -> u8 { match self { Haste::Base => 3, Haste::Plus => 3, Haste::PlusPlus => 3 } } fn description(self) -> String { format!("Haste increases SpeedStat by {:?}%. Lasts {:?}T. Red Attack based skills will strike again dealing {:?}% SpeedStat as red damage.", self.speed_multi() - 100, self.duration(), Strike::Haste.dmg_multi()) } } fn haste(cast: Cast, game: &mut Game, values: Haste) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Haste, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.speed_multi())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Hybrid { Base, Plus, PlusPlus } impl Hybrid { fn green_multi(self) -> usize { match self { Hybrid::Base => 150, Hybrid::Plus => 175, Hybrid::PlusPlus => 200 } } fn duration(self) -> u8 { match self { Hybrid::Base => 3, Hybrid::Plus => 4, Hybrid::PlusPlus => 5 } } fn description(self) -> String { format!("Hybrid increases GreenPower by {:?}% .Lasts {:?}T. Blue based Attack skills will blast again dealing {:?}% GreenPower as blue damage.", self.green_multi() - 100, self.duration(), Blast::Hybrid.dmg_multi()) } } fn hybrid(cast: Cast, game: &mut Game, values: Hybrid) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Hybrid, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.green_multi())) }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Intercept { Base, Plus, PlusPlus } impl Intercept { fn red_heal_multi(self) -> usize { match self { Intercept::Base => 85, Intercept::Plus => 100, Intercept::PlusPlus => 125 } } fn duration(self) -> u8 { match self { Intercept::Base => 1, Intercept::Plus => 1, Intercept::PlusPlus => 1 } } fn description(self) -> String { format!("Intercept redirects skills against the team to target, lasts {:?}T. Heals RedLife for {:?} RedPower.", self.duration(), self.red_heal_multi()) } } fn intercept(cast: Cast, game: &mut Game, values: Intercept) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Intercept, duration: values.duration(), meta: None }, } ); game.action(cast, Action::Heal { construct: cast.target, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.red_heal_multi()), colour: Colour::Red, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Invert { Base, Plus, PlusPlus } impl Invert { fn duration(self) -> u8 { match self { Invert::Base => 2, Invert::Plus => 3, Invert::PlusPlus => 4 } } fn description(self) -> String { format!("Reverse healing/recharge into damage and damage into healing/recharge. Any excess red or blue damage is converted into shield recharge after healing. Lasts {:?}T.", self.duration()) } } fn invert(cast: Cast, game: &mut Game, values: Invert) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Invert, duration: values.duration(), meta: None }, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Link { Base, Plus, PlusPlus } impl Link { fn duration(self) -> u8 { match self { Link::Base => 1, Link::Plus => 1, Link::PlusPlus => 2 } } fn blue_dmg_base(self) -> usize { match self { Link::Base => 25, Link::Plus => 35, Link::PlusPlus => 45 } } fn description(self) -> String { format!("Stun target for {:?}T. Deal blue damage of {:?}% BluePower multiplied by number of effects on target.", self.duration(), self.blue_dmg_base()) } } fn link(cast: Cast, game: &mut Game, values: Link) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Stun, duration: values.duration(), meta: None }, } ); let bp = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.blue_dmg_base()); let links = game.value(Value::Effects { construct: cast.target }); let amount = bp.pct(100 + 100usize.saturating_mul(links)); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Purge { Base, Plus, PlusPlus } impl Purge { fn duration(self) -> u8 { match self { Purge::Base => 2, Purge::Plus => 3, Purge::PlusPlus => 4 } } fn description(self) -> String { format!("Remove all effects from target construct. Applies purge disabling target green skills for {:?}T.", self.duration()) } } fn purge(cast: Cast, game: &mut Game, values: Purge) { game.action(cast, Action::RemoveAll { construct: cast.target, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Purge, duration: values.duration(), meta: None } }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Purify { Base, Plus, PlusPlus } impl Purify { fn green_heal_base(self) -> usize { match self { Purify::Base => 45, Purify::Plus => 60, Purify::PlusPlus => 85 } } fn duration(self) -> u8 { match self { Purify::Base => 2, Purify::Plus => 3, Purify::PlusPlus => 4 } } fn pure_multi(self) -> usize { match self { Purify::Base => 150, Purify::Plus => 175, Purify::PlusPlus => 200 } } fn description(self) -> String { format!("Remove all effects and heals for {:?}% GreenPower per effect removed. Applies Pure increasing healing taken by {:?}%. Pure lasts {:?}T", self.green_heal_base(), self.pure_multi() - 100, self.duration()) } } fn purify(cast: Cast, game: &mut Game, values: Purify) { let gp = game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }); let rms = game.value(Value::Removals { construct: cast.target }); let amount = gp.pct(values.green_heal_base().saturating_mul(rms)); game.action(cast, Action::RemoveAll { construct: cast.target, } ); game.action(cast, Action::Heal { construct: cast.target, colour: Colour::Green, amount, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Pure, duration: values.duration(), meta: Some(EffectMeta::Multiplier(values.pure_multi())) } }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Recharge { Base, Plus, PlusPlus } impl Recharge { fn heal_multi(self) -> usize { match self { Recharge::Base => 45, Recharge::Plus => 60, Recharge::PlusPlus => 85 } } fn description(self) -> String { format!("Recharge RedLife and BlueLife based on {:?}% RedPower and BluePower.", self.heal_multi()) } } fn recharge(cast: Cast, game: &mut Game, values: Recharge) { game.action(cast, Action::Heal { construct: cast.target, colour: Colour::Red, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.heal_multi()), } ); game.action(cast, Action::Heal { construct: cast.target, colour: Colour::Blue, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.heal_multi()), }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Reflect { Base, Plus, PlusPlus } impl Reflect { fn duration(self) -> u8 { match self { Reflect::Base => 1, Reflect::Plus => 1, Reflect::PlusPlus => 2 } } fn heal_multi(self) -> usize { match self { Reflect::Base => 45, Reflect::Plus => 70, Reflect::PlusPlus => 100 } } fn description(self) -> String { format!("Reflect incoming blue skills to source. Lasts {:?}T. Recharges target BlueLife based on {:?}% BluePower.", self.duration(), self.heal_multi()) } } fn reflect(cast: Cast, game: &mut Game, values: Reflect) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Reflect, duration: values.duration(), meta: None }, } ); game.action(cast, Action::Heal { construct: cast.target, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.heal_multi()), colour: Colour::Blue, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Restrict { Base, Plus, PlusPlus } impl Restrict { fn dmg_multi(self) -> usize { match self { Restrict::Base => 40, Restrict::Plus => 55, Restrict::PlusPlus => 70 } } fn duration(self) -> u8 { match self { Restrict::Base => 2, Restrict::Plus => 2, Restrict::PlusPlus => 3 } } fn description(self) -> String { format!("Disable the target from using red skills for {:?}T and deals {:?}% RedPower as red damage. Deals 35% more damage per red skill on target.", self.duration(), self.dmg_multi()) } } fn restrict(cast: Cast, game: &mut Game, values: Restrict) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Restrict, duration: values.duration(), meta: None } } ); let rp = game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.dmg_multi()); let restricts = game.value(Value::ColourSkills { construct: cast.target, colour: Colour::Red }); let amount = rp.pct(100 + 35usize.saturating_mul(restricts)); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Red, amount, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Ruin { Base, Plus, PlusPlus } impl Ruin { fn dmg_multi(self) -> usize { match self { Ruin::Base => 40, Ruin::Plus => 55, Ruin::PlusPlus => 70 } } fn duration(self) -> u8 { match self { Ruin::Base => 1, Ruin::Plus => 1, Ruin::PlusPlus => 2 } } fn description(self) -> String { format!("Team wide skill. Stun each construct for {:?}T. Deal {:?}% BluePower as blue damage to each construct.", self.duration(), self.dmg_multi()) } } fn ruin(cast: Cast, game: &mut Game, values: Ruin) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Stun, duration: values.duration(), meta: None } } ); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount: game.value(Value::Stat { construct: cast.target, stat: Stat::BluePower }).pct(values.dmg_multi()), } ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Sleep { Base, Plus, PlusPlus } impl Sleep { fn green_heal_multi(self) -> usize { match self { Sleep::Base => 160, Sleep::Plus => 200, Sleep::PlusPlus => 240 } } fn duration(self) -> u8 { match self { Sleep::Base => 2, Sleep::Plus => 2, Sleep::PlusPlus => 3 } } fn description(self) -> String { format!("Stun for {:?}T and heal target for {:?}% GreenPower.", self.duration(), self.green_heal_multi()) } } fn sleep(cast: Cast, game: &mut Game, values: Sleep) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Stun, duration: values.duration(), meta: None }, } ); game.action(cast, Action::Heal { construct: cast.target, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.green_heal_multi()), colour: Colour::Green, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Silence { Base, Plus, PlusPlus } impl Silence { fn dmg_multi(self) -> usize { match self { Silence::Base => 55, Silence::Plus => 65, Silence::PlusPlus => 80 } } fn duration(self) -> u8 { match self { Silence::Base => 2, Silence::Plus => 2, Silence::PlusPlus => 3 } } fn description(self) -> String { format!("Disable the target from using blue skills for {:?}T and deals {:?}% BluePower as blue damage. Deals 45% more Damage per blue skill on target.", self.duration(), self.dmg_multi()) } } fn silence(cast: Cast, game: &mut Game, values: Silence) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Silence, duration: values.duration(), meta: None }, } ); let bp = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.dmg_multi()); let silences = game.value(Value::ColourSkills { construct: cast.target, colour: Colour::Blue }); let amount = bp.pct(100 + 45usize.saturating_mul(silences)); game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, amount, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Sustain { Base, Plus, PlusPlus } impl Sustain { fn duration(self) -> u8 { match self { Sustain::Base => 1, Sustain::Plus => 1, Sustain::PlusPlus => 2 } } fn red_heal_multi(self) -> usize { match self { Sustain::Base => 110, Sustain::Plus => 130, Sustain::PlusPlus => 150 } } fn description(self) -> String { format!("Construct cannot be KO'd while active. Lasts {:?}T. Recharges target RedLife based on {:?}% RedPower.", self.duration(), self.red_heal_multi()) } } fn sustain(cast: Cast, game: &mut Game, values: Sustain) { game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Sustain, duration: values.duration(), meta: None }, } ); game.action(cast, Action::Heal { construct: cast.target, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::RedPower }).pct(values.red_heal_multi()), colour: Colour::Red, }, ); } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum Triage { Base, Plus, PlusPlus } impl Triage { fn heal_multi(self) -> usize { match self { Triage::Base => 75, Triage::Plus => 90, Triage::PlusPlus => 110 } } fn duration(self) -> u8 { match self { Triage::Base => 2, Triage::Plus => 2, Triage::PlusPlus => 4 } } fn description(self) -> String { format!("Heals target for {:?}% GreenPower each turn. Lasts {:?}T.", self.heal_multi(), self.duration()) } } fn triage(cast: Cast, game: &mut Game, values: Triage) { let amount = game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.heal_multi()); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Triage, duration: values.duration(), meta: Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::TriageTick, speed: cast.speed, amount }) }, } ); if game.affected(cast.target, Effect::Triaged) { return; } game.action(cast, Action::Heal { construct: cast.target, colour: Colour::Green, amount, } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Triaged, duration: 1, meta: None }, }, ); } fn triage_tick(cast: Cast, game: &mut Game) { game.action(cast, Action::Heal { construct: cast.target, colour: Colour::Green, amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Triage }), } ); game.action(cast, Action::Effect { construct: cast.target, effect: ConstructEffect { effect: Effect::Triaged, duration: 1, meta: None }, }, ); }