diff options
| author | troido <troido@protonmail.com> | 2020-04-10 00:16:39 +0200 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-04-10 00:16:39 +0200 |
| commit | afd1317197d1346626c58736defbbdf8aee7da68 (patch) | |
| tree | 56781223a2664f292ee6f470d992b47c6b1b8609 | |
| parent | e7b4ed0f044c3ada82155f81d3b61c0c5ce36583 (diff) | |
send out notifications when fighting
| -rw-r--r-- | src/components/ear.rs | 87 | ||||
| -rw-r--r-- | src/components/mod.rs | 2 | ||||
| -rw-r--r-- | src/systems/attacking.rs | 40 | ||||
| -rw-r--r-- | src/systems/interact.rs | 32 | ||||
| -rw-r--r-- | src/worldmessages.rs | 2 |
5 files changed, 135 insertions, 28 deletions
diff --git a/src/components/ear.rs b/src/components/ear.rs index 4bfc87b..1432164 100644 --- a/src/components/ear.rs +++ b/src/components/ear.rs @@ -2,23 +2,96 @@ use specs::{ HashMapStorage, Component, + Entity, + WriteStorage }; #[derive(Debug, Clone)] -pub struct Sound { - pub source: Option<String>, - pub text: String +pub enum HealthNotification { + Attack, + Damage, + Heal } -impl Sound { - pub fn as_message(self) -> (Option<String>, String) { - (None, format!("{}: {}", self.source.unwrap_or("".to_string()), self.text)) +use HealthNotification::*; + +#[derive(Debug, Clone)] +pub enum Notification { + Sound{ + source: Option<String>, + text: String + }, + Health { + actor: String, + target: String, + amount: i64, + typ: HealthNotification + }, + Kill { + actor: String, + target: String + }, + Die { + actor: String, + target: String + } +} + +use Notification::*; + + +impl Notification { + + + pub fn type_name(&self) -> String { + (match self { + Sound{source: _, text: _} => "sound", + Health{actor: _, target: _, amount: _, typ} => match typ { + Attack => "attack", + Damage => "damage", + Heal => "heal" + }, + Kill{actor: _, target: _} => "kill", + Die{actor: _, target: _} => "die" + }).to_string() + } + + pub fn as_message(&self) -> (String, String) { + let body = match self { + Sound{source, text} => { + if let Some(name) = &source { + format!("{}: {}", name, &text) + } else { + text.clone() + } + } + Health{actor, target, amount, typ} => { + match typ { + Attack | Damage => format!("{} attacks {} for {} damage", actor, target, amount), + Heal => format!("{} heals {} for {} health", actor, target, amount) + } + }, + Kill{actor, target} => { + format!("{} kills {}", actor, target) + }, + Die{actor, target} => { + format!("{} was killed by {}", target, actor) + } + }; + (self.type_name(), body) } } #[derive(Component, Debug, Clone, Default)] #[storage(HashMapStorage)] pub struct Ear{ - pub sounds: Vec<Sound> + pub sounds: Vec<Notification> +} + +pub fn say(ears: &mut WriteStorage<Ear>, ent: Entity, msg: Notification){ + if let Some(ear) = ears.get_mut(ent) { + ear.sounds.push(msg); + } } + diff --git a/src/components/mod.rs b/src/components/mod.rs index 4065cc2..cb28c4b 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -23,7 +23,7 @@ pub use flags::{ Flags }; pub use ear::{ - Sound, + Notification, Ear }; diff --git a/src/systems/attacking.rs b/src/systems/attacking.rs index e4001c9..804fac1 100644 --- a/src/systems/attacking.rs +++ b/src/systems/attacking.rs @@ -11,7 +11,17 @@ use specs::{ }; use crate::{ - components::{Health, AttackInbox, AttackType, Dead, Position, Autofight}, + components::{ + Health, + AttackInbox, + AttackType, + Dead, + Position, + Autofight, + Ear, + ear::{Notification, HealthNotification::{Attack, Damage, Heal}, say}, + Visible + }, resources::NewEntities, Template, util @@ -27,9 +37,11 @@ impl <'a> System<'a> for Attacking { WriteStorage<'a, Dead>, ReadStorage<'a, Position>, Write<'a, NewEntities>, - WriteStorage<'a, Autofight> + WriteStorage<'a, Autofight>, + WriteStorage<'a, Ear>, + ReadStorage<'a, Visible> ); - fn run(&mut self, (entities, mut attackeds, mut healths, mut deads, positions, mut new, mut autofighters): Self::SystemData) { + fn run(&mut self, (entities, mut attackeds, mut healths, mut deads, positions, mut new, mut autofighters, mut ears, visibles): Self::SystemData) { for (entity, attacked, autofighter) in (&entities, &attackeds, &mut autofighters).join() { for attack in &attacked.messages { @@ -42,27 +54,43 @@ impl <'a> System<'a> for Attacking { } } } - for (ent, health, attacked) in (&entities, &mut healths, &mut attackeds).join() { + for (target, health, attacked) in (&entities, &mut healths, &mut attackeds).join() { + let target_name = visibles.get(target).map(|v| v.name.as_str()).unwrap_or("?").to_string(); let mut wounded = false; + let mut attackers = Vec::new(); + let mut attacker_names = Vec::new(); for attack in attacked.messages.drain(..) { + let actor_name = attack.attacker.map(|ae| visibles.get(ae)).flatten().map(|v| v.name.as_str()).unwrap_or("?").to_string(); match attack.typ { AttackType::Attack(strength) => { let damage = rand::thread_rng().gen_range(0, strength+1); health.health -= damage; if damage > 0 { wounded = true; + if let Some(actor) = attack.attacker { + say(&mut ears, actor, Notification::Health{actor: actor_name.clone(), target: target_name.clone(), amount: damage, typ: Attack}); + attackers.push(actor); + attacker_names.push(actor_name.clone()); + } + say(&mut ears, target, Notification::Health{actor: actor_name.clone(), target: target_name.clone(), amount: damage, typ: Damage}); } } AttackType::Heal(healthdiff) => { + say(&mut ears, target, Notification::Health{actor: actor_name.clone(), target: target_name.clone(), amount: healthdiff, typ: Heal}); health.health += healthdiff; } } } health.health = util::clamp(health.health, 0, health.maxhealth); if health.health == 0 { - deads.insert(ent, Dead).unwrap(); + deads.insert(target, Dead).unwrap(); + let killers = attacker_names.join(" and "); + say(&mut ears, target, Notification::Die{actor: killers.clone(), target: target_name.clone()}); + for actor in attackers { + say(&mut ears, actor, Notification::Kill{actor: killers.clone(), target: target_name.clone()}); + } } - if let Some(position) = positions.get(ent){ + if let Some(position) = positions.get(target){ if wounded { new.create(position.pos, &Template::empty("wound")).unwrap(); } diff --git a/src/systems/interact.rs b/src/systems/interact.rs index fb11488..73f9023 100644 --- a/src/systems/interact.rs +++ b/src/systems/interact.rs @@ -17,9 +17,10 @@ use crate::{ ControlCooldown, Interactable, Dead, - Sound, + Notification, Ear, - Inventory + Inventory, + Visible }, controls::{Control}, resources::{Ground, NewEntities} @@ -37,10 +38,11 @@ impl <'a> System<'a> for Interact { WriteStorage<'a, Dead>, Write<'a, NewEntities>, WriteStorage<'a, Ear>, - WriteStorage<'a, Inventory> + WriteStorage<'a, Inventory>, + ReadStorage<'a, Visible> ); - fn run(&mut self, (entities, controllers, positions, ground, mut cooldowns, interactables, mut deads, new, mut ears, mut inventories): Self::SystemData) { + fn run(&mut self, (entities, controllers, positions, ground, mut cooldowns, interactables, mut deads, new, mut ears, mut inventories, visibles): Self::SystemData) { for (entity, controller, position) in (&entities, &controllers, &positions).join(){ let mut target = None; let ear = ears.get_mut(entity); @@ -61,15 +63,16 @@ impl <'a> System<'a> for Interact { _ => {} } if let Some((ent, interactable, arg)) = target { + let name = visibles.get(ent).map(|v| v.name.as_str()); match interactable { Interactable::Harvest => { deads.insert(ent, Dead).unwrap(); } Interactable::Say(text) => { - say(ear, text.clone()); + say(ear, text.clone(), name); } Interactable::Reply(text) => { - say(ear, text.replace("{}", &arg.unwrap())); + say(ear, text.replace("{}", &arg.unwrap()), name); } Interactable::Exchange(prefix, exchanges) => { if let Some(txt) = arg { @@ -79,19 +82,22 @@ impl <'a> System<'a> for Interact { if let Some(exchange) = exchanges.get(action) { if exchange.can_trade(inventory){ exchange.trade(inventory, &new.encyclopedia); - say(ear, format!("Success! '{}' ({})", txt, exchange.show())); + say(ear, format!("Success! '{}' ({})", txt, exchange.show()), name); } else { - say(ear, format!("You do not have the required items or inventory space for '{}' ({})", txt, exchange.show())); + say(ear, format!("You do not have the required items or inventory space for '{}' ({})", txt, exchange.show()), name); } } else { - say(ear, format!("Invalid option: {}", action)); + say(ear, format!("Invalid option: {}", action), name); } } } } else { - say(ear, format!("options: {:?}", exchanges.iter().map(|(id, exchange)| + say( + ear, + format!("options: {:?}", exchanges.iter().map(|(id, exchange)| format!("{}{}: {}", prefix, id, exchange.show()) - ).collect::<Vec<String>>()) + ).collect::<Vec<String>>()), + name ); } } @@ -102,8 +108,8 @@ impl <'a> System<'a> for Interact { } } -fn say(maybe_ear: Option<&mut Ear>, text: String){ +fn say(maybe_ear: Option<&mut Ear>, text: String, source: Option<&str>){ if let Some(ear) = maybe_ear { - ear.sounds.push(Sound{source: None, text}); + ear.sounds.push(Notification::Sound{text, source: source.map(|s| s.to_string())}); } } diff --git a/src/worldmessages.rs b/src/worldmessages.rs index 676ef00..7dd05ec 100644 --- a/src/worldmessages.rs +++ b/src/worldmessages.rs @@ -68,7 +68,7 @@ pub type ChangeMessage = Vec<(Pos, Vec<Sprite>)>; pub type HealthMessage = (i64, i64); pub type InventoryMessage = Vec<(String, bool)>; pub type GroundMessage = Vec<String>; -pub type SoundMessage = Vec<(Option<String>, String)>; +pub type SoundMessage = Vec<(String, String)>; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] pub struct FieldMessage { |
