From 454a8c7028ea8225a85ddbc884075adcb625faac Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Sun, 20 Aug 2023 17:27:11 +0100 Subject: [PATCH] refactors hunger system still works the same way, just cleaner --- src/components.rs | 1 + src/gui/mod.rs | 19 +++--- src/hunger_system.rs | 151 ++++++++++++++++++++++++++++++------------- src/spawner.rs | 2 +- 4 files changed, 120 insertions(+), 53 deletions(-) diff --git a/src/components.rs b/src/components.rs index 7dfa8d9..19a5ca6 100644 --- a/src/components.rs +++ b/src/components.rs @@ -130,6 +130,7 @@ pub enum HungerState { Hungry, Weak, Fainting, + Starving, } #[derive(Component, Serialize, Deserialize, Clone)] diff --git a/src/gui/mod.rs b/src/gui/mod.rs index fe79585..9c7ce7b 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -1,8 +1,8 @@ use super::{ - ai::CARRY_CAPACITY_PER_STRENGTH, camera, gamelog, gamesystem, rex_assets::RexAssets, ArmourClassBonus, Attributes, - Burden, Charges, Equipped, Hidden, HungerClock, HungerState, InBackpack, MagicItem, MagicItemClass, Map, - MasterDungeonMap, Name, ObfuscatedName, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill, Skills, - State, Viewshed, + ai::CARRY_CAPACITY_PER_STRENGTH, camera, gamelog, gamesystem, hunger_system::get_hunger_colour, + hunger_system::get_hunger_state, rex_assets::RexAssets, ArmourClassBonus, Attributes, Burden, Charges, Equipped, + Hidden, HungerClock, HungerState, InBackpack, MagicItem, MagicItemClass, Map, MasterDungeonMap, Name, + ObfuscatedName, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill, Skills, State, Viewshed, }; use rltk::prelude::*; use specs::prelude::*; @@ -113,17 +113,20 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { // Draw hunger match hunger.state { HungerState::Satiated => { - ctx.print_color_right(70, 53, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "Satiated") + ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Satiated") } HungerState::Normal => {} HungerState::Hungry => { - ctx.print_color_right(70, 53, RGB::named(rltk::BROWN1), RGB::named(rltk::BLACK), "Hungry") + ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Hungry") } HungerState::Weak => { - ctx.print_color_right(70, 53, RGB::named(rltk::ORANGE), RGB::named(rltk::BLACK), "Weak") + ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Weak") } HungerState::Fainting => { - ctx.print_color_right(70, 53, RGB::named(rltk::RED), RGB::named(rltk::BLACK), "Fainting") + ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Fainting") + } + HungerState::Starving => { + ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Starving") } } // Burden diff --git a/src/hunger_system.rs b/src/hunger_system.rs index bc9df0f..00d5b53 100644 --- a/src/hunger_system.rs +++ b/src/hunger_system.rs @@ -1,62 +1,125 @@ use super::{ effects::{add_effect, EffectType, Targets}, - gamelog, HungerClock, HungerState, LOG_TICKS, + gamelog, Clock, HungerClock, HungerState, TakingTurn, LOG_TICKS, }; +use rltk::prelude::*; use specs::prelude::*; +/// 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 = 4; + +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>); + 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) = data; + let (entities, mut hunger_clock, player_entity, turn_clock, turns) = data; - for (entity, mut clock) in (&entities, &mut hunger_clock).join() { + // 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 }, Targets::Entity { target: entity }); + } if LOG_TICKS && entity == *player_entity { - rltk::console::log(format!("HUNGER SYSTEM: Ticked for player entity. [clock: {}]", clock.duration)); + rltk::console::log(format!( + "HUNGER SYSTEM: Ticked for player entity. [clock: {}]", + hunger_clock.duration + )); } - clock.duration -= 1; - if clock.duration > 0 { - return; + if hunger_clock.state == initial_state { + continue; } - - match clock.state { - HungerState::Satiated => { - clock.state = HungerState::Normal; - clock.duration = 1200; - if entity == *player_entity { - gamelog::Logger::new().append("You are no longer satiated.").log(); - } - } - HungerState::Normal => { - clock.state = HungerState::Hungry; - clock.duration = 400; - if entity == *player_entity { - gamelog::Logger::new().colour(rltk::BROWN1).append("You feel hungry.").log(); - } - } - HungerState::Hungry => { - clock.state = HungerState::Weak; - clock.duration = 200; - if entity == *player_entity { - gamelog::Logger::new().colour(rltk::ORANGE).append("You feel weak with hunger.").log(); - } - } - HungerState::Weak => { - clock.state = HungerState::Fainting; - clock.duration = 200; - if entity == *player_entity { - gamelog::Logger::new().colour(rltk::RED).append("You feel hungry enough to faint.").log(); - } - } - HungerState::Fainting => { - add_effect(None, EffectType::Damage { amount: 1 }, Targets::Entity { target: entity }); - if entity == *player_entity { - gamelog::Logger::new().colour(rltk::RED).append("You can't go on without food...").log(); - } - } + 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("satiated") + .colour(WHITE) + .period() + .log(), + HungerState::Normal => {} + HungerState::Hungry => gamelog::Logger::new() + .append("You feel") + .colour(get_hunger_colour(hunger_clock.state)) + .append("hungry") + .colour(WHITE) + .period() + .log(), + HungerState::Weak => gamelog::Logger::new() + .append("You feel") + .colour(get_hunger_colour(hunger_clock.state)) + .append("weak with hunger") + .colour(WHITE) + .period() + .log(), + HungerState::Fainting => gamelog::Logger::new() + .append("You feel") + .colour(get_hunger_colour(hunger_clock.state)) + .append("hungry enough to faint") + .colour(WHITE) + .period() + .log(), + _ => gamelog::Logger::new() + .colour(get_hunger_colour(hunger_clock.state)) + .append("You can't go on without food!") + .log(), } } } diff --git a/src/spawner.rs b/src/spawner.rs index 8826b1c..fcbd662 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -39,7 +39,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { .with(Faction { name: "player".to_string() }) .with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true }) .with(Name { name: "you".to_string(), plural: "you".to_string() }) - .with(HungerClock { state: HungerState::Satiated, duration: 200 }) + .with(HungerClock { state: HungerState::Satiated, duration: 1200 }) .with(Attributes { strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) }, dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) },