mnml/core/src/skill.rs
2019-12-20 11:06:33 +10:00

2224 lines
74 KiB
Rust

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::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::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::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<Skill> {
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<Item> {
let mut components = Item::from(*self).components();
components.sort_unstable();
return components;
}
pub fn colours(&self) -> Vec<Colour> {
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::<Vec<Colour>>();
}
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 }) },
}
);
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, colour: Colour::Blue }).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, colour: Colour::Blue }).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, colour: Colour::Red }).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, colour: Colour::Blue }).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 }) },
}
);
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 }) },
},
);
game.action(cast,
Action::Damage {
construct: cast.target,
colour: Colour::Blue,
amount,
},
);
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 }),
},
);
}
#[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 }) },
}
);
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 },
},
);
}