Look shows health and charges.

This commit is contained in:
Condorra 2023-02-23 22:55:02 +11:00
parent 8e1d15bade
commit 70dae5b853
5 changed files with 102 additions and 5 deletions

View File

@ -5,8 +5,12 @@ use ansi::{ansi, flow_around, word_wrap};
use crate::{ use crate::{
db::ItemSearchParams, db::ItemSearchParams,
models::{item::{Item, LocationActionType, Subattack, ItemFlag}}, models::{item::{Item, LocationActionType, Subattack, ItemFlag}},
static_content::room::{self, Direction}, static_content::{
room::{self, Direction},
possession_type::possession_data,
},
language, language,
services::combat::max_health,
}; };
use itertools::Itertools; use itertools::Itertools;
use std::sync::Arc; 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(); let phrases_str: Vec<&str> = phrases.iter().map(|p| p.as_str()).collect();
contents_desc.push_str(&(language::join_words(&phrases_str) + ".\n")); 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.trans.queue_for_session(
ctx.session, ctx.session,
Some(&format!("{}\n{}\n{}", Some(&format!("{}\n{}\n{}",

View File

@ -302,6 +302,7 @@ pub struct Item {
pub sex: Option<Sex>, pub sex: Option<Sex>,
pub active_combat: Option<ActiveCombat>, pub active_combat: Option<ActiveCombat>,
pub weight: u64, pub weight: u64,
pub charges: u8
} }
impl Item { impl Item {
@ -378,6 +379,7 @@ impl Default for Item {
sex: None, sex: None,
active_combat: Some(Default::default()), active_combat: Some(Default::default()),
weight: 0, weight: 0,
charges: 0,
} }
} }
} }

View File

@ -244,8 +244,20 @@ pub async fn handle_resurrect(trans: &DBTrans, player: &mut Item) -> DResult<boo
Ok(true) Ok(true)
} }
pub fn max_health(_whom: &Item) -> u64 { 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 24
}
} }
pub static TASK_HANDLER: &(dyn TaskHandler + Sync + Send) = &AttackTaskHandler; pub static TASK_HANDLER: &(dyn TaskHandler + Sync + Send) = &AttackTaskHandler;

View File

@ -14,7 +14,6 @@ use crate::models::{
}; };
use crate::services::{ use crate::services::{
combat::{ combat::{
max_health,
corpsify_item, corpsify_item,
start_attack, start_attack,
} }
@ -78,6 +77,7 @@ pub struct NPC {
pub says: Vec<NPCSayInfo>, pub says: Vec<NPCSayInfo>,
pub attackable: bool, pub attackable: bool,
pub aggression: u64, pub aggression: u64,
pub max_health: u64,
pub intrinsic_weapon: Option<PossessionType>, pub intrinsic_weapon: Option<PossessionType>,
pub total_xp: u64, pub total_xp: u64,
pub total_skills: BTreeMap<SkillType, f64>, pub total_skills: BTreeMap<SkillType, f64>,
@ -102,6 +102,7 @@ impl Default for NPC {
.map(|sk| (sk.clone(), if &sk == &SkillType::Dodge { 8.0 } else { 10.0 })).collect(), .map(|sk| (sk.clone(), if &sk == &SkillType::Dodge { 8.0 } else { 10.0 })).collect(),
attackable: false, attackable: false,
aggression: 0, aggression: 0,
max_health: 24,
intrinsic_weapon: None, intrinsic_weapon: None,
species: SpeciesType::Human, species: SpeciesType::Human,
wander_zones: vec!(), wander_zones: vec!(),
@ -166,6 +167,7 @@ pub fn npc_static_items() -> Box<dyn Iterator<Item = StaticItem>> {
total_xp: c.total_xp.clone(), total_xp: c.total_xp.clone(),
total_skills: c.total_skills.clone(), total_skills: c.total_skills.clone(),
species: c.species.clone(), species: c.species.clone(),
health: c.max_health.clone(),
aliases: c.aliases.iter().map(|a| (*a).to_owned()).collect::<Vec<String>>(), aliases: c.aliases.iter().map(|a| (*a).to_owned()).collect::<Vec<String>>(),
..Item::default() ..Item::default()
}) })
@ -423,7 +425,7 @@ impl TaskHandler for NPCRecloneTaskHandler {
corpsify_item(ctx.trans, &npc_item).await?; corpsify_item(ctx.trans, &npc_item).await?;
npc_item.is_dead = false; 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(); npc_item.location = npc.spawn_location.to_owned();
ctx.trans.save_item_model(&npc_item).await?; ctx.trans.save_item_model(&npc_item).await?;
return Ok(None); return Ok(None);

View File

@ -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 struct PossessionData {
pub weapon_data: Option<WeaponData>, pub weapon_data: Option<WeaponData>,
pub display: &'static str, pub display: &'static str,
@ -61,6 +77,7 @@ pub struct PossessionData {
pub details_less_explicit: Option<&'static str>, pub details_less_explicit: Option<&'static str>,
pub aliases: Vec<&'static str>, pub aliases: Vec<&'static str>,
pub max_health: u64, pub max_health: u64,
pub charge_data: Option<ChargeData>,
pub weight: u64, pub weight: u64,
} }
@ -75,6 +92,7 @@ impl Default for PossessionData {
aliases: vec!(), aliases: vec!(),
max_health: 10, max_health: 10,
weight: 100, weight: 100,
charge_data: None,
} }
} }
} }
@ -128,6 +146,8 @@ impl Into<Item> for PossessionType {
is_proper: false, is_proper: false,
..Pronouns::default_inanimate() ..Pronouns::default_inanimate()
}, },
charges: possession_dat.charge_data.as_ref()
.map(|cd| cd.max_charges).unwrap_or(0),
..Default::default() ..Default::default()
} }
} }
@ -232,6 +252,12 @@ pub fn possession_data() -> &'static BTreeMap<PossessionType, PossessionData> {
display: "medium trauma kit", 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.", 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"), aliases: vec!("trauma"),
charge_data: Some(ChargeData {
max_charges: 5,
charge_name_prefix: "treatment",
charge_name_suffix: "worth of supplies",
..Default::default()
}),
..Default::default() ..Default::default()
}), }),
).into_iter().collect() ).into_iter().collect()