From 70dae5b853a7d59059bf2f8179caf7b83fda4c03 Mon Sep 17 00:00:00 2001 From: Condorra Date: Thu, 23 Feb 2023 22:55:02 +1100 Subject: [PATCH] Look shows health and charges. --- .../src/message_handler/user_commands/look.rs | 57 ++++++++++++++++++- blastmud_game/src/models/item.rs | 2 + blastmud_game/src/services/combat.rs | 16 +++++- blastmud_game/src/static_content/npc.rs | 6 +- .../src/static_content/possession_type.rs | 26 +++++++++ 5 files changed, 102 insertions(+), 5 deletions(-) diff --git a/blastmud_game/src/message_handler/user_commands/look.rs b/blastmud_game/src/message_handler/user_commands/look.rs index 628613f7..1a6c99df 100644 --- a/blastmud_game/src/message_handler/user_commands/look.rs +++ b/blastmud_game/src/message_handler/user_commands/look.rs @@ -5,8 +5,12 @@ use ansi::{ansi, flow_around, word_wrap}; use crate::{ db::ItemSearchParams, models::{item::{Item, LocationActionType, Subattack, ItemFlag}}, - static_content::room::{self, Direction}, + static_content::{ + room::{self, Direction}, + possession_type::possession_data, + }, language, + services::combat::max_health, }; use itertools::Itertools; use std::sync::Arc; @@ -75,6 +79,57 @@ pub async fn describe_normal_item(ctx: &VerbContext<'_>, item: &Item) -> UResult let phrases_str: Vec<&str> = phrases.iter().map(|p| p.as_str()).collect(); contents_desc.push_str(&(language::join_words(&phrases_str) + ".\n")); } + let health_max = max_health(&item); + if health_max > 0 { + let health_ratio = (item.health as f64) / (health_max as f64); + if item.item_type == "player" || item.item_type == "npc" { + if health_ratio == 1.0 { + contents_desc.push_str(&format!("{} is in perfect health.\n", &language::caps_first(&item.pronouns.subject))); + } else if health_ratio >= 0.75 { + contents_desc.push_str(&format!("{} has some minor cuts and bruises.\n", &language::caps_first(&item.pronouns.subject))); + } else if health_ratio >= 0.5 { + contents_desc.push_str(&format!("{} has deep wounds all over {} body.\n", &language::caps_first(&item.pronouns.subject), &item.pronouns.possessive)); + } else if health_ratio >= 0.25 { + contents_desc.push_str(&format!("{} looks seriously injured.\n", + &language::caps_first( + &item.pronouns.subject))); + } else { + contents_desc.push_str(&format!("{} looks like {}'s on death's door.\n", + &language::caps_first( + &item.pronouns.subject), + &item.pronouns.possessive)); + } + } else if item.item_type == "possession" { + if health_ratio == 1.0 { + contents_desc.push_str(&format!("{}'s in perfect condition.\n", &language::caps_first(&item.pronouns.subject))); + } else if health_ratio >= 0.75 { + contents_desc.push_str(&format!("{}'s slightly beaten up.\n", &language::caps_first(&item.pronouns.subject))); + } else if health_ratio >= 0.5 { + contents_desc.push_str(&format!("{}'s pretty beaten up.\n", &language::caps_first(&item.pronouns.subject))); + } else if health_ratio >= 0.25 { + contents_desc.push_str(&format!("{}'s seriously damaged.\n", &language::caps_first(&item.pronouns.subject))); + } else { + contents_desc.push_str(&format!("{}'s nearly completely destroyed.\n", + &language::caps_first(&item.pronouns.subject))); + } + } + } + + if item.item_type == "possession" { + if let Some(charge_data) = item.possession_type.as_ref() + .and_then(|pt| possession_data().get(&pt)) + .and_then(|pd| pd.charge_data.as_ref()) { + let unit = if item.charges == 1 { + charge_data.charge_name_prefix.to_owned() + " " + + charge_data.charge_name_suffix + } else { + language::pluralise(charge_data.charge_name_prefix) + " " + + charge_data.charge_name_suffix + }; + contents_desc.push_str(&format!("It has {} {} left.\n", item.charges, unit)); + } + } + ctx.trans.queue_for_session( ctx.session, Some(&format!("{}\n{}\n{}", diff --git a/blastmud_game/src/models/item.rs b/blastmud_game/src/models/item.rs index 76aa236b..8a174e51 100644 --- a/blastmud_game/src/models/item.rs +++ b/blastmud_game/src/models/item.rs @@ -302,6 +302,7 @@ pub struct Item { pub sex: Option, pub active_combat: Option, pub weight: u64, + pub charges: u8 } impl Item { @@ -378,6 +379,7 @@ impl Default for Item { sex: None, active_combat: Some(Default::default()), weight: 0, + charges: 0, } } } diff --git a/blastmud_game/src/services/combat.rs b/blastmud_game/src/services/combat.rs index e09f1185..7929e194 100644 --- a/blastmud_game/src/services/combat.rs +++ b/blastmud_game/src/services/combat.rs @@ -244,8 +244,20 @@ pub async fn handle_resurrect(trans: &DBTrans, player: &mut Item) -> DResult u64 { - 24 +pub fn max_health(whom: &Item) -> u64 { + if whom.item_type == "npc" { + npc_by_code().get(whom.item_code.as_str()) + .map(|npc| npc.max_health) + .unwrap_or(24) + } else if whom.item_type == "player" { + (22.0 + (whom.total_xp as f64).log(1.4)).min(60.0) as u64 + } else if whom.item_type == "possession" { + whom.possession_type.as_ref().and_then(|pt| possession_data().get(&pt)) + .map(|poss| poss.max_health) + .unwrap_or(10) + } else { + 24 + } } pub static TASK_HANDLER: &(dyn TaskHandler + Sync + Send) = &AttackTaskHandler; diff --git a/blastmud_game/src/static_content/npc.rs b/blastmud_game/src/static_content/npc.rs index e860205d..ac070028 100644 --- a/blastmud_game/src/static_content/npc.rs +++ b/blastmud_game/src/static_content/npc.rs @@ -14,7 +14,6 @@ use crate::models::{ }; use crate::services::{ combat::{ - max_health, corpsify_item, start_attack, } @@ -78,6 +77,7 @@ pub struct NPC { pub says: Vec, pub attackable: bool, pub aggression: u64, + pub max_health: u64, pub intrinsic_weapon: Option, pub total_xp: u64, pub total_skills: BTreeMap, @@ -102,6 +102,7 @@ impl Default for NPC { .map(|sk| (sk.clone(), if &sk == &SkillType::Dodge { 8.0 } else { 10.0 })).collect(), attackable: false, aggression: 0, + max_health: 24, intrinsic_weapon: None, species: SpeciesType::Human, wander_zones: vec!(), @@ -166,6 +167,7 @@ pub fn npc_static_items() -> Box> { total_xp: c.total_xp.clone(), total_skills: c.total_skills.clone(), species: c.species.clone(), + health: c.max_health.clone(), aliases: c.aliases.iter().map(|a| (*a).to_owned()).collect::>(), ..Item::default() }) @@ -423,7 +425,7 @@ impl TaskHandler for NPCRecloneTaskHandler { corpsify_item(ctx.trans, &npc_item).await?; npc_item.is_dead = false; - npc_item.health = max_health(&npc_item); + npc_item.health = npc.max_health; npc_item.location = npc.spawn_location.to_owned(); ctx.trans.save_item_model(&npc_item).await?; return Ok(None); diff --git a/blastmud_game/src/static_content/possession_type.rs b/blastmud_game/src/static_content/possession_type.rs index 9c1f2b1a..27dcfb8f 100644 --- a/blastmud_game/src/static_content/possession_type.rs +++ b/blastmud_game/src/static_content/possession_type.rs @@ -53,6 +53,22 @@ impl Default for WeaponData { } } +pub struct ChargeData { + pub max_charges: u8, + pub charge_name_prefix: &'static str, + pub charge_name_suffix: &'static str, +} + +impl Default for ChargeData { + fn default() -> Self { + Self { + max_charges: 1, + charge_name_prefix: "charge", + charge_name_suffix: "" + } + } +} + pub struct PossessionData { pub weapon_data: Option, pub display: &'static str, @@ -61,6 +77,7 @@ pub struct PossessionData { pub details_less_explicit: Option<&'static str>, pub aliases: Vec<&'static str>, pub max_health: u64, + pub charge_data: Option, pub weight: u64, } @@ -75,6 +92,7 @@ impl Default for PossessionData { aliases: vec!(), max_health: 10, weight: 100, + charge_data: None, } } } @@ -128,6 +146,8 @@ impl Into for PossessionType { is_proper: false, ..Pronouns::default_inanimate() }, + charges: possession_dat.charge_data.as_ref() + .map(|cd| cd.max_charges).unwrap_or(0), ..Default::default() } } @@ -232,6 +252,12 @@ pub fn possession_data() -> &'static BTreeMap { display: "medium trauma kit", details: "A collection of bandages and and small gadgets that look like they could, in the right hands, make an unhealthy person healthy again. It looks like when brand new, it could be used 5 times.", aliases: vec!("trauma"), + charge_data: Some(ChargeData { + max_charges: 5, + charge_name_prefix: "treatment", + charge_name_suffix: "worth of supplies", + ..Default::default() + }), ..Default::default() }), ).into_iter().collect()