sort stack speed as resolving

This commit is contained in:
ntr 2019-03-24 18:37:58 +11:00
parent 467db4838f
commit 0143849ec2
4 changed files with 53 additions and 61 deletions

View File

@ -28,8 +28,6 @@ ensure all skills impl
Skill::Taunt -> redirect incomnig attacks to self Skill::Taunt -> redirect incomnig attacks to self
Skill::Toxic -> apply debuff to attackers Skill::Toxic -> apply debuff to attackers
colour speeds
update speed of rest of stack on cryp speed change update speed of rest of stack on cryp speed change
include target name in effect resolution include target name in effect resolution
eg strangle applies buff to self eg strangle applies buff to self

View File

@ -196,14 +196,12 @@ impl Game {
&& self.teams.iter().all(|t| t.cryps.len() == self.team_size) && self.teams.iter().all(|t| t.cryps.len() == self.team_size)
} }
pub fn start(&mut self) -> &mut Game { pub fn start(mut self) -> Game {
self.log.push("Game starting...".to_string()); self.log.push("Game starting...".to_string());
self.skill_phase_start()
self.skill_phase_start();
self
} }
fn skill_phase_start(&mut self) -> &mut Game { fn skill_phase_start(mut self) -> Game {
self.log.push("<Skill Phase>".to_string()); self.log.push("<Skill Phase>".to_string());
if ![Phase::Start, Phase::Resolve].contains(&self.phase) { if ![Phase::Start, Phase::Resolve].contains(&self.phase) {
@ -212,11 +210,9 @@ impl Game {
self.phase = Phase::Skill; self.phase = Phase::Skill;
self.stack.clear();
self.pve_add_skills(); self.pve_add_skills();
if self.skill_phase_finished() { if self.skill_phase_finished() {
self.resolve_phase_start(); return self.resolve_phase_start()
} }
self self
@ -343,7 +339,7 @@ impl Game {
// requires no input // requires no input
// just do it // just do it
fn resolve_phase_start(&mut self) -> &mut Game { fn resolve_phase_start(mut self) -> Game {
if self.phase != Phase::Skill { if self.phase != Phase::Skill {
panic!("game not in skill phase"); panic!("game not in skill phase");
} }
@ -355,7 +351,10 @@ impl Game {
self.resolve_skills() self.resolve_skills()
} }
fn log_resolution(&mut self, source: &mut Cryp, target: &mut Cryp, cast: &Cast) -> &mut Game { fn log_resolution(&mut self, cast: &Cast) -> &mut Game {
let source = self.cryp_by_id(cast.source_cryp_id).unwrap().clone();
let target = self.cryp_by_id(cast.target_cryp_id).unwrap().clone();
match cast.resolution.disable.disabled { match cast.resolution.disable.disabled {
true => { true => {
self.log.push(format!("{:} {:?} {:} disabled {:?}", source.name, cast.skill, target.name, cast.resolution.disable.effects)); self.log.push(format!("{:} {:?} {:} disabled {:?}", source.name, cast.skill, target.name, cast.resolution.disable.effects));
@ -415,12 +414,11 @@ impl Game {
}); });
self.stack = sorted; self.stack = sorted;
self.stack.reverse();
self self
} }
fn resolve_skills(&mut self) -> &mut Game { fn resolve_skills(mut self) -> Game {
if self.phase != Phase::Resolve { if self.phase != Phase::Resolve {
panic!("game not in Resolve phase"); panic!("game not in Resolve phase");
} }
@ -440,17 +438,20 @@ impl Game {
self.stack_sort_speed(); self.stack_sort_speed();
// update the stack with the resolved skills // temp vec of this round's resolving skills
for mut skill in self.stack.clone() { // because need to check cooldown use before pushing them into the complete list
let mut resolving = vec![];
while let Some(mut skill) = self.stack.pop() {
// println!("{:} resolving ", skill); // println!("{:} resolving ", skill);
let mut source = self.cryp_by_id(skill.source_cryp_id).unwrap().clone(); let mut source = self.cryp_by_id(skill.source_cryp_id).unwrap().clone();
let mut target = self.cryp_by_id(skill.target_cryp_id).unwrap().clone(); let mut target = self.cryp_by_id(skill.target_cryp_id).unwrap().clone();
skill.set_resolution(&mut source, &mut target); skill.set_resolution(&mut source, &mut target);
self.log_resolution(&mut source, &mut target, &skill); self.log_resolution(&skill);
self.resolved.push(skill); resolving.push(skill);
if target.is_ko() && !target.ko_logged { if target.is_ko() && !target.ko_logged {
self.log.push(format!("{:} KO", target.name)); self.log.push(format!("{:} KO", target.name));
@ -467,17 +468,15 @@ impl Game {
self.update_cryp(&mut source); self.update_cryp(&mut source);
self.update_cryp(&mut target); self.update_cryp(&mut target);
// find a way to self.stack_sort_speed();
// resort the stack after each cast because
// the cryp speed may have changed
// self.stack_sort_speed();
}; };
// println!("{:#?}", self.resolved); // println!("{:#?}", self.resolving);
// now Resolve has all been assigned // now Resolve has all been assigned
// handle cooldowns and statuses // handle cooldowns and statuses
self.progress_durations(); self.progress_durations(&resolving);
self.resolved.append(&mut resolving);
if self.finished() { if self.finished() {
return self.finish() return self.finish()
@ -486,7 +485,7 @@ impl Game {
self.skill_phase_start() self.skill_phase_start()
} }
fn progress_durations(&mut self) -> &mut Game { fn progress_durations(&mut self, resolved: &Vec<Cast>) -> &mut Game {
for mut cryp in self.all_cryps() { for mut cryp in self.all_cryps() {
// println!("progressing durations for {:}", cryp.name); // println!("progressing durations for {:}", cryp.name);
@ -497,7 +496,7 @@ impl Game {
// only reduce cooldowns if no cd was used // only reduce cooldowns if no cd was used
// have to borrow self for the skill check // have to borrow self for the skill check
{ {
if let Some(skill) = self.stack.iter_mut().find(|s| s.source_cryp_id == cryp.id) { if let Some(skill) = resolved.iter().find(|s| s.source_cryp_id == cryp.id) {
if skill.used_cooldown() { if skill.used_cooldown() {
cryp.skill_set_cd(skill.skill); cryp.skill_set_cd(skill.skill);
} else { } else {
@ -524,10 +523,9 @@ impl Game {
self.teams.iter().find(|t| t.cryps.iter().any(|c| !c.is_ko())) self.teams.iter().find(|t| t.cryps.iter().any(|c| !c.is_ko()))
} }
fn finish(&mut self) -> &mut Game { fn finish(mut self) -> Game {
self.phase = Phase::Finish; self.phase = Phase::Finish;
self.log.push(format!("Game finished.")); self.log.push(format!("Game finished."));
self.stack.clear();
{ {
let winner = self.teams.iter().find(|t| t.cryps.iter().any(|c| !c.is_ko())); let winner = self.teams.iter().find(|t| t.cryps.iter().any(|c| !c.is_ko()));
@ -567,7 +565,7 @@ pub fn game_skill(params: GameSkillParams, tx: &mut Transaction, account: &Accou
game.add_skill(account.id, params.cryp_id, params.target_cryp_id, params.skill)?; game.add_skill(account.id, params.cryp_id, params.target_cryp_id, params.skill)?;
if game.skill_phase_finished() { if game.skill_phase_finished() {
game.resolve_phase_start(); game = game.resolve_phase_start();
} }
game_update(&game, tx)?; game_update(&game, tx)?;
@ -843,7 +841,7 @@ pub fn game_instance_join(tx: &mut Transaction, player: Player, game_id: Uuid) -
game.team_add(team)?; game.team_add(team)?;
if game.can_start() { if game.can_start() {
game.start(); game = game.start();
} }
println!("{:?} game joined", game.id); println!("{:?} game joined", game.id);
@ -905,9 +903,7 @@ mod tests {
assert!(game.can_start()); assert!(game.can_start());
game.start(); return game.start();
return game;
} }
fn create_2v2_test_game() -> Game { fn create_2v2_test_game() -> Game {
@ -953,9 +949,7 @@ mod tests {
assert!(game.can_start()); assert!(game.can_start());
game.start(); return game.start();
return game;
} }
#[test] #[test]
@ -973,7 +967,7 @@ mod tests {
assert!(game.skill_phase_finished()); assert!(game.skill_phase_finished());
game.resolve_phase_start(); game = game.resolve_phase_start();
assert!([Phase::Skill, Phase::Finish].contains(&game.phase)); assert!([Phase::Skill, Phase::Finish].contains(&game.phase));
@ -994,7 +988,7 @@ mod tests {
game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
assert!(game.skill_phase_finished()); assert!(game.skill_phase_finished());
game.resolve_phase_start(); game = game.resolve_phase_start();
// should auto progress back to skill phase // should auto progress back to skill phase
assert!(game.phase == Phase::Skill); assert!(game.phase == Phase::Skill);
@ -1024,7 +1018,7 @@ mod tests {
game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap(); game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap();
assert!(game.skill_phase_finished()); assert!(game.skill_phase_finished());
game.resolve_phase_start(); game = game.resolve_phase_start();
assert!(!game.team_by_id(y_team.id).cryps[0].is_stunned()); assert!(!game.team_by_id(y_team.id).cryps[0].is_stunned());
assert!(game.phase == Phase::Finish); assert!(game.phase == Phase::Finish);
@ -1050,7 +1044,7 @@ mod tests {
let _x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestTouch).unwrap(); let _x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestTouch).unwrap();
game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
game.resolve_phase_start(); game = game.resolve_phase_start();
// should auto progress back to skill phase // should auto progress back to skill phase
assert!(game.phase == Phase::Skill); assert!(game.phase == Phase::Skill);
@ -1061,7 +1055,7 @@ mod tests {
let _x_block_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::Stun).unwrap(); let _x_block_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::Stun).unwrap();
let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
game.resolve_phase_start(); game = game.resolve_phase_start();
assert!(game.team_by_id(x_team.id).cryps[0].skill_on_cd(Skill::Stun).is_some()); assert!(game.team_by_id(x_team.id).cryps[0].skill_on_cd(Skill::Stun).is_some());
assert!(game.team_by_id(y_team.id).cryps[0].skill_on_cd(Skill::Block).is_none()); assert!(game.team_by_id(y_team.id).cryps[0].skill_on_cd(Skill::Block).is_none());
@ -1080,7 +1074,7 @@ mod tests {
let _x_block_id = game.add_skill(x_team.id, x_cryp.id, None, Skill::TestParry).unwrap(); let _x_block_id = game.add_skill(x_team.id, x_cryp.id, None, Skill::TestParry).unwrap();
game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestStun).unwrap(); game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestStun).unwrap();
game.resolve_phase_start(); game = game.resolve_phase_start();
// should not be stunned because of parry // should not be stunned because of parry
assert!(game.team_by_id(x_team.id).cryps[0].is_stunned() == false); assert!(game.team_by_id(x_team.id).cryps[0].is_stunned() == false);
@ -1099,12 +1093,12 @@ mod tests {
let _x_siphon_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestSiphon).unwrap(); let _x_siphon_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestSiphon).unwrap();
let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
game.resolve_phase_start(); game = game.resolve_phase_start();
game.add_skill(x_team.id, x_cryp.id, None, Skill::TestBlock).unwrap(); game.add_skill(x_team.id, x_cryp.id, None, Skill::TestBlock).unwrap();
game.add_skill(y_team.id, y_cryp.id, None, Skill::TestBlock).unwrap(); game.add_skill(y_team.id, y_cryp.id, None, Skill::TestBlock).unwrap();
game.resolve_phase_start(); game = game.resolve_phase_start();
assert!(game.resolved.iter().any(|r| r.skill == Skill::SiphonTick)); assert!(game.resolved.iter().any(|r| r.skill == Skill::SiphonTick));
} }
@ -1127,7 +1121,7 @@ mod tests {
game.add_skill(x_team.id, y_cryp.id, Some(i_cryp.id), Skill::TestTouch).unwrap(); game.add_skill(x_team.id, y_cryp.id, Some(i_cryp.id), Skill::TestTouch).unwrap();
assert!(game.skill_phase_finished()); assert!(game.skill_phase_finished());
game.resolve_phase_start(); game = game.resolve_phase_start();
assert!([Phase::Skill, Phase::Finish].contains(&game.phase)); assert!([Phase::Skill, Phase::Finish].contains(&game.phase));
@ -1144,7 +1138,7 @@ mod tests {
assert!(game.add_skill(x_team.id, x_cryp.id, Some(i_cryp.id), Skill::TestTouch).is_err()); assert!(game.add_skill(x_team.id, x_cryp.id, Some(i_cryp.id), Skill::TestTouch).is_err());
assert!(game.skill_phase_finished()); assert!(game.skill_phase_finished());
game.resolve_phase_start(); game = game.resolve_phase_start();
assert!(game.team_by_id(i_team.id).skills_required() == 1); assert!(game.team_by_id(i_team.id).skills_required() == 1);
assert!(game.team_by_id(x_team.id).skills_required() == 2); assert!(game.team_by_id(x_team.id).skills_required() == 2);

View File

@ -133,7 +133,7 @@ impl Instance {
.team_add(plr_team)? .team_add(plr_team)?
.team_add(bot_team)?; .team_add(bot_team)?;
game.start(); game = game.start();
Ok(game) Ok(game)
} }
@ -253,7 +253,7 @@ impl Instance {
.team_add(a_team).unwrap() .team_add(a_team).unwrap()
.team_add(b_team).unwrap(); .team_add(b_team).unwrap();
game.start(); game = game.start();
assert!(game.finished()); assert!(game.finished());
let winner = game.winner().unwrap(); let winner = game.winner().unwrap();

View File

@ -577,24 +577,24 @@ impl Skill {
let speed = source.skill_speed(*self); let speed = source.skill_speed(*self);
let mut resolution = Resolution { skill: *self, results: vec![], disable: source.disabled(*self), speed }; let resolution = Resolution { skill: *self, results: vec![], disable: source.disabled(*self), speed };
if target.is_ko() {
return resolution;
}
if resolution.disable.disabled { if resolution.disable.disabled {
return resolution; return resolution;
} }
match self.category() == Category::Red { // match self.category() == Category::Red {
true => { // true => {
if let Some(evasion) = target.evade(*self) { // if let Some(evasion) = target.evade(*self) {
resolution.results.push(evasion); // resolution.results.push(evasion);
return resolution; // return resolution;
} // }
}, // },
false => (), // false => (),
// }
if target.is_ko() {
return resolution;
} }
if target.is_reflecting() { if target.is_reflecting() {