use crate::utils::event::{Event, MessageQueue};
use crate::utils::{GameTimeC, HealthC};
use crate::health::disease::{DiseaseMonitor, ActiveDisease};
use crate::health::injury::{ActiveInjury};
use crate::health::side::{SideEffectsMonitor};
use crate::health::medagent::{MedicalAgentsMonitor, CurveType};
use crate::health::medagent::fluent::{AgentStart};
use crate::inventory::items::{InventoryItem, ConsumableC, ApplianceC};
use crate::body::BodyPart;
use std::collections::{HashMap, BTreeMap};
use std::cell::{RefCell, Cell, RefMut};
use std::rc::Rc;
use std::sync::Arc;
use std::convert::TryFrom;
use std::fmt;
use std::hash::{Hash, Hasher};
mod update;
mod status_methods;
mod monitors;
pub(crate) mod state;
pub mod disease;
pub mod injury;
pub mod side;
pub mod medagent;
pub struct Health {
pub stamina_regain_rate: Cell<f32>,
pub blood_regain_rate: Cell<f32>,
pub oxygen_regain_rate: Cell<f32>,
pub diseases: Arc<RefCell<HashMap<String, Rc<ActiveDisease>>>>,
pub injuries: Arc<RefCell<HashMap<InjuryKey, Rc<ActiveInjury>>>>,
pub medical_agents: Arc<MedicalAgentsMonitor>,
pub disease_monitors: Rc<RefCell<HashMap<usize, Box<dyn DiseaseMonitor>>>>,
pub side_effects: Rc<RefCell<HashMap<usize, Box<dyn SideEffectsMonitor>>>>,
body_temperature: Cell<f32>,
heart_rate: Cell<f32>,
top_pressure: Cell<f32>,
bottom_pressure: Cell<f32>,
blood_level: Cell<f32>,
food_level: Cell<f32>,
water_level: Cell<f32>,
stamina_level: Cell<f32>,
fatigue_level: Cell<f32>,
oxygen_level: Cell<f32>,
is_alive: Cell<bool>,
has_blood_loss: Cell<bool>,
message_queue: RefCell<BTreeMap<usize, Event>>
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InjuryKey {
pub injury: String,
pub body_part: BodyPart
}
impl fmt::Display for InjuryKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} on {}", self.injury, self.body_part)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum StageLevel {
Undefined = -1,
InitialStage = 1,
Progressing = 2,
Worrying = 3,
Critical = 4
}
impl Default for StageLevel {
fn default() -> Self { StageLevel::Undefined }
}
impl Hash for StageLevel {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_usize(*self as usize);
}
}
impl fmt::Display for StageLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl TryFrom<i32> for StageLevel {
type Error = ();
fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
x if x == StageLevel::InitialStage as i32 => Ok(StageLevel::InitialStage),
x if x == StageLevel::Progressing as i32 => Ok(StageLevel::Progressing),
x if x == StageLevel::Worrying as i32 => Ok(StageLevel::Worrying),
x if x == StageLevel::Critical as i32 => Ok(StageLevel::Critical),
_ => Err(()),
}
}
}
pub struct MedicalAgentBuilder {
pub name: RefCell<String>,
pub duration_minutes: Cell<f32>,
pub curve_type: RefCell<CurveType>,
pub items: RefCell<Vec<String>>
}
impl MedicalAgentBuilder {
pub fn start() -> Box<dyn AgentStart> {
Box::new(MedicalAgentBuilder {
name: RefCell::new(String::new()),
curve_type: RefCell::new(CurveType::Linearly),
duration_minutes: Cell::new(0.),
items: RefCell::new(Vec::new())
})
}
}
impl Health {
pub(crate) fn new() -> Self {
let healthy = HealthC::healthy();
Health {
disease_monitors: Rc::new(RefCell::new(HashMap::new())),
side_effects: Rc::new(RefCell::new(HashMap::new())),
diseases: Arc::new(RefCell::new(HashMap::new())),
injuries: Arc::new(RefCell::new(HashMap::new())),
stamina_regain_rate: Cell::new(0.1),
blood_regain_rate: Cell::new(0.006),
oxygen_regain_rate: Cell::new(0.05),
message_queue: RefCell::new(BTreeMap::new()),
medical_agents: Arc::new(MedicalAgentsMonitor::new()),
has_blood_loss: Cell::new(false),
is_alive: Cell::new(true),
blood_level: Cell::new(healthy.blood_level),
body_temperature: Cell::new(healthy.body_temperature),
top_pressure: Cell::new(healthy.top_pressure),
bottom_pressure: Cell::new(healthy.bottom_pressure),
food_level: Cell::new(healthy.food_level),
oxygen_level: Cell::new(healthy.oxygen_level),
water_level: Cell::new(healthy.water_level),
heart_rate: Cell::new(healthy.heart_rate),
stamina_level: Cell::new(healthy.stamina_level),
fatigue_level: Cell::new(healthy.fatigue_level)
}
}
pub(crate) fn on_consumed(&self, game_time: &GameTimeC, item: &ConsumableC,
inventory_items: &HashMap<String, Box<dyn InventoryItem>>){
self.food_level.set(crate::utils::clamp(self.food_level.get() + item.food_gain, 0., 100.));
self.water_level.set(crate::utils::clamp(self.water_level.get() + item.water_gain, 0., 100.));
for (_, monitor) in self.disease_monitors.borrow().iter() {
monitor.on_consumed(self, game_time, item, inventory_items);
}
for (_, disease) in self.diseases.borrow().iter() {
if disease.is_active(game_time) {
disease.on_consumed(game_time, item, inventory_items);
}
}
for (_, agent) in self.medical_agents.agents.borrow().iter() {
agent.on_consumed(game_time, item.name.to_string())
}
}
pub(crate) fn on_appliance_taken(&self, game_time: &GameTimeC, item: &ApplianceC,
body_part: BodyPart, inventory_items: &HashMap<String, Box<dyn InventoryItem>>){
for (_, monitor) in self.disease_monitors.borrow().iter() {
monitor.on_appliance_taken(self, game_time, item, body_part, inventory_items);
}
for (_, disease) in self.diseases.borrow().iter() {
if disease.is_active(game_time) {
disease.on_appliance_taken(game_time, item, body_part, inventory_items);
}
}
for (_, injury) in self.injuries.borrow().iter() {
if injury.is_active(game_time) {
injury.on_appliance_taken(game_time, item, body_part, inventory_items);
}
}
for (_, agent) in self.medical_agents.agents.borrow().iter() {
agent.on_appliance_taken(game_time, item.name.to_string())
}
}
pub(crate) fn declare_dead(&self) { self.is_alive.set(false); }
pub fn clear_diseases(&self) {
self.diseases.borrow_mut().clear();
}
pub fn clear_injuries(&self) {
self.injuries.borrow_mut().clear();
}
}
impl MessageQueue for Health {
fn has_messages(&self) -> bool { self.message_queue.borrow().len() > 0 }
fn queue_message(&self, message: Event) {
let mut q = self.message_queue.borrow_mut();
let id = q.len();
q.insert(id, message);
}
fn get_message_queue(&self) -> RefMut<'_, BTreeMap<usize, Event>> {
self.message_queue.borrow_mut()
}
}