use crate::utils::event::{MessageQueue, Event};
use crate::health::disease::{ActiveDisease, ActiveStage, StageLevel};
use crate::utils::{GameTimeC, clamp_bottom};
use crate::error::{ChainInvertErr, ChainInvertBackErr};
use std::time::Duration;
use std::collections::{BTreeMap};
use std::convert::TryFrom;
impl ActiveDisease {
pub fn invert(&self, game_time: &GameTimeC) -> Result<(), ChainInvertErr> {
if self.is_inverted.get() { return Err(ChainInvertErr::AlreadyInverted); }
if !self.is_active(game_time) { return Err(ChainInvertErr::DiseaseNotActiveAtGivenTime); }
let active_stage = match self.get_active_stage(game_time) {
Some(o) => o,
None => return Err(ChainInvertErr::NoActiveStageAtGivenTime)
};
let mut stages = BTreeMap::new();
let gt = game_time.as_secs_f32();
let pt = active_stage.peak_time.as_secs_f32();
let level_int = active_stage.info.level as i32;
let d = if gt > pt { 0. } else { pt - gt }; let new_start_time = clamp_bottom(gt - d, 0.);
let new_peak_time = new_start_time + active_stage.info.reaches_peak_in_hours*60.*60.;
let mut chain_start_time = new_start_time;
stages.insert(active_stage.info.level, ActiveStage {
info: active_stage.info.copy(),
duration: Duration::from_secs_f32(new_peak_time-new_start_time),
start_time: GameTimeC::from_duration(Duration::from_secs_f64(new_start_time as f64)),
peak_time: GameTimeC::from_duration(Duration::from_secs_f64(new_peak_time as f64)),
});
let mut t = new_start_time;
for l in (level_int+1)..(StageLevel::Critical as i32+1) {
let b = self.initial_data.borrow();
let ind = match b.iter().position(|x| (x.level as i32) == l) {
Some(i) => i,
None => continue
};
let mut info = match b.get(ind) {
Some(i) => i.copy(),
None => continue
};
let start_time = clamp_bottom(t - info.reaches_peak_in_hours*60.*60.,0.);
let peak_time = t;
let level = match StageLevel::try_from(l) {
Ok(l) => l,
_ => continue
};
info.is_endless = false;
stages.insert(level, ActiveStage {
info,
duration: Duration::from_secs_f32(clamp_bottom(peak_time-start_time, 0.)),
start_time: GameTimeC::from_duration(Duration::from_secs_f64(start_time as f64)),
peak_time: GameTimeC::from_duration(Duration::from_secs_f64(peak_time as f64)),
});
t = start_time;
if chain_start_time > t { chain_start_time = t; }
}
t = new_peak_time;
let mut l = level_int-1;
while l > 0 {
let b = self.initial_data.borrow();
let ind = match b.iter().position(|x| (x.level as i32) == l) {
Some(o) => o,
None => continue
};
let mut info = match b.get(ind) {
Some(o) => *o,
None => continue
};
let start_time = t;
let peak_time = start_time + info.reaches_peak_in_hours*60.*60.;
let level = match StageLevel::try_from(l) {
Ok(l) => l,
_ => continue
};
info.is_endless = false;
stages.insert(level, ActiveStage {
info,
duration: Duration::from_secs_f32(clamp_bottom(peak_time-start_time, 0.)),
start_time: GameTimeC::from_duration(Duration::from_secs_f64(start_time as f64)),
peak_time: GameTimeC::from_duration(Duration::from_secs_f64(peak_time as f64)),
});
t = peak_time;
l -= 1;
if chain_start_time > t { chain_start_time = t; }
}
self.stages.replace(stages);
self.activation_time.replace(GameTimeC::from_duration(Duration::from_secs_f32(chain_start_time)));
self.end_time.replace(Some(GameTimeC::from_duration(Duration::from_secs_f32(t))));
self.will_end.set(true);
self.is_inverted.set(true);
self.queue_message(Event::DiseaseInverted(self.disease.get_name()));
return Ok(());
}
pub fn invert_back(&self, game_time: &GameTimeC) -> Result<(), ChainInvertBackErr> {
if !self.is_inverted.get() { return Err(ChainInvertBackErr::AlreadyInvertedBack); }
if !self.is_active(game_time) {
return Err(ChainInvertBackErr::DiseaseNotActiveAtGivenTime);
}
let active_stage = match self.get_active_stage(game_time) {
Some(o) => o,
None => return Err(ChainInvertBackErr::NoActiveStageAtGivenTime)
};
let mut stages = BTreeMap::new();
let gt = game_time.as_secs_f32();
let mut will_end = true;
let pt = active_stage.peak_time.as_secs_f32();
let level_int = active_stage.info.level as i32;
let d = if gt > pt { 0. } else { pt - gt }; let new_start_time = clamp_bottom(gt - d, 0.);
let new_peak_time = new_start_time + active_stage.info.reaches_peak_in_hours*60.*60.;
let mut chain_start_time = new_start_time;
stages.insert(active_stage.info.level, ActiveStage {
info: active_stage.info.copy(),
duration: Duration::from_secs_f32(clamp_bottom(new_peak_time-new_start_time, 0.)),
start_time: GameTimeC::from_duration(Duration::from_secs_f64(new_start_time as f64)),
peak_time: GameTimeC::from_duration(Duration::from_secs_f64(new_peak_time as f64)),
});
let mut t = new_start_time;
let mut l = level_int-1;
while l > 0 {
let b = self.initial_data.borrow();
let ind = match b.iter().position(|x| (x.level as i32) == l) {
Some(o) => o,
None => continue
};
let info = match b.get(ind) {
Some(o) => o,
None => continue
};
if info.is_endless { will_end = false; }
let start_time = clamp_bottom(t - info.reaches_peak_in_hours*60.*60., 0.);
let peak_time = t;
let level = match StageLevel::try_from(l) {
Ok(l) => l,
_ => continue
};
stages.insert(level, ActiveStage {
info: info.copy(),
duration: Duration::from_secs_f32(clamp_bottom(peak_time-start_time, 0.)),
start_time: GameTimeC::from_duration(Duration::from_secs_f64(start_time as f64)),
peak_time: GameTimeC::from_duration(Duration::from_secs_f64(peak_time as f64)),
});
t = start_time;
l -= 1;
if chain_start_time > t { chain_start_time = t; }
}
t = new_peak_time;
for l in (level_int+1)..(StageLevel::Critical as i32+1) {
let b = self.initial_data.borrow();
let ind = match b.iter().position(|x| (x.level as i32) == l) {
Some(o) => o,
None => continue
};
let info = match b.get(ind) {
Some(o) => o,
None => continue
};
if info.is_endless { will_end = false; }
let start_time = t;
let peak_time = t + info.reaches_peak_in_hours*60.*60.;
let level = match StageLevel::try_from(l) {
Ok(l) => l,
_ => continue
};
stages.insert(level, ActiveStage {
info: info.copy(),
duration: Duration::from_secs_f32(clamp_bottom(peak_time-start_time, 0.)),
start_time: GameTimeC::from_duration(Duration::from_secs_f64(start_time as f64)),
peak_time: GameTimeC::from_duration(Duration::from_secs_f64(peak_time as f64)),
});
t = peak_time;
if chain_start_time > t { chain_start_time = t; }
}
let new_end_time = if will_end {
Some(GameTimeC::from_duration(Duration::from_secs_f32(t)))
} else {
None
};
self.stages.replace(stages);
self.activation_time.replace(GameTimeC::from_duration(Duration::from_secs_f32(chain_start_time)));
self.end_time.replace(new_end_time);
self.will_end.set(will_end);
self.is_inverted.set(false);
self.queue_message(Event::DiseaseResumed(self.disease.get_name()));
return Ok(());
}
}