refactors hunger system

still works the same way, just cleaner
This commit is contained in:
Llywelwyn 2023-08-20 17:27:11 +01:00
parent 23a6d5e025
commit 454a8c7028
4 changed files with 120 additions and 53 deletions

View file

@ -130,6 +130,7 @@ pub enum HungerState {
Hungry, Hungry,
Weak, Weak,
Fainting, Fainting,
Starving,
} }
#[derive(Component, Serialize, Deserialize, Clone)] #[derive(Component, Serialize, Deserialize, Clone)]

View file

@ -1,8 +1,8 @@
use super::{ use super::{
ai::CARRY_CAPACITY_PER_STRENGTH, camera, gamelog, gamesystem, rex_assets::RexAssets, ArmourClassBonus, Attributes, ai::CARRY_CAPACITY_PER_STRENGTH, camera, gamelog, gamesystem, hunger_system::get_hunger_colour,
Burden, Charges, Equipped, Hidden, HungerClock, HungerState, InBackpack, MagicItem, MagicItemClass, Map, hunger_system::get_hunger_state, rex_assets::RexAssets, ArmourClassBonus, Attributes, Burden, Charges, Equipped,
MasterDungeonMap, Name, ObfuscatedName, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill, Skills, Hidden, HungerClock, HungerState, InBackpack, MagicItem, MagicItemClass, Map, MasterDungeonMap, Name,
State, Viewshed, ObfuscatedName, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill, Skills, State, Viewshed,
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -113,17 +113,20 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
// Draw hunger // Draw hunger
match hunger.state { match hunger.state {
HungerState::Satiated => { 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::Normal => {}
HungerState::Hungry => { 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 => { 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 => { 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 // Burden

View file

@ -1,62 +1,125 @@
use super::{ use super::{
effects::{add_effect, EffectType, Targets}, effects::{add_effect, EffectType, Targets},
gamelog, HungerClock, HungerState, LOG_TICKS, gamelog, Clock, HungerClock, HungerState, TakingTurn, LOG_TICKS,
}; };
use rltk::prelude::*;
use specs::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 {} 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 { impl<'a> System<'a> for HungerSystem {
#[allow(clippy::type_complexity)] #[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) { 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 { 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 hunger_clock.state == initial_state {
if clock.duration > 0 { continue;
return;
} }
if entity != *player_entity {
match clock.state { continue;
HungerState::Satiated => { }
clock.state = HungerState::Normal; // Things which only happen to the player.
clock.duration = 1200; match hunger_clock.state {
if entity == *player_entity { HungerState::Satiated => gamelog::Logger::new()
gamelog::Logger::new().append("You are no longer satiated.").log(); .append("You feel")
} .colour(get_hunger_colour(hunger_clock.state))
} .append("satiated")
HungerState::Normal => { .colour(WHITE)
clock.state = HungerState::Hungry; .period()
clock.duration = 400; .log(),
if entity == *player_entity { HungerState::Normal => {}
gamelog::Logger::new().colour(rltk::BROWN1).append("You feel hungry.").log(); HungerState::Hungry => gamelog::Logger::new()
} .append("You feel")
} .colour(get_hunger_colour(hunger_clock.state))
HungerState::Hungry => { .append("hungry")
clock.state = HungerState::Weak; .colour(WHITE)
clock.duration = 200; .period()
if entity == *player_entity { .log(),
gamelog::Logger::new().colour(rltk::ORANGE).append("You feel weak with hunger.").log(); HungerState::Weak => gamelog::Logger::new()
} .append("You feel")
} .colour(get_hunger_colour(hunger_clock.state))
HungerState::Weak => { .append("weak with hunger")
clock.state = HungerState::Fainting; .colour(WHITE)
clock.duration = 200; .period()
if entity == *player_entity { .log(),
gamelog::Logger::new().colour(rltk::RED).append("You feel hungry enough to faint.").log(); HungerState::Fainting => gamelog::Logger::new()
} .append("You feel")
} .colour(get_hunger_colour(hunger_clock.state))
HungerState::Fainting => { .append("hungry enough to faint")
add_effect(None, EffectType::Damage { amount: 1 }, Targets::Entity { target: entity }); .colour(WHITE)
if entity == *player_entity { .period()
gamelog::Logger::new().colour(rltk::RED).append("You can't go on without food...").log(); .log(),
} _ => gamelog::Logger::new()
} .colour(get_hunger_colour(hunger_clock.state))
.append("You can't go on without food!")
.log(),
} }
} }
} }

View file

@ -39,7 +39,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
.with(Faction { name: "player".to_string() }) .with(Faction { name: "player".to_string() })
.with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true }) .with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true })
.with(Name { name: "you".to_string(), plural: "you".to_string() }) .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 { .with(Attributes {
strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) }, strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) },
dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) }, dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) },