From 81f64b07a63bc564727278b977b0f81c3d8b0c72 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 18 Nov 2021 15:25:29 -0500 Subject: [PATCH] Add rations, and the ability to eat them --- src/components.rs | 5 ++++- src/game_log.rs | 4 ++++ src/inventory_system.rs | 23 +++++++++++++++++++++++ src/main.rs | 1 + src/saveload_system.rs | 10 ++++++---- src/spawner.rs | 39 +++++++++++++++++++++++++++++---------- 6 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/components.rs b/src/components.rs index 436ef03..1aedea1 100644 --- a/src/components.rs +++ b/src/components.rs @@ -48,7 +48,7 @@ pub struct Name { } impl Name { - pub fn new(s: S) -> Self { + pub fn from(s: S) -> Self { Name { name: s.to_string(), } @@ -193,6 +193,9 @@ pub struct HungerClock { pub duration: i32, } +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct ProvidesFood {} + // Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an // Entity. diff --git a/src/game_log.rs b/src/game_log.rs index ab83087..72fec60 100644 --- a/src/game_log.rs +++ b/src/game_log.rs @@ -8,4 +8,8 @@ impl GameLog { entries: vec![first_entry.to_string()], } } + + pub fn log(&mut self, s: S) { + self.entries.push(s.to_string()); + } } diff --git a/src/inventory_system.rs b/src/inventory_system.rs index 11ac37f..2acd787 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -66,6 +66,8 @@ impl<'a> System<'a> for ItemUseSystem { WriteStorage<'a, InBackpack>, WriteExpect<'a, ParticleBuilder>, ReadStorage<'a, Position>, + ReadStorage<'a, ProvidesFood>, + WriteStorage<'a, HungerClock>, ); #[allow(clippy::cognitive_complexity)] @@ -89,6 +91,8 @@ impl<'a> System<'a> for ItemUseSystem { mut backpack, mut particle_builder, positions, + provides_food, + mut hunger_clocks, ) = data; for (entity, useitem) in (&entities, &wants_use).join() { @@ -184,6 +188,25 @@ impl<'a> System<'a> for ItemUseSystem { } } + // If it is edible, eat it! + match provides_food.get(useitem.item) { + None => {} + Some(_) => { + used_item = true; + let target = targets[0]; + + if let Some(hc) = hunger_clocks.get_mut(target) { + hc.state = HungerState::WellFed; + hc.duration = 20; + + gamelog.entries.push(format!( + "You eat the {}.", + names.get(useitem.item).unwrap().name + )); + } + } + } + // If the item heals, apply the healing match healing.get(useitem.item) { None => {} diff --git a/src/main.rs b/src/main.rs index 510bbe3..4f65772 100644 --- a/src/main.rs +++ b/src/main.rs @@ -495,6 +495,7 @@ fn main() -> rltk::BError { WantsToRemoveItem, ParticleLifetime, HungerClock, + ProvidesFood, ); gs.ecs.insert(SimpleMarkerAllocator::::new()); diff --git a/src/saveload_system.rs b/src/saveload_system.rs index 530442f..b84b006 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -9,7 +9,7 @@ use std::fs::File; use std::path::Path; macro_rules! serialize_individually { - ($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*) => { + ($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*,) => { $( SerializeComponents::>::serialize( &( $ecs.read_storage::<$type>(), ), @@ -76,7 +76,8 @@ pub fn save_game(ecs: &mut World) { DefenseBonus, WantsToRemoveItem, ParticleLifetime, - HungerClock + HungerClock, + ProvidesFood, ); } @@ -90,7 +91,7 @@ pub fn does_save_exist() -> bool { } macro_rules! deserialize_individually { - ($ecs:expr, $de:expr, $data:expr, $( $type:ty),*) => { + ($ecs:expr, $de:expr, $data:expr, $( $type:ty),*,) => { $( DeserializeComponents::::deserialize( &mut ( &mut $ecs.write_storage::<$type>(), ), @@ -159,7 +160,8 @@ pub fn load_game(ecs: &mut World) { DefenseBonus, WantsToRemoveItem, ParticleLifetime, - HungerClock + HungerClock, + ProvidesFood, ); } diff --git a/src/spawner.rs b/src/spawner.rs index a6e1274..ed98564 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -20,7 +20,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { }) .with(Player {}) .with(Viewshed::default()) - .with(Name::new("Player")) + .with(Name::from("Player")) .with(CombatStats { max_hp: 30, hp: 30, @@ -49,6 +49,7 @@ fn room_table(map_depth: i32) -> RandomTable { .add("Shield", 3) .add("Longsword", map_depth - 1) .add("Tower Shield", map_depth - 1) + .add("Rations", 10) } /// fills a room with stuff! @@ -97,6 +98,7 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) { "Shield" => shield(ecs, x, y), "Longsword" => longsword(ecs, x, y), "Tower Shield" => tower_shield(ecs, x, y), + "Rations" => rations(ecs, x, y), _ => {} } } @@ -121,7 +123,7 @@ fn monster(ecs: &mut World, x: i32, y: i32, glyph: rltk::FontCharTy }) .with(Viewshed::default()) .with(Monster {}) - .with(Name::new(name)) + .with(Name::from(name)) .with(BlocksTile {}) .with(CombatStats { max_hp: 16, @@ -142,7 +144,7 @@ fn health_potion(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Health Potion")) + .with(Name::from("Health Potion")) .with(Item {}) .with(Consumable {}) .with(ProvidesHealing { heal_amount: 8 }) @@ -159,7 +161,7 @@ fn magic_missile_scroll(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Magic Missile Scroll")) + .with(Name::from("Magic Missile Scroll")) .with(Item {}) .with(Consumable {}) .with(Ranged { range: 6 }) @@ -177,7 +179,7 @@ fn fireball_scroll(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Fireball Scroll")) + .with(Name::from("Fireball Scroll")) .with(Item {}) .with(Consumable {}) .with(Ranged { range: 6 }) @@ -196,7 +198,7 @@ fn confusion_scroll(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Confusion Scroll")) + .with(Name::from("Confusion Scroll")) .with(Item {}) .with(Consumable {}) .with(Ranged { range: 6 }) @@ -214,7 +216,7 @@ fn dagger(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Dagger")) + .with(Name::from("Dagger")) .with(Item {}) .with(Equippable { slot: EquipmentSlot::Melee, @@ -233,7 +235,7 @@ fn shield(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Shield")) + .with(Name::from("Shield")) .with(Item {}) .with(Equippable { slot: EquipmentSlot::Shield, @@ -252,7 +254,7 @@ fn longsword(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Longsword")) + .with(Name::from("Longsword")) .with(Item {}) .with(Equippable { slot: EquipmentSlot::Melee, @@ -271,7 +273,7 @@ fn tower_shield(ecs: &mut World, x: i32, y: i32) { bg: RGB::named(rltk::BLACK), render_order: 2, }) - .with(Name::new("Tower Shield")) + .with(Name::from("Tower Shield")) .with(Item {}) .with(Equippable { slot: EquipmentSlot::Shield, @@ -280,3 +282,20 @@ fn tower_shield(ecs: &mut World, x: i32, y: i32) { .marked::>() .build(); } + +fn rations(ecs: &mut World, x: i32, y: i32) { + ecs.create_entity() + .with(Position { x, y }) + .with(Renderable { + glyph: rltk::to_cp437('%'), + fg: RGB::named(rltk::GREEN), + bg: RGB::named(rltk::BLACK), + render_order: 2, + }) + .with(Name::from("Rations")) + .with(Item {}) + .with(ProvidesFood {}) + .with(Consumable {}) + .marked::>() + .build(); +}