use super::{ effects::{ add_effect, EffectType, Targets }, gamelog, Clock, HungerClock, HungerState, TakingTurn, DamageType, }; use bracket_lib::prelude::*; use specs::prelude::*; use crate::config::CONFIG; /// HungerSystem is in charge of ticking down the hunger clock for entities with a hunger clock, /// every time the turn clock ticks. pub struct HungerSystem {} const MAX_SATIATION: i32 = 2000; const HUNGER_BREAKPOINTS: [(i32, HungerState); 5] = [ (1000, HungerState::Satiated), (600, HungerState::Normal), (400, HungerState::Hungry), (200, HungerState::Weak), (0, HungerState::Fainting), ]; const BASE_CLOCK_DECREMENT_PER_TURN: i32 = 1; pub fn get_hunger_state(duration: i32) -> HungerState { for (threshold, state) in HUNGER_BREAKPOINTS.iter() { if duration > *threshold { return *state; } } return HungerState::Starving; } pub fn get_hunger_colour(state: HungerState) -> (u8, u8, u8) { match state { HungerState::Satiated => GREEN, HungerState::Normal => WHITE, HungerState::Hungry => BROWN1, HungerState::Weak => ORANGE, HungerState::Fainting => RED3, HungerState::Starving => RED, } } impl<'a> System<'a> for HungerSystem { #[allow(clippy::type_complexity)] type SystemData = ( Entities<'a>, WriteStorage<'a, HungerClock>, ReadExpect<'a, Entity>, ReadStorage<'a, Clock>, ReadStorage<'a, TakingTurn>, ); fn run(&mut self, data: Self::SystemData) { let (entities, mut hunger_clock, player_entity, turn_clock, turns) = data; // If the turn clock isn't taking a turn this tick, don't bother ticking hunger. let mut ticked = false; for (_e, _c, _t) in (&entities, &turn_clock, &turns).join() { ticked = true; break; } if !ticked { return; } // Otherwise, tick down the hunger clock for all entities with one. for (entity, mut hunger_clock) in (&entities, &mut hunger_clock).join() { if hunger_clock.duration >= MAX_SATIATION { hunger_clock.duration = MAX_SATIATION; } else { hunger_clock.duration -= BASE_CLOCK_DECREMENT_PER_TURN; } let initial_state = hunger_clock.state; hunger_clock.state = get_hunger_state(hunger_clock.duration); if hunger_clock.state == HungerState::Starving { add_effect( None, EffectType::Damage { amount: 1, damage_type: DamageType::Forced }, Targets::Entity { target: entity } ); } if CONFIG.logging.log_ticks && entity == *player_entity { console::log( format!( "HUNGER SYSTEM: Ticked for player entity. [clock: {}]", hunger_clock.duration ) ); } if hunger_clock.state == initial_state { continue; } if entity != *player_entity { continue; } // Things which only happen to the player. match hunger_clock.state { HungerState::Satiated => gamelog::Logger ::new() .append("You feel") .colour(get_hunger_colour(hunger_clock.state)) .append_n("satiated") .colour(WHITE) .period() .log(), HungerState::Normal => {} HungerState::Hungry => gamelog::Logger ::new() .append("You feel") .colour(get_hunger_colour(hunger_clock.state)) .append_n("hungry") .colour(WHITE) .period() .log(), HungerState::Weak => gamelog::Logger ::new() .append("You feel") .colour(get_hunger_colour(hunger_clock.state)) .append_n("weak with hunger") .colour(WHITE) .period() .log(), HungerState::Fainting => gamelog::Logger ::new() .append("You feel") .colour(get_hunger_colour(hunger_clock.state)) .append_n("hungry enough to faint") .colour(WHITE) .period() .log(), _ => gamelog::Logger ::new() .colour(get_hunger_colour(hunger_clock.state)) .append_n("You can't go on without food!") .log(), } } } }