diff --git a/raws/spawns.json b/raws/spawns.json index 5719515..6fd9508 100644 --- a/raws/spawns.json +++ b/raws/spawns.json @@ -301,7 +301,12 @@ "power": 4 }, "vision_range": 4, - "ai": "bystander" + "ai": "bystander", + "quips": [ + "Quiet down, it's too early!", + "Oh my, I drank too much.", + "Still saving the world, eh?" + ] }, { "name": "Priest", @@ -337,7 +342,12 @@ "power": 4 }, "vision_range": 4, - "ai": "bystander" + "ai": "bystander", + "quips": [ + "Great to see a new face here!", + "I hear there's going to be a good sermon on tea", + "Want some cake?" + ] }, { "name": "Blacksmith", @@ -409,7 +419,13 @@ "power": 4 }, "vision_range": 4, - "ai": "bystander" + "ai": "bystander", + "quips": [ + "Hello, dear", + "Off saving the world again?", + "Be careful in the dungeon!", + "Your father would be so proud, were he here." + ] }, { "name": "Peasant", @@ -427,7 +443,102 @@ "power": 4 }, "vision_range": 4, - "ai": "bystander" + "ai": "bystander", + "quips": [ + "Why are you in my house?" + ] + }, + { + "name": "Dock Worker", + "renderable": { + "glyph": "☺", + "fg": "#999999", + "bg": "#000000", + "order": 1 + }, + "blocks_tile": true, + "stats": { + "max_hp": 16, + "hp": 16, + "defense": 1, + "power": 4 + }, + "vision_range": 4, + "ai": "bystander", + "quips": [ + "Lovely day, eh?", + "Nice weather", + "Hello" + ] + }, + { + "name": "Fisher", + "renderable": { + "glyph": "☺", + "fg": "#999999", + "bg": "#000000", + "order": 1 + }, + "blocks_tile": true, + "stats": { + "max_hp": 16, + "hp": 16, + "defense": 1, + "power": 4 + }, + "vision_range": 4, + "ai": "bystander", + "quips": [ + "They're biting today!", + "I caught something, but it wasn't a fish!", + "Looks like rain" + ] + }, + { + "name": "Wannabe Pirate", + "renderable": { + "glyph": "☺", + "fg": "#aa9999", + "bg": "#000000", + "order": 1 + }, + "blocks_tile": true, + "stats": { + "max_hp": 16, + "hp": 16, + "defense": 1, + "power": 4 + }, + "vision_range": 4, + "ai": "bystander", + "quips": [ + "Arrr", + "Grog!", + "Booze!" + ] + }, + { + "name": "Drunk", + "renderable": { + "glyph": "☺", + "fg": "#aa9999", + "bg": "#000000", + "order": 1 + }, + "blocks_tile": true, + "stats": { + "max_hp": 16, + "hp": 16, + "defense": 1, + "power": 4 + }, + "vision_range": 4, + "ai": "bystander", + "quips": [ + "Hic", + "Need... more... booze!", + "Spare a copper?" + ] }, { "name": "Rat", diff --git a/src/bystander_ai_system.rs b/src/bystander_ai_system.rs index 1e6bee0..f05e599 100644 --- a/src/bystander_ai_system.rs +++ b/src/bystander_ai_system.rs @@ -1,8 +1,9 @@ -use ::rltk::RandomNumberGenerator; +use ::rltk::{Point, RandomNumberGenerator}; use specs::prelude::*; +use super::game_log::GameLog; use super::{Map, RunState}; -use crate::components::{Bystander, EntityMoved, Position, Viewshed}; +use crate::components::{Bystander, EntityMoved, Name, Position, Quips, Viewshed}; pub struct BystanderAI {} @@ -17,6 +18,10 @@ impl<'a> System<'a> for BystanderAI { WriteStorage<'a, Position>, WriteStorage<'a, EntityMoved>, WriteExpect<'a, RandomNumberGenerator>, + ReadExpect<'a, Point>, + WriteExpect<'a, GameLog>, + WriteStorage<'a, Quips>, + ReadStorage<'a, Name>, ); fn run(&mut self, data: Self::SystemData) { @@ -29,6 +34,10 @@ impl<'a> System<'a> for BystanderAI { mut position, mut entity_moved, mut rng, + player_pos, + mut gamelog, + mut quips, + names, ) = data; if *runstate != RunState::MonsterTurn { @@ -38,6 +47,28 @@ impl<'a> System<'a> for BystanderAI { for (entity, mut viewshed, _bystander, mut pos) in (&entities, &mut viewshed, &bystander, &mut position).join() { + // Possibly quip + if let Some(quip) = quips.get_mut(entity) { + if !quip.available.is_empty() + && viewshed.visible_tiles.contains(&player_pos) + && rng.roll_dice(1, 6) == 1 + { + let name = names.get(entity); + let quip_index = if quip.available.len() == 1 { + 0 + } else { + (rng.roll_dice(1, quip.available.len() as i32) - 1) as usize + }; + + gamelog.append(format!( + "{} says \"{}\"", + name.unwrap().name, + quip.available[quip_index] + )); + quip.available.remove(quip_index); + } + } + // Try to move randomly let mut x = pos.x; let mut y = pos.y; diff --git a/src/components.rs b/src/components.rs index 20c0e27..8d5d411 100644 --- a/src/components.rs +++ b/src/components.rs @@ -243,6 +243,11 @@ pub struct Bystander {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Vendor {} +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct Quips { + pub available: Vec, +} + // Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an // Entity. diff --git a/src/main.rs b/src/main.rs index 0901f78..301229e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -540,6 +540,7 @@ fn main() -> ::rltk::BError { Door, Bystander, Vendor, + Quips, ); gs.ecs.insert(SimpleMarkerAllocator::::new()); diff --git a/src/raws/mob_structs.rs b/src/raws/mob_structs.rs index 0dfd2ea..6b1eab8 100644 --- a/src/raws/mob_structs.rs +++ b/src/raws/mob_structs.rs @@ -10,6 +10,7 @@ pub struct Mob { pub stats: MobStats, pub vision_range: i32, pub ai: String, + pub quips: Option>, } #[derive(Deserialize, Debug)] diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index 9ef6189..e1737c1 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -219,6 +219,13 @@ pub fn spawn_named_mob( _ => {} }; + // Quips + if let Some(quips) = &mob_template.quips { + eb = eb.with(Quips { + available: quips.clone(), + }); + } + if mob_template.blocks_tile { eb = eb.with(BlocksTile {}); } diff --git a/src/saveload_system.rs b/src/saveload_system.rs index 1d3735f..00b43fc 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -91,6 +91,7 @@ pub fn save_game(ecs: &mut World) { Door, Bystander, Vendor, + Quips, ); } @@ -184,6 +185,7 @@ pub fn load_game(ecs: &mut World) { Door, Bystander, Vendor, + Quips, ); }