2250 lines
74 KiB
Rust
2250 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::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<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 }) },
|
|
}
|
|
);
|
|
|
|
// 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 },
|
|
},
|
|
);
|
|
}
|