diff --git a/core/src/game.rs b/core/src/game.rs index 9258c2e0..a09f4647 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -26,8 +26,10 @@ pub enum Phase { #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Value { Stat { construct: Uuid, stat: Stat, mult: usize }, - Fixed { amount: usize }, + Fixed { value: usize }, Cooldowns { construct: Uuid, mult: usize }, + ColourSkills { construct: Uuid, colour: Colour, mult: usize }, + DamageTaken { construct: Uuid, colour: Colour, mult: usize }, // Skills { construct: Uuid, colour: Colour }, } @@ -40,12 +42,12 @@ pub enum Colour { #[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] pub enum Action { + Cast { construct: Uuid, skill: Skill }, Hit { construct: Uuid, skill: Skill }, - HitCast { construct: Uuid, skill: Skill, source: Uuid }, Damage { construct: Uuid, values: Vec, colour: Colour }, + Healing { construct: Uuid, values: Vec, colour: Colour }, Effect { construct: Uuid, effect: ConstructEffect }, IncreaseCooldowns { construct: Uuid, turns: usize }, - // Recharge { skill: Skill, red: usize, blue: usize }, } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -191,7 +193,9 @@ impl Game { } fn skill_phase_start(mut self, resolution_animation_ms: i64) -> Game { - self.phase_start = Utc::now() + self.events.push(vec![]); + + self.phase_start = Utc::now() .checked_add_signed(Duration::milliseconds(resolution_animation_ms)) .expect("could not set phase start"); @@ -413,8 +417,6 @@ impl Game { } pub fn resolve_phase_start(mut self) -> Game { - self.events.push(vec![]); - if self.phase != Phase::Skill { panic!("game not in skill phase"); } @@ -493,54 +495,49 @@ impl Game { self.skill_phase_start(r_animation_ms) } - fn event_add(&mut self, mut events: Vec) -> &mut Game { - self.events.last_mut().unwrap().append(&mut events); - self - } - pub fn actions(&mut self, actions: Vec) -> &mut Game { + let mut events_group = vec![]; + + // calculate values first? + // for result damage value need to pass &events and .find() + for action in actions { - match action { + let mut events = match action { + Action::Cast { construct, skill } => self.cast(construct, skill), Action::Hit { construct, skill } => self.hit(construct, skill), - Action::HitCast { construct, skill, source } => self.hit_cast(construct, skill, source), Action::Damage { construct, values, colour } => self.damage(construct, values, colour), + Action::Healing { construct, values, colour } => unimplemented!(), Action::Effect { construct, effect } => self.effect(construct, effect), Action::IncreaseCooldowns { construct, turns } => self.increase_cooldowns(construct, turns), }; + + events_group.append(&mut events); } + self.events.last_mut().unwrap().append(&mut events_group); self } - fn hit_cast(&mut self, construct: Uuid, skill: Skill, source: Uuid) -> &mut Game { - self.event_add(vec![Event::new(EventVariant::HitCast { skill: skill, source: source }, construct)]); - self + fn cast(&mut self, construct: Uuid, skill: Skill) -> Vec { + vec![Event::new(EventVariant::Cast { skill: skill }, construct)] } - fn hit(&mut self, construct: Uuid, skill: Skill) -> &mut Game { - self.event_add(vec![Event::new(EventVariant::Hit { skill: skill }, construct)]); - self + fn hit(&mut self, construct: Uuid, skill: Skill) -> Vec { + vec![Event::new(EventVariant::Hit { skill: skill }, construct)] } - fn damage(&mut self, construct: Uuid, values: Vec, colour: Colour) -> &mut Game { - let events = match colour { + fn damage(&mut self, construct: Uuid, values: Vec, colour: Colour) -> Vec { + match colour { _ => self.construct_by_id(construct).unwrap().deal_red_damage(128) // fixme unwrap - }; - - self.event_add(events); - self + } } - fn effect(&mut self, construct: Uuid, effect: ConstructEffect) -> &mut Game { - let events = self.construct_by_id(construct).unwrap().add_effect(effect); - self.event_add(events); - self + fn effect(&mut self, construct: Uuid, effect: ConstructEffect) -> Vec { + self.construct_by_id(construct).unwrap().add_effect(effect) } - fn increase_cooldowns(&mut self, construct: Uuid, turns: usize) -> &mut Game { - let events = self.construct_by_id(construct).unwrap().increase_cooldowns(turns); - self.event_add(events); - self + fn increase_cooldowns(&mut self, construct: Uuid, turns: usize) -> Vec { + self.construct_by_id(construct).unwrap().increase_cooldowns(turns) } fn progress_durations(&mut self, events: &Vec) -> &mut Game { diff --git a/core/src/skill.rs b/core/src/skill.rs index a0282286..02ee2586 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -8,6 +8,693 @@ use game::{Game, Colour, Value, Action}; use construct::{Construct, ConstructEffect, EffectMeta, Stat}; use effect::{Effect, Cooldown}; +#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] +pub struct Cast { + pub id: Uuid, + pub player: Uuid, + pub source: Uuid, + pub target: Uuid, + pub skill: Skill, + pub speed: usize, +} + +fn start() {} + +impl Cast { + pub fn new(source: Uuid, player: Uuid, target: Uuid, skill: Skill) -> Cast { + return Cast { + id: Uuid::new_v4(), + source, + player, + target, + skill, + speed: 0, + }; + } + + pub fn new_tick(source: &mut Construct, target: &mut Construct, skill: Skill) -> Cast { + Cast { + id: Uuid::new_v4(), + source: source.id, + player: source.account, + target: target.id, + skill, + speed: source.skill_speed(skill), + } + } + + pub fn used_cooldown(&self) -> bool { + return self.skill.base_cd().is_some(); + } + + pub fn actions(&self) -> Vec { + let mut rng = thread_rng(); + + let mut actions = vec![]; + + if self.skill.cast_animation() { + actions.push({ Action::Cast { construct: self.target, skill: self.skill }}); + } + + actions.push(Action::Hit { construct: self.target, skill: self.skill }); + + let mut rest = match self.skill { + Skill::Attack => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], + }, + ], + + Skill::Block => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Block, duration: 1, meta: Some(EffectMeta::Multiplier(35)), tick: None }, + }, + ], + + Skill::Buff => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Buff, duration: 3, meta: Some(EffectMeta::Multiplier(130)), tick: None }, + }, + ], + + + + Skill::Amplify => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }, + }, + ], + Skill::AmplifyPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }, + }, + ], + Skill::AmplifyPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None }, + }, + ], + + Skill::Absorb => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::Absorption)), tick: None }, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], + colour: Colour::Blue, + }, + ], + Skill::AbsorbPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlus)), tick: None }, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], + colour: Colour::Blue, + }, + ], + Skill::AbsorbPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlusPlus)), tick: None }, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], + colour: Colour::Blue, + }, + ], + + Skill::Banish | + Skill::BanishPlus | + Skill::BanishPlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![Value::Stat { construct: self.target, stat: Stat::RedLife, mult: self.skill.multiplier() }], + }, + Action::Damage { + construct: self.target, + colour: Colour::Blue, + values: vec![Value::Stat { construct: self.target, stat: Stat::BlueLife, mult: self.skill.multiplier() }], + }, + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None } + } + ], + + Skill::Bash | + Skill::BashPlus | + Skill::BashPlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![ + Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }, + Value::Cooldowns { construct: self.source, mult: 45 }, + ], + }, + Action::Effect { + construct: self.target, + effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None } + }, + Action::IncreaseCooldowns { + construct: self.target, + turns: 1, + }, + ], + + Skill::Blast | + Skill::BlastPlus | + Skill::BlastPlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Blue, + values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], + }, + ], + + Skill::Break => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None}, + }, + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Vulnerable, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None, }, + }, + ], + Skill::BreakPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Stun, duration: 1, meta: None, tick: None}, + }, + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(175)), tick: None, }, + }, + ], + Skill::BreakPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Stun, duration: 2, meta: None, tick: None}, + }, + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None, }, + }, + ], + + Skill::Chaos | + Skill::ChaosPlus | + Skill::ChaosPlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![ + Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }, + Value::Stat { construct: self.source, stat: Stat::RedPower, mult: rng.gen_range(0, 30) }, + ], + }, + Action::Damage { + construct: self.target, + colour: Colour::Blue, + values: vec![ + Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }, + Value::Stat { construct: self.source, stat: Stat::BluePower, mult: rng.gen_range(0, 30) }, + ], + }, + ], + + Skill::Counter => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None }, + }, + ], + Skill::CounterPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None }, + }, + ], + Skill::CounterPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None }, + }, + ], + Skill::CounterAttack | + Skill::CounterAttackPlus | + Skill::CounterAttackPlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], + }, + ], + + Skill::Intercept | + Skill::InterceptPlus | + Skill::InterceptPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect {effect: Effect::Intercept, duration: 1, meta: None, tick: None}, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], + colour: Colour::Red, + }, + ], + + Skill::Restrict | + Skill::RestrictPlus | + Skill::RestrictPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect { effect: Effect::Restrict, duration: 2, meta: None, tick: None } + }, + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![Value::ColourSkills { construct: self.source, colour: Colour::Red, mult: self.skill.multiplier() }], + }, + ], + + + + Skill::Slay | + Skill::SlayPlus | + Skill::SlayPlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], + }, + Action::Healing { + construct: self.target, + colour: Colour::Green, + values: vec![Value::DamageTaken { construct: self.target, colour: Colour::Red, mult: 50 }], + }, + ], + +// fn slay(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.red_power().pct(skill.multiplier()) + source.green_power().pct(skill.multiplier()); +// let slay_events = target.deal_red_damage(skill, amount); + +// for e in slay_events { +// match e { +// Event::Damage { amount, mitigation: _, colour: _, skill: _ } => { +// game.event(Event::new(source, target).event(e)); +// let heal = source.deal_green_damage(skill, amount.pct(50)); +// for h in heal { +// game.event(Event::new(source, source).event(h).stages(EventStages::PostOnly)); +// }; +// }, +// _ => game.event(Event::new(source, target).event(e)), +// } +// } + +// } + + Skill::Sleep => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], + colour: Colour::Blue, + }, + ], + Skill::SleepPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], + colour: Colour::Blue, + }, + ], + Skill::SleepPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }], + colour: Colour::Blue, + }, + ], + + Skill::Strike | + Skill::StrikePlus | + Skill::StrikePlusPlus => vec![ + Action::Damage { + construct: self.target, + colour: Colour::Red, + values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], + }, + ], + + Skill::Sustain | + Skill::SustainPlus | + Skill::SustainPlusPlus => vec![ + Action::Effect { + construct: self.target, + effect: ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None}, + }, + Action::Healing { + construct: self.target, + values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], + colour: Colour::Red, + }, + ], + + _ => unimplemented!() + }; + + actions.append(&mut rest); + return actions; + } +} + +fn end() {} + + +// fn heal(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.green_power().pct(skill.multiplier()); +// target.deal_green_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e))); +// } + +// fn triage(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let skip_tick = target.effects.iter().any(|e| { +// match e.effect { +// Effect::Triage => source.skill_speed(skill) <= e.tick.unwrap().speed, +// _ => false, +// } +// }); + +// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0]; +// let tick_skill = match meta { +// Some(EffectMeta::Skill(s)) => s, +// _ => panic!("no triage tick skill"), +// }; +// let triage = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); +// game.event(Event::new(source, target).event(target.add_effect(skill, triage))); + +// match skip_tick { +// false => return triage_tick(source, target, resolutions, tick_skill) +// } +// } + +// fn triage_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.green_power().pct(skill.multiplier()); +// target.deal_green_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::EndPost))); +// } + +// fn amplify(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// } + +// fn haste(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// } + +// fn debuff(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// } + +// fn decay(source: &mut Construct, target: &mut Construct, skill: Skill) { + +// let wither = skill.effect()[0]; +// game.event(Event::new(source, target).event(target.add_effect(skill, wither))); + +// let skip_tick = target.effects.iter().any(|e| { +// match e.effect { +// Effect::Decay => source.skill_speed(skill) <= e.tick.unwrap().speed, +// _ => false, +// } +// }); +// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[1]; +// let tick_skill = match meta { +// Some(EffectMeta::Skill(s)) => s, +// _ => panic!("no decay tick skill"), +// }; +// let decay = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); +// game.event(Event::new(source, target) +// .event(target.add_effect(skill, decay)) +// .stages(EventStages::PostOnly)); + +// match skip_tick { +// false => return decay_tick(source, target, resolutions, tick_skill) +// } +// } + +// fn decay_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.blue_power().pct(skill.multiplier()); +// target.deal_blue_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::EndPost))); +// } + +// // electrify is the buff effect +// // when attacked it runs electrocute and applies a debuff +// fn electrify(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let electrify = skill.effect()[0]; +// game.event(Event::new(source, target).event(target.add_effect(skill, electrify))); +// } + +// fn electrocute(source: &mut Construct, target: &mut Construct, skill: Skill) { +// // Remove electric buff, no need to display if construct is dead +// if !source.is_ko() { +// let electric = source.effects.iter().position(|e| e.effect == Effect::Electric); +// match electric { +// Some(eff) => { +// let ce = source.effects.remove(eff); +// game.event(Event::new(source, source) +// .event(Event::Removal { skill, effect: Some(ce.effect), construct_effects: source.effects.clone() }) +// .stages(EventStages::PostOnly)); +// } +// None => () +// } +// } + +// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0]; +// let tick_skill = match meta { +// Some(EffectMeta::Skill(s)) => s, +// _ => panic!("no electrocute tick skill"), +// }; + +// let skip_tick = target.effects.iter().any(|e| { +// match e.effect { +// Effect::Electrocute => source.skill_speed(skill) <= e.tick.unwrap().speed, +// _ => false, +// } +// }); +// let electrocute = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); +// game.event(Event::new(source, target) +// .event(target.add_effect(skill, electrocute)) +// .stages(EventStages::PostOnly)); + + +// match skip_tick { +// false => return electrocute_tick(source, target, resolutions, tick_skill) +// } +// } + +// fn electrocute_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.blue_power().pct(skill.multiplier()); +// target.deal_blue_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::EndPost))); +// } + +// fn ruin(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.blue_power().pct(skill.multiplier()); +// target.deal_blue_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); + +// game.event(Event::new(source, target) +// .event(target.add_effect(skill, skill.effect()[0])) +// .stages(EventStages::PostOnly)); +// } + +// fn absorb(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// let blue_amount = source.blue_power().pct(skill.multiplier()); +// target.recharge(skill, 0, blue_amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); +// } + +// fn absorption(source: &mut Construct, target: &mut Construct, reflect_skill: Skill, amount: usize, skill: Skill) { +// let absorb = skill.effect()[0].set_meta(EffectMeta::AddedDamage(amount)); + +// game.event(Event::new(source, target) +// .event(target.add_effect(reflect_skill, absorb)) +// .stages(EventStages::PostOnly)); + +// let absorb_index = target.effects.iter().position(|e| e.effect == Effect::Absorb).expect("No absorb"); +// let ce = target.effects.remove(absorb_index); + +// game.event(Event::new(source, target) +// .event(Event::Removal { skill, effect: Some(ce.effect), construct_effects: target.effects.clone() }) +// .stages(EventStages::PostOnly)); +// } + +// fn curse(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// } + +// fn hybrid(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// } + +// fn invert(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); +// } + +// fn reflect(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); + +// let blue_amount = source.blue_power().pct(skill.multiplier()); +// target.recharge(skill, 0, blue_amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); + +// } + +// fn recharge(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); +// let red_amount = source.red_power().pct(skill.multiplier()); +// let blue_amount = source.blue_power().pct(skill.multiplier()); +// target.recharge(skill, red_amount, blue_amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); + +// } + +// fn siphon(source: &mut Construct, target: &mut Construct, skill: Skill) { + +// let skip_tick = target.effects.iter().any(|e| { +// match e.effect { +// Effect::Siphon => source.skill_speed(skill) <= e.tick.unwrap().speed, +// _ => false, +// } +// }); +// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0]; +// let tick_skill = match meta { +// Some(EffectMeta::Skill(s)) => s, +// _ => panic!("no siphon tick skill"), +// }; +// let siphon = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); +// game.event(Event::new(source, target).event(target.add_effect(skill, siphon))); + +// match skip_tick { +// false => return siphon_tick(source, target, resolutions, tick_skill) +// } +// } + +// fn siphon_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { +// let amount = source.blue_power().pct(skill.multiplier()) + source.green_power().pct(skill.multiplier()); +// let siphon_events = target.deal_blue_damage(skill, amount); + +// for e in siphon_events { +// match e { +// Event::Damage { amount, mitigation: _, colour: _, skill: _ } => { +// game.event(Event::new(source, target).event(e).stages(EventStages::EndPost)); +// let heal = source.deal_green_damage(skill, amount); +// for h in heal { +// game.event(Event::new(source, source).event(h).stages(EventStages::PostOnly)); +// }; +// }, +// _ => game.event(Event::new(source, target).event(e).stages(EventStages::EndPost)), +// } +// } + +// } + +// fn link(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); + +// let amount = source.blue_power().pct(skill.multiplier().saturating_mul(target.effects.len() as usize)); +// target.deal_blue_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); + +// } + +// fn silence(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); + +// let s_multi = target.skills +// .iter() +// .fold(100, |acc, cs| match cs.skill.colours().contains(&Colour::Blue) { +// true => acc + 45, +// false => acc, +// }); + +// let amount = source.blue_power().pct(skill.multiplier()).pct(s_multi); +// target.deal_blue_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); + +// } + +// fn purge(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); +// if target.effects.len() > 0 { +// target.effects.clear(); +// game.event(Event::new(source, target) +// .event(Event::Removal { skill, effect: None, construct_effects: target.effects.clone() }) +// .stages(EventStages::PostOnly)); +// } + +// let effect = skill.effect()[0]; +// game.event(Event::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); + +// } + +// fn purify(source: &mut Construct, target: &mut Construct, skill: Skill) { +// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); +// if target.effects.len() > 0 { +// let amount = source.green_power().pct(skill.multiplier().saturating_mul(target.effects.len() as usize)); +// target.effects.clear(); +// game.event(Event::new(source, target) +// .event(Event::Removal { skill, effect: None, construct_effects: target.effects.clone() }) +// .stages(EventStages::PostOnly)); +// target.deal_green_damage(skill, amount) +// .into_iter() +// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); +// } +// let effect = skill.effect()[0]; +// game.event(Event::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); + +// } + // pub fn dev_resolve(a_id: Uuid, b_id: Uuid, skill: Skill) { // let mut resolutions =vec![]; @@ -67,170 +754,33 @@ pub fn resolve(game: &mut Game, cast: Cast) { } -#[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 new_tick(source: &mut Construct, target: &mut Construct, skill: Skill) -> Cast { - Cast { - id: Uuid::new_v4(), - source: source.id, - player: source.account, - target: target.id, - skill, - speed: source.skill_speed(skill), - } - } - - pub fn used_cooldown(&self) -> bool { - return self.skill.base_cd().is_some(); - } - - pub fn actions(&self) -> Vec { - let mut actions = match self.skill.is_tick() { - false => vec![Action::HitCast { construct: self.target, skill: self.skill, source: self.source }], - true => vec![Action::Hit { construct: self.target, skill: self.skill }] - }; - - let mut rest = match self.skill { - Skill::Amplify => vec![ - Action::Effect { - construct: self.target, - effect: ConstructEffect { effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }, - }, - ], - Skill::AmplifyPlus => vec![ - Action::Effect { - construct: self.target, - effect: ConstructEffect { effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }, - }, - ], - Skill::AmplifyPlusPlus => vec![ - Action::Effect { - construct: self.target, - effect: ConstructEffect { effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None }, - }, - ], - - Skill::Attack => vec![ - Action::Damage { - construct: self.target, - colour: Colour::Red, - values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], - }, - ], - - - Skill::Banish => vec![ - Action::Effect { - construct: self.target, - effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None } - } - ], - Skill::BanishPlus => vec![ - Action::Effect { - construct: self.target, - effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None } - } - ], - Skill::BanishPlusPlus => vec![ - Action::Effect { - construct: self.target, - effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None } - } - ], - - Skill::Bash | - Skill::BashPlus | - Skill::BashPlusPlus => vec![ - Action::Damage { - construct: self.target, - colour: Colour::Red, - values: vec![ - Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }, - Value::Cooldowns { construct: self.source, mult: 45 }, - ], - }, - Action::Effect { - construct: self.target, - effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None } - }, - Action::IncreaseCooldowns { - construct: self.target, - turns: 1, - }, - ], - - Skill::Blast | - Skill::BlastPlus | - Skill::BlastPlusPlus => vec![ - Action::Damage { - construct: self.target, - colour: Colour::Blue, - values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], - }, - ], - - Skill::Strike | - Skill::StrikePlus | - Skill::StrikePlusPlus => vec![ - Action::Damage { - construct: self.target, - colour: Colour::Red, - values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], - }, - ], - - _ => unimplemented!() - }; - - actions.append(&mut rest); - return actions; - } -} - pub type Disable = Vec; #[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] pub struct Event { pub target: Uuid, pub variant: EventVariant, + pub stages: EventStages, pub delay: i64, } impl Event { pub fn new(variant: EventVariant, target: Uuid) -> Event { - let delay = variant.delay(); + let stages = variant.stages(); + Event { target, variant, - delay, + delay: stages.delay(), + stages: stages, } } } #[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] pub enum EventVariant { + Cast { skill: Skill }, Hit { skill: Skill }, - HitCast { skill: Skill, source: Uuid }, Damage { amount: usize, mitigation: usize, colour: Colour, display: EventConstruct }, Effect { effect: Effect, duration: u8, display: EventConstruct }, @@ -256,17 +806,48 @@ pub enum EventVariant { } impl EventVariant { - fn delay(&self) -> i64 { - // let source_duration = 1000; // Time for SOURCE ONLY - let target_duration = 1500; // Time for target animation - let target_delay = 500; // Add delay if theres source animation - let combat_text_delay = 1300; // Time for all post skill - let combat_text_overlap = 600; // overlap between animation and combat text + fn stages(&self) -> EventStages { + match self { + EventVariant::Disable { disable: _} + => EventStages::PostOnly, + EventVariant::Damage { amount: _, mitigation: _, colour: _, display: _ } + => EventStages::PostOnly, + EventVariant::Healing { amount: _, overhealing: _} + => EventStages::PostOnly, + EventVariant::Recharge { red: _, blue: _} + => EventStages::PostOnly, + EventVariant::Inversion { skill: _ } + => EventStages::PostOnly, + EventVariant::Reflection { skill: _ } + => EventStages::PostOnly, + EventVariant::AoeSkill { skill: _ } + => EventStages::PostOnly, + EventVariant::Skill { skill: _ } + => EventStages::PostOnly, + EventVariant::Effect { effect: _, duration: _, display: _ } + => EventStages::PostOnly, + EventVariant::Removal { effect: _, display: _ } + => EventStages::PostOnly, + EventVariant::TargetKo { skill: _ } + => EventStages::PostOnly, + EventVariant::Ko () + => EventStages::PostOnly, + EventVariant::Forfeit () + => EventStages::PostOnly, + EventVariant::Incomplete () + => EventStages::PostOnly, + EventVariant::Evasion { skill: _, evasion_rating: _ } + => EventStages::PostOnly, - match self { - EventVariant::Hit { skill: _ } => target_duration - combat_text_overlap, - EventVariant::HitCast { skill: _, source: _ } => target_delay + target_duration - combat_text_overlap, - _ => combat_text_delay, + EventVariant::CooldownDecrease { skill: _, turns: _ } + => EventStages::PostOnly, + EventVariant::CooldownIncrease { skill: _, turns: _ } + => EventStages::PostOnly, + + EventVariant::Hit { skill: _ } + => EventStages::PostOnly, + EventVariant::Cast { skill: _ } + => EventStages::PostOnly, } } } @@ -292,6 +873,44 @@ impl EventConstruct { } } +#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] +pub enum EventStages { + #[serde(rename = "START_SKILL END_SKILL POST_SKILL")] + AllStages, // Anim Anim Anim + #[serde(rename = "START_SKILL END_SKILL")] + StartEnd, // Anim Anim Skip + #[serde(rename = "START_SKILL POST_SKILL")] + StartPost, // Anim Skip Anim + #[serde(rename = "START_SKILL")] + StartOnly, // Anim Skip Skip + #[serde(rename = "END_SKILL POST_SKILL")] + EndPost, // Skip Anim Anim + #[serde(rename = "END_SKILL")] + EndOnly, // Skip Anim Skip + #[serde(rename = "POST_SKILL")] + PostOnly, // Skip Skip Anim +} + +impl EventStages { + fn delay(self) -> i64 { + let source_duration = 1000; // Time for SOURCE ONLY + let target_delay = 500; // Used for Source + Target + let target_duration = 1500; // Time for TARGET ONLY + let post_skill = 1000; // Time for all POST + let source_and_target_total = target_delay + target_duration; // SOURCE + TARGET time + + match self { + EventStages::AllStages => source_and_target_total + post_skill, // Anim Anim Anim + EventStages::StartEnd => source_and_target_total, // Anim Anim Skip + EventStages::StartPost => source_duration + post_skill, // Anim Skip Anim + EventStages::StartOnly => source_duration, // Anim Skip Skip + EventStages::EndPost => target_duration + post_skill, // Skip Anim Anim + EventStages::EndOnly => target_duration, // Skip Anim Skip + EventStages::PostOnly => post_skill, // Skip Skip Anim + } + } +} + #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Skill { Attack, @@ -971,6 +1590,35 @@ impl Skill { } } + fn cast_animation(&self) -> bool { + match self { + Skill::HybridBlast | + Skill::HasteStrike | + Skill::CounterAttack| + Skill::CounterAttackPlus | + Skill::CounterAttackPlusPlus | // counter + Skill::Electrocute| + Skill::ElectrocutePlus | + Skill::ElectrocutePlusPlus | + Skill::Absorption| + Skill::AbsorptionPlus | + Skill::AbsorptionPlusPlus | + Skill::ElectrocuteTick| + Skill::ElectrocuteTickPlus | + Skill::ElectrocuteTickPlusPlus | + Skill::DecayTick| + Skill::DecayTickPlus | + Skill::DecayTickPlusPlus | + Skill::SiphonTick| + Skill::SiphonTickPlus | + Skill::SiphonTickPlusPlus | + Skill::TriageTick| + Skill::TriageTickPlus | + Skill::TriageTickPlusPlus => false, + _ => true, + } + } + pub fn ko_castable(&self) -> bool { match self { Skill::ElectrocuteTick | @@ -1114,437 +1762,8 @@ impl Skill { } } -// fn sleep(source: &mut Construct, target: &mut Construct, skill: Skill) { -// skill.effect().into_iter() -// .for_each(|e| (game.event(Event::new(source, target).event(target.add_effect(skill, e))))); -// let amount = source.green_power().pct(skill.multiplier()); -// target.deal_green_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); -// } - -// fn sustain(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); - -// let red_amount = source.red_power().pct(skill.multiplier()); -// target.recharge(skill, red_amount, 0) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// } - -// fn intercept(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let intercept = skill.effect()[0]; -// game.event(Event::new(source, target).event(target.add_effect(skill, intercept))); - -// let red_amount = source.red_power().pct(skill.multiplier()); -// target.recharge(skill, red_amount, 0) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// } - -// fn break_(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let stun = skill.effect()[0]; -// game.event(Event::new(source, target).event(target.add_effect(skill, stun))); -// let vuln = skill.effect()[1]; -// game.event(Event::new(source, target).event(target.add_effect(skill, vuln)).stages(EventStages::PostOnly)); - -// } - -// fn block(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn buff(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target) -// .event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn counter(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target) -// .event(target.add_effect(skill, skill.effect()[0]))); - -// } - -// fn counter_attack(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.red_power().pct(skill.multiplier()); -// target.deal_red_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e))); - -// } - -// fn restrict(source: &mut Construct, target: &mut Construct, skill: Skill) { -// skill.effect().into_iter() -// .for_each(|e| (game.event(Event::new(source, target).event(target.add_effect(skill, e))))); - -// let s_multi = target.skills -// .iter() -// .fold(100, |acc, cs| match cs.skill.colours().contains(&Colour::Red) { -// true => acc + 35, -// false => acc, -// }); - -// let amount = source.red_power().pct(skill.multiplier()).pct(s_multi); -// target.deal_red_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - - -// } - -// fn slay(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.red_power().pct(skill.multiplier()) + source.green_power().pct(skill.multiplier()); -// let slay_events = target.deal_red_damage(skill, amount); - -// for e in slay_events { -// match e { -// Event::Damage { amount, mitigation: _, colour: _, skill: _ } => { -// game.event(Event::new(source, target).event(e)); -// let heal = source.deal_green_damage(skill, amount.pct(50)); -// for h in heal { -// game.event(Event::new(source, source).event(h).stages(EventStages::PostOnly)); -// }; -// }, -// _ => game.event(Event::new(source, target).event(e)), -// } -// } - -// } - -// fn heal(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.green_power().pct(skill.multiplier()); -// target.deal_green_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e))); -// } - -// fn triage(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let skip_tick = target.effects.iter().any(|e| { -// match e.effect { -// Effect::Triage => source.skill_speed(skill) <= e.tick.unwrap().speed, -// _ => false, -// } -// }); - -// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0]; -// let tick_skill = match meta { -// Some(EffectMeta::Skill(s)) => s, -// _ => panic!("no triage tick skill"), -// }; -// let triage = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); -// game.event(Event::new(source, target).event(target.add_effect(skill, triage))); - -// match skip_tick { -// false => return triage_tick(source, target, resolutions, tick_skill) -// } -// } - -// fn triage_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.green_power().pct(skill.multiplier()); -// target.deal_green_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::EndPost))); -// } - -// fn chaos(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let mut rng = thread_rng(); -// let b_rng: usize = rng.gen_range(100, 130); -// let amount = source.blue_power().pct(skill.multiplier()).pct(b_rng); -// target.deal_blue_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e))); -// let r_rng: usize = rng.gen_range(100, 130); -// let amount = source.red_power().pct(skill.multiplier()).pct(r_rng); -// target.deal_red_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); -// } - -// fn amplify(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn haste(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn debuff(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn decay(source: &mut Construct, target: &mut Construct, skill: Skill) { - -// let wither = skill.effect()[0]; -// game.event(Event::new(source, target).event(target.add_effect(skill, wither))); - -// let skip_tick = target.effects.iter().any(|e| { -// match e.effect { -// Effect::Decay => source.skill_speed(skill) <= e.tick.unwrap().speed, -// _ => false, -// } -// }); -// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[1]; -// let tick_skill = match meta { -// Some(EffectMeta::Skill(s)) => s, -// _ => panic!("no decay tick skill"), -// }; -// let decay = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); -// game.event(Event::new(source, target) -// .event(target.add_effect(skill, decay)) -// .stages(EventStages::PostOnly)); - -// match skip_tick { -// false => return decay_tick(source, target, resolutions, tick_skill) -// } -// } - -// fn decay_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.blue_power().pct(skill.multiplier()); -// target.deal_blue_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::EndPost))); -// } - -// // electrify is the buff effect -// // when attacked it runs electrocute and applies a debuff -// fn electrify(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let electrify = skill.effect()[0]; -// game.event(Event::new(source, target).event(target.add_effect(skill, electrify))); -// } - -// fn electrocute(source: &mut Construct, target: &mut Construct, skill: Skill) { -// // Remove electric buff, no need to display if construct is dead -// if !source.is_ko() { -// let electric = source.effects.iter().position(|e| e.effect == Effect::Electric); -// match electric { -// Some(eff) => { -// let ce = source.effects.remove(eff); -// game.event(Event::new(source, source) -// .event(Event::Removal { skill, effect: Some(ce.effect), construct_effects: source.effects.clone() }) -// .stages(EventStages::PostOnly)); -// } -// None => () -// } -// } - -// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0]; -// let tick_skill = match meta { -// Some(EffectMeta::Skill(s)) => s, -// _ => panic!("no electrocute tick skill"), -// }; - -// let skip_tick = target.effects.iter().any(|e| { -// match e.effect { -// Effect::Electrocute => source.skill_speed(skill) <= e.tick.unwrap().speed, -// _ => false, -// } -// }); -// let electrocute = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); -// game.event(Event::new(source, target) -// .event(target.add_effect(skill, electrocute)) -// .stages(EventStages::PostOnly)); - - -// match skip_tick { -// false => return electrocute_tick(source, target, resolutions, tick_skill) -// } -// } - -// fn electrocute_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.blue_power().pct(skill.multiplier()); -// target.deal_blue_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::EndPost))); -// } - -// fn ruin(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.blue_power().pct(skill.multiplier()); -// target.deal_blue_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// game.event(Event::new(source, target) -// .event(target.add_effect(skill, skill.effect()[0])) -// .stages(EventStages::PostOnly)); -// } - -// fn absorb(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// let blue_amount = source.blue_power().pct(skill.multiplier()); -// target.recharge(skill, 0, blue_amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); -// } - -// fn absorption(source: &mut Construct, target: &mut Construct, reflect_skill: Skill, amount: usize, skill: Skill) { -// let absorb = skill.effect()[0].set_meta(EffectMeta::AddedDamage(amount)); - -// game.event(Event::new(source, target) -// .event(target.add_effect(reflect_skill, absorb)) -// .stages(EventStages::PostOnly)); - -// let absorb_index = target.effects.iter().position(|e| e.effect == Effect::Absorb).expect("No absorb"); -// let ce = target.effects.remove(absorb_index); - -// game.event(Event::new(source, target) -// .event(Event::Removal { skill, effect: Some(ce.effect), construct_effects: target.effects.clone() }) -// .stages(EventStages::PostOnly)); -// } - -// fn curse(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn hybrid(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn invert(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); -// } - -// fn reflect(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); - -// let blue_amount = source.blue_power().pct(skill.multiplier()); -// target.recharge(skill, 0, blue_amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// } - -// fn recharge(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); -// let red_amount = source.red_power().pct(skill.multiplier()); -// let blue_amount = source.blue_power().pct(skill.multiplier()); -// target.recharge(skill, red_amount, blue_amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// } - -// fn siphon(source: &mut Construct, target: &mut Construct, skill: Skill) { - -// let skip_tick = target.effects.iter().any(|e| { -// match e.effect { -// Effect::Siphon => source.skill_speed(skill) <= e.tick.unwrap().speed, -// _ => false, -// } -// }); -// let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0]; -// let tick_skill = match meta { -// Some(EffectMeta::Skill(s)) => s, -// _ => panic!("no siphon tick skill"), -// }; -// let siphon = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill)); -// game.event(Event::new(source, target).event(target.add_effect(skill, siphon))); - -// match skip_tick { -// false => return siphon_tick(source, target, resolutions, tick_skill) -// } -// } - -// fn siphon_tick(source: &mut Construct, target: &mut Construct, skill: Skill) { -// let amount = source.blue_power().pct(skill.multiplier()) + source.green_power().pct(skill.multiplier()); -// let siphon_events = target.deal_blue_damage(skill, amount); - -// for e in siphon_events { -// match e { -// Event::Damage { amount, mitigation: _, colour: _, skill: _ } => { -// game.event(Event::new(source, target).event(e).stages(EventStages::EndPost)); -// let heal = source.deal_green_damage(skill, amount); -// for h in heal { -// game.event(Event::new(source, source).event(h).stages(EventStages::PostOnly)); -// }; -// }, -// _ => game.event(Event::new(source, target).event(e).stages(EventStages::EndPost)), -// } -// } - -// } - -// fn link(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); - -// let amount = source.blue_power().pct(skill.multiplier().saturating_mul(target.effects.len() as usize)); -// target.deal_blue_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// } - -// fn silence(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); - -// let s_multi = target.skills -// .iter() -// .fold(100, |acc, cs| match cs.skill.colours().contains(&Colour::Blue) { -// true => acc + 45, -// false => acc, -// }); - -// let amount = source.blue_power().pct(skill.multiplier()).pct(s_multi); -// target.deal_blue_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); - -// } - -// fn purge(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); -// if target.effects.len() > 0 { -// target.effects.clear(); -// game.event(Event::new(source, target) -// .event(Event::Removal { skill, effect: None, construct_effects: target.effects.clone() }) -// .stages(EventStages::PostOnly)); -// } - -// let effect = skill.effect()[0]; -// game.event(Event::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); - -// } - -// fn purify(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); -// if target.effects.len() > 0 { -// let amount = source.green_power().pct(skill.multiplier().saturating_mul(target.effects.len() as usize)); -// target.effects.clear(); -// game.event(Event::new(source, target) -// .event(Event::Removal { skill, effect: None, construct_effects: target.effects.clone() }) -// .stages(EventStages::PostOnly)); -// target.deal_green_damage(skill, amount) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); -// } -// let effect = skill.effect()[0]; -// game.event(Event::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); - -// } - -// fn banish(source: &mut Construct, target: &mut Construct, skill: Skill) { -// game.event(Event::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd)); - -// let red_damage = target.red_life().pct(skill.multiplier()); -// let blue_damage = target.blue_life().pct(skill.multiplier()); - -// if red_damage > 0 { -// target.deal_red_damage(skill, red_damage) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); -// } - -// if blue_damage > 0 { -// target.deal_blue_damage(skill, blue_damage) -// .into_iter() -// .for_each(|e| game.event(Event::new(source, target).event(e).stages(EventStages::PostOnly))); -// } - -// game.event(Event::new(source, target).event(target.add_effect(skill, skill.effect()[0])).stages(EventStages::PostOnly)); -// } // #[cfg(test)] mod tests { @@ -1997,164 +2216,6 @@ mod tests { // false => (), // } - // match skill { - // Skill::Amplify| - // Skill::AmplifyPlus | - // Skill::AmplifyPlusPlus => amplify(game, skill), - - // Skill::Banish| - // Skill::BanishPlus | - // Skill::BanishPlusPlus => banish(game, skill), - - // Skill::Bash| - // Skill::BashPlus | - // Skill::BashPlusPlus => bash(game, skill), - - // Skill::Blast| - // Skill::BlastPlus | - // Skill::BlastPlusPlus => blast(game, skill), - - // Skill::Chaos| - // Skill::ChaosPlus | - // Skill::ChaosPlusPlus => chaos(game, skill), - - // Skill::Sustain| - // Skill::SustainPlus | - // Skill::SustainPlusPlus => sustain(game, skill), - - // Skill::Electrify| - // Skill::ElectrifyPlus | - // Skill::ElectrifyPlusPlus => electrify(game, skill), - // Skill::ElectrocuteTick| - // Skill::ElectrocuteTickPlus | - // Skill::ElectrocuteTickPlusPlus => electrocute_tick(game, skill), - - // Skill::Curse| - // Skill::CursePlus | - // Skill::CursePlusPlus => curse(game, skill), - - // Skill::Decay| - // Skill::DecayPlus | - // Skill::DecayPlusPlus => decay(game, skill), - // Skill::DecayTick| - // Skill::DecayTickPlus | - // Skill::DecayTickPlusPlus => decay_tick(game, skill), - - // Skill::Haste| - // Skill::HastePlus | - // Skill::HastePlusPlus => haste(game, skill), - - // Skill::Heal| - // Skill::HealPlus | - // Skill::HealPlusPlus => heal(game, skill), - - // Skill::Absorb| - // Skill::AbsorbPlus | - // Skill::AbsorbPlusPlus => absorb(game, skill), - - // Skill::Hybrid| - // Skill::HybridPlus | - // Skill::HybridPlusPlus => hybrid(game, skill), - - // Skill::Invert| - // Skill::InvertPlus | - // Skill::InvertPlusPlus => invert(game, skill), - - // Skill::Counter| - // Skill::CounterPlus | - // Skill::CounterPlusPlus => counter(game, skill), - - // Skill::Purge| - // Skill::PurgePlus | - // Skill::PurgePlusPlus => purge(game, skill), - - // Skill::Purify| - // Skill::PurifyPlus | - // Skill::PurifyPlusPlus => purify(game, skill), - - // Skill::Recharge| - // Skill::RechargePlus | - // Skill::RechargePlusPlus => recharge(game, skill), - - // Skill::Reflect| - // Skill::ReflectPlus | - // Skill::ReflectPlusPlus => reflect(game, skill), - - // Skill::Ruin| - // Skill::RuinPlus | - // Skill::RuinPlusPlus => ruin(game, skill), - - // Skill::Link| - // Skill::LinkPlus | - // Skill::LinkPlusPlus => link(game, skill), - - // Skill::Silence| - // Skill::SilencePlus | - // Skill::SilencePlusPlus => silence(game, skill), - - // Skill::Siphon| - // Skill::SiphonPlus | - // Skill::SiphonPlusPlus => siphon(game, skill), - // Skill::SiphonTick| - // Skill::SiphonTickPlus | - // Skill::SiphonTickPlusPlus => siphon_tick(game, skill), - - // Skill::Slay| - // Skill::SlayPlus | - // Skill::SlayPlusPlus => slay(game, skill), - - // Skill::Sleep| - // Skill::SleepPlus | - // Skill::SleepPlusPlus => sleep(game, skill), - - // Skill::Restrict| - // Skill::RestrictPlus | - // Skill::RestrictPlusPlus => restrict(game, skill), - - // Skill::Strike| - // Skill::StrikePlus | - // Skill::StrikePlusPlus => strike(game, skill), - - // Skill::Intercept| - // Skill::InterceptPlus | - // Skill::InterceptPlusPlus => intercept(game, skill), - - // Skill::Break| - // Skill::BreakPlus | - // Skill::BreakPlusPlus => break_(game, skill), - - // Skill::Triage| - // Skill::TriagePlus | - // Skill::TriagePlusPlus => triage(game, skill), - - // Skill::TriageTick| - // Skill::TriageTickPlus | - // Skill::TriageTickPlusPlus => triage_tick(game, skill), - - // // Base Skills - // Skill::Attack => attack(game, skill), - // Skill::Block => block(game, skill), - // Skill::Buff => buff(game, skill), - // Skill::Debuff => debuff(game, skill), - // Skill::Stun => stun(game, skill), - - // // Triggered - // Skill::Electrocute | - // Skill::ElectrocutePlus | - // Skill::ElectrocutePlusPlus => panic!("should only trigger from electrify hit"), - // Skill::HasteStrike => panic!("should only trigger from haste"), - // Skill::Absorption| - // Skill::AbsorptionPlus | - // Skill::AbsorptionPlusPlus => panic!("should only trigger from absorb"), - // Skill::HybridBlast => panic!("should only trigger from hybrid"), - // Skill::CounterAttack| - // Skill::CounterAttackPlus | - // Skill::CounterAttackPlusPlus => panic!("should only trigger from counter"), - - - // // Not used - // }; - // for Event { source: event_source, target: event_target, event, stages: _ } in resolutions.clone() { // let mut source = game.construct_by_id(event_source.id).unwrap().clone(); // let mut target = game.construct_by_id(event_target.id).unwrap().clone();