hastestrike and hybridblast

This commit is contained in:
ntr
2019-12-11 16:37:58 +10:00
parent 5e8d6a62af
commit bf3c087155
4 changed files with 77 additions and 251 deletions
+5
View File
@@ -378,6 +378,11 @@ impl Construct {
None
}
pub fn additional_skills(&self, skill: Skill) -> Vec<Skill> {
self.effects.iter()
.filter_map(|e| skill.additional_skill(e.effect))
.collect::<Vec<Skill>>()
}
pub fn is_stunned(&self) -> bool {
self.available_skills().len() == 0
+26 -70
View File
@@ -134,7 +134,7 @@ impl Game {
.unwrap()
}
fn all_constructs(&self) -> Vec<Construct> {
fn copy_constructs(&self) -> Vec<Construct> {
self.players.clone()
.into_iter()
.flat_map(
@@ -426,7 +426,7 @@ impl Game {
}
// find their statuses with ticks
let mut ticks = self.all_constructs()
let mut ticks = self.copy_constructs()
.iter()
.flat_map(
|c| c.effects
@@ -477,6 +477,7 @@ impl Game {
self.add_resolution(&cast, &Event::Disable { construct: cast.source, effects });
return self;
}
// for aoe events send the source / target animations before each set of casts
if cast.skill.aoe() {
if cast.skill.cast_animation() {
@@ -492,6 +493,8 @@ impl Game {
self.execute(cast);
}
self.progress_durations();
self
}
@@ -515,8 +518,6 @@ impl Game {
false => vec![cast],
};
// check for reflect
return casts;
}
@@ -531,6 +532,13 @@ impl Game {
return self;
}
// hastestrike / hybridblast
// i think this goes here...
// maybe in modify casts or something
for skill in self.construct(cast.target).additional_skills(cast.skill) {
self.resolve(Cast { skill, ..cast });
}
if let Some(immunity) = self.construct(cast.target).immune(cast.skill) {
self.add_resolution(&cast, &Event::Immune { construct: cast.target, effects: immunity });
return self;
@@ -716,17 +724,25 @@ impl Game {
(x, y)
}
fn progress_durations(&mut self, Resolutions: &Vec<Cast>) -> &mut Game {
for mut construct in self.all_constructs() {
// info!("progressing durations for {:}", construct.name);
fn progress_durations(&mut self) -> &mut Game {
let last = self.resolutions.len() - 1;
let used_cooldown = self.resolutions[last].iter()
.filter_map(|r| match r.event {
Event::Cast { construct, player: _, direction: _ } => match r.skill.base_cd().is_some() {
true => Some(construct),
false => None,
}
_ => None,
})
.collect::<Vec<Uuid>>();
for mut construct in self.copy_constructs() {
if construct.is_ko() {
continue;
}
match Resolutions.iter().find(|s| s.source == construct.id) {
Some(skill) => { construct.skill_set_cd(skill.skill); },
None => { construct.reduce_cooldowns(); },
if !used_cooldown.contains(&construct.id) {
construct.reduce_cooldowns();
};
// always reduce durations
@@ -737,66 +753,6 @@ impl Game {
self
}
// fn log_resolution(&mut self, speed: usize, resolution: &Resolution) -> &mut Game {
// let Resolution { source, target, Resolution, stages: _ } = resolution;
// match Resolution {
// Resolution::Ko { skill: _ }=>
// self.log.push(format!("{:} KO!", target.name)),
// Resolution::Disable { skill, disable } =>
// self.log.push(format!("{:} {:?} {:} disabled {:?}",
// source.name, skill, target.name, disable)),
// Resolution::Immunity { skill, immunity } =>
// self.log.push(format!("[{:}] {:} {:?} {:} immune {:?}",
// speed, source.name, skill, target.name, immunity)),
// Resolution::TargetKo { skill } =>
// self.log.push(format!("[{:}] {:} {:?} {:} - target is KO",
// speed, source.name, skill, target.name)),
// Resolution::Damage { skill, amount, mitigation, colour: _ } =>
// self.log.push(format!("[{:}] {:} {:?} {:} {:} ({:} mitigated)",
// speed, source.name, skill, target.name, amount, mitigation)),
// Resolution::Healing { skill, amount, overhealing } =>
// self.log.push(format!("[{:}] {:} {:?} {:} {:} healing ({:}OH)",
// speed, source.name, skill, target.name, amount, overhealing)),
// Resolution::Inversion { skill } =>
// self.log.push(format!("[{:}] {:} {:?} {:} INVERTED",
// speed, source.name, skill, target.name)),
// Resolution::Reflection { skill } =>
// self.log.push(format!("[{:}] {:} {:?} {:} REFLECTED",
// speed, source.name, skill, target.name)),
// Resolution::Effect { skill, effect, duration, construct_effects: _ } =>
// self.log.push(format!("[{:}] {:} {:?} {:} {:?} {:}T",
// speed, source.name, skill, target.name, effect, duration)),
// Resolution::Skill { skill } =>
// self.log.push(format!("[{:}] {:} {:?} {:}",
// speed, source.name, skill, target.name)),
// Resolution::Removal { effect, construct_effects: _ } =>
// self.log.push(format!("[{:}] {:?} removed {:} {:?}",
// speed, source.name, target.name, effect)),
// Resolution::Recharge { skill, red, blue } =>
// self.log.push(format!("[{:}] {:} {:?} {:} {:}R {:}B",
// speed, source.name, skill, target.name, red, blue)),
// Resolution::Evasion { skill, evasion_rating } =>
// self.log.push(format!("[{:}] {:} {:?} {:} evaded ({:}%)",
// speed, source.name, skill, target.name, evasion_rating)),
// Resolution::Incomplete => panic!("incomplete resolution {:?}", resolution),
// }
// self
// }
pub fn finished(&self) -> bool {
self.phase == Phase::Finished || self.players.iter().any(|t| t.constructs.iter().all(|c| c.is_ko()))
}
+46 -176
View File
@@ -47,10 +47,6 @@ impl Cast {
}
}
pub fn used_cooldown(&self) -> bool {
return self.skill.base_cd().is_some();
}
pub fn actions(&self) -> Vec<Action> {
let mut rng = thread_rng();
@@ -509,6 +505,14 @@ impl Cast {
},
],
Skill::HasteStrike => vec![
Action::Damage {
construct: self.target,
colour: Colour::Red,
values: vec![Value::Stat { construct: self.source, stat: Stat::Speed, mult: self.skill.multiplier() }],
},
],
Skill::Hybrid => vec![
Action::Effect {
construct: self.target,
@@ -528,6 +532,14 @@ impl Cast {
},
],
Skill::HybridBlast => vec![
Action::Damage {
construct: self.target,
colour: Colour::Blue,
values: vec![Value::Stat { construct: self.source, stat: Stat::GreenPower, mult: self.skill.multiplier() }],
},
],
Skill::Intercept |
Skill::InterceptPlus |
Skill::InterceptPlusPlus => vec![
@@ -1773,6 +1785,36 @@ impl Skill {
}
}
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();
@@ -2145,177 +2187,5 @@ mod tests {
// }
}
// Skill::Strike => game.event(
// Event::Damage {
// colour: Colour::Red,
// amount: SkillPower { construct: cast.source, skill: Skill::Strike }
// },
// Event::LifeSteal {
// amount: CastDamage { id: cast.id, colour: Colour::Red, target: cast.source },
// },
// ),
// Skill::Attack => game.event(Event::Damage {
// colour: Colour::Red,
// amount: Stat { construct: cast.source, stat: Stat::RedPower, pct: ATTACK_RED_POWER_PCT }
// }),
// Skill::Bash => game.event(Event::Damage {
// colour: Colour::Red,
// amounts: vec![
// Stat { construct: cast.source, stat: Stat::RedPower, pct: ATTACK_RED_POWER_PCT },
// Cooldowns { construct: cast.source },
// ],
// })
// // we clone the current state of the target and source
// // so we can modify them during the resolution
// // no more than 1 mutable ref allowed on game
// let mut source = game.construct_by_id(cast.source).unwrap().clone();
// let mut target = game.construct_by_id(target_id).unwrap().clone();
// // bail out on ticks that have been removed
// if skill.is_tick() && target.effects.iter().find(|ce| match ce.tick {
// Some(t) => t.id == cast.id,
// None => false,
// }).is_none() {
// return;
// }
// if let Some(_disable) = source.disabled(skill) {
// game.event(Event::new(source, target).event(Event::Disable { disable, skill }).stages(EventStages::PostOnly));
// return;
// }
// if target.is_ko() {
// game.event(Event::new(source, target).event(Event::TargetKo { skill }).stages(EventStages::PostOnly));
// return;
// }
// if target.affected(Effect::Reflect) && skill.colours().contains(&Colour::Blue) && !skill.is_tick() {
// // guard against overflow
// if source.affected(Effect::Reflect) {
// }
// game.event(Event::new(source, target).event(Event::Reflection { skill }));
// return cast_actions(skill, &mut source.clone(), source, resolutions);
// }
// // haste_strike_check(game)
// if source.affected(Effect::Haste) {
// match skill {
// Skill::Slay |
// Skill::SlayPlus |
// Skill::SlayPlusPlus |
// Skill::Chaos |
// Skill::ChaosPlus |
// Skill::ChaosPlusPlus |
// Skill::Strike |
// Skill::StrikePlus |
// Skill::StrikePlusPlus => {
// let amount = source.speed().pct(Skill::HasteStrike.multiplier());
// target.deal_red_damage(Skill::HasteStrike, amount)
// .into_iter()
// .for_each(|e| game.event(Event::new(source, target).event(e)));
// },
// _ => (),
// }
// }
// if source.affected(Effect::Hybrid) {
// match skill {
// Skill::Blast|
// Skill::BlastPlus |
// Skill::BlastPlusPlus |
// Skill::Chaos |
// Skill::ChaosPlus |
// Skill::ChaosPlusPlus |
// Skill::Siphon |
// Skill::SiphonPlus |
// Skill::SiphonPlusPlus => {
// let amount = source.green_power().pct(Skill::HybridBlast.multiplier());
// target.deal_blue_damage(Skill::HybridBlast, amount)
// .into_iter()
// .for_each(|e| game.event(Event::new(source, target).event(e)));
// },
// _ => (),
// }
// }
// match self.category() == EffectCategory::Red {
// true => {
// if let Some(evasion) = target.evade(*self) {
// game.event(evasion);
// return Event;
// }
// },
// false => (),
// }
// for Event { source: event_source, target: event_target, event, stages: _ } in resolutions.clone() {
// let mut source = game.construct_by_id(event_source.id).unwrap().clone();
// let mut target = game.construct_by_id(event_target.id).unwrap().clone();
// match event {
// Event::Damage { amount, skill, mitigation, colour: c } => {
// if target.affected(Effect::Electric) && !skill.is_tick() {
// let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter()
// .find(|e| e.effect == Effect::Electric).unwrap().clone();
// match meta {
// Some(EffectMeta::CastOnHit(s)) => {
// // Gurad against reflect overflow
// if !(source.affected(Effect::Reflect) && target.affected(Effect::Reflect)) {
// // Check reflect don't bother if electrocute is procing on death
// if source.affected(Effect::Reflect) && !target.is_ko() {
// game.event(Event::new(&target, &source)
// .event(Event::Reflection { skill: s }).stages(EventStages::EndPost));
// electrocute(&mut source, &mut target, resolutions, s);
// } else {
// electrocute(&mut target, &mut source, resolutions, s);
// }
// }
// },
// _ => panic!("no electrify skill"),
// };
// }
// if target.affected(Effect::Absorb) && !target.is_ko() {
// let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter()
// .find(|e| e.effect == Effect::Absorb).unwrap().clone();
// match meta {
// Some(EffectMeta::CastOnHit(s)) => {
// absorption(&mut source, &mut target, resolutions, skill, amount + mitigation, s);
// },
// _ => panic!("no absorb skill"),
// };
// }
// if c == Colour::Red {
// if target.affected(Effect::Counter) && !target.is_ko() {
// let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter()
// .find(|e| e.effect == Effect::Counter).unwrap().clone();
// match meta {
// Some(EffectMeta::CastOnHit(s)) => {
// counter_attack(&mut target, &mut source, resolutions, s);
// },
// _ => panic!("no counter skill"),
// };
// }
// }
// if target.is_ko() && event_target.green == 0 {
// // Make sure target ko is from this event
// target.effects.clear();
// game.event(Event::new(&source, &target).event(Event::Ko()).stages(EventStages::PostOnly));
// }
// },
// _ => (),
// };
// game.update_construct(&mut source);
// game.update_construct(&mut target);
// };