diff --git a/blastmud_game/src/message_handler/user_commands/cut.rs b/blastmud_game/src/message_handler/user_commands/cut.rs index 29da3d9..d1312eb 100644 --- a/blastmud_game/src/message_handler/user_commands/cut.rs +++ b/blastmud_game/src/message_handler/user_commands/cut.rs @@ -17,6 +17,7 @@ use crate::{ comms::broadcast_to_room, destroy_container, skills::skill_check_and_grind, + urges::change_stress_considering_cool, }, static_content::possession_type::{can_butcher_possessions, possession_data}, }; @@ -34,6 +35,15 @@ impl QueueCommandHandler for QueueHandler { "You butcher things while they are dead, not while YOU are dead!".to_owned(), )?; } + if ctx.item.urges.as_ref().map(|u| u.stress.value).unwrap_or(0) > 7000 { + user_error( + ansi!( + "You are too tired and stressed to consider crafts. Maybe try to \ + sit or recline for a bit!" + ) + .to_owned(), + )?; + } let (from_corpse_id, what_part) = match ctx.command { QueueCommand::Cut { from_corpse, @@ -213,6 +223,7 @@ impl QueueCommandHandler for QueueHandler { } if skill_check_and_grind(&ctx.trans, ctx.item, &SkillType::Craft, 10.0).await? < 0.0 { + change_stress_considering_cool(&ctx.trans, &mut ctx.item, 500).await?; broadcast_to_room( &ctx.trans, &ctx.item.location, diff --git a/blastmud_game/src/message_handler/user_commands/improvise.rs b/blastmud_game/src/message_handler/user_commands/improvise.rs index 6b96ebf..3bd983e 100644 --- a/blastmud_game/src/message_handler/user_commands/improvise.rs +++ b/blastmud_game/src/message_handler/user_commands/improvise.rs @@ -12,6 +12,7 @@ use crate::{ comms::broadcast_to_room, destroy_container, skills::{crit_fail_penalty_for_skill, skill_check_and_grind}, + urges::change_stress_considering_cool, }, static_content::possession_type::{ improv_by_ingredient, improv_by_output, possession_data, possession_type_names, @@ -37,6 +38,16 @@ impl QueueCommandHandler for WithQueueHandler { QueueCommand::ImprovWith { possession_id } => possession_id, _ => user_error("Unexpected command".to_owned())?, }; + if ctx.item.urges.as_ref().map(|u| u.stress.value).unwrap_or(0) > 7000 { + user_error( + ansi!( + "You are too tired and stressed to consider crafts. Maybe try to \ + sit or recline for a bit!" + ) + .to_owned(), + )?; + } + let item = match ctx .trans .find_item_by_type_code("possession", &item_id) @@ -304,6 +315,7 @@ impl QueueCommandHandler for FromQueueHandler { ) .await?; if skill_result <= -0.5 { + change_stress_considering_cool(&ctx.trans, &mut ctx.item, 1000).await?; crit_fail_penalty_for_skill(&ctx.trans, ctx.item, &craft_data.skill).await?; ctx.trans .delete_item(&item.item_type, &item.item_code) @@ -320,6 +332,7 @@ impl QueueCommandHandler for FromQueueHandler { .await?; } } else if skill_result <= 0.0 { + change_stress_considering_cool(&ctx.trans, &mut ctx.item, 500).await?; if let Some((sess, _)) = session { ctx.trans .queue_for_session( diff --git a/blastmud_game/src/message_handler/user_commands/make.rs b/blastmud_game/src/message_handler/user_commands/make.rs index 409c94b..4885283 100644 --- a/blastmud_game/src/message_handler/user_commands/make.rs +++ b/blastmud_game/src/message_handler/user_commands/make.rs @@ -11,11 +11,13 @@ use crate::{ comms::broadcast_to_room, destroy_container, skills::{crit_fail_penalty_for_skill, skill_check_and_grind}, + urges::change_stress_considering_cool, }, static_content::possession_type::{ possession_data, recipe_craft_by_recipe, CraftData, PossessionType, }, }; +use ansi::ansi; use async_trait::async_trait; use std::time; use std::{collections::BTreeSet, sync::Arc}; @@ -37,6 +39,16 @@ impl QueueCommandHandler for QueueHandler { if ctx.item.death_data.is_some() { user_error("The dead aren't very good at making stuff.".to_owned())?; } + if ctx.item.urges.as_ref().map(|u| u.stress.value).unwrap_or(0) > 7000 { + user_error( + ansi!( + "You are too tired and stressed to consider crafts. Maybe try to \ + sit or recline for a bit!" + ) + .to_owned(), + )?; + } + let (bench_id_opt, instructions_id) = match ctx.command { QueueCommand::Make { ref bench_possession_id, @@ -296,6 +308,7 @@ impl QueueCommandHandler for QueueHandler { ctx.trans .delete_item(&item.item_type, &item.item_code) .await?; + change_stress_considering_cool(&ctx.trans, &mut ctx.item, 1000).await?; if let Some((sess, _)) = session { ctx.trans .queue_for_session( @@ -308,6 +321,7 @@ impl QueueCommandHandler for QueueHandler { .await?; } } else if skill_result <= 0.0 { + change_stress_considering_cool(&ctx.trans, &mut ctx.item, 500).await?; if let Some((sess, _)) = session { ctx.trans .queue_for_session( diff --git a/blastmud_game/src/message_handler/user_commands/movement.rs b/blastmud_game/src/message_handler/user_commands/movement.rs index e0de991..1b97d2c 100644 --- a/blastmud_game/src/message_handler/user_commands/movement.rs +++ b/blastmud_game/src/message_handler/user_commands/movement.rs @@ -660,6 +660,17 @@ impl QueueCommandHandler for QueueHandler { QueueCommand::Movement { direction, source } => (direction, source), _ => user_error("Unexpected command".to_owned())?, }; + + if ctx.item.urges.as_ref().map(|u| u.stress.value).unwrap_or(0) > 9500 { + user_error( + ansi!( + "You are so tired and stressed you can't move. Maybe try to \ + sit or recline for a bit!" + ) + .to_owned(), + )?; + } + let use_location = if ctx.item.death_data.is_some() { if ctx.item.item_type != "player" { user_error("Dead players don't move".to_owned())?; diff --git a/blastmud_game/src/services/combat.rs b/blastmud_game/src/services/combat.rs index 4fe61ff..0dec95a 100644 --- a/blastmud_game/src/services/combat.rs +++ b/blastmud_game/src/services/combat.rs @@ -15,7 +15,7 @@ use crate::{ comms::broadcast_to_room, destroy_container, skills::{calculate_total_stats_skills_for_user, skill_check_and_grind, skill_check_only}, - urges::recalculate_urge_growth, + urges::{change_stress_considering_cool, recalculate_urge_growth}, }, static_content::{ journals::{award_journal_if_needed, check_journal_for_kill}, @@ -132,6 +132,36 @@ async fn process_attack( attack: &WeaponAttackData, weapon: &WeaponData, ) -> DResult { + if attacker_item + .urges + .as_ref() + .map(|u| u.stress.value) + .unwrap_or(0) + > 8000 + { + let msg_exp = format!( + "{} looks like {} wanted to attack {}, but was too tired and stressed to do it.\n", + attacker_item.display_for_sentence(true, 1, false), + attacker_item.pronouns.subject, + victim_item.display_for_sentence(true, 1, true), + ); + let msg_nonexp = format!( + "{} looks like {} wanted to attack {}, but was too tired and stressed to do it.\n", + attacker_item.display_for_sentence(false, 1, false), + attacker_item.pronouns.subject, + victim_item.display_for_sentence(false, 1, true), + ); + broadcast_to_room( + ctx.trans, + &attacker_item.location, + None, + &msg_exp, + Some(&msg_nonexp), + ) + .await?; + return Ok(false); + } + let attack_skill = *attacker_item .total_skills .get(&weapon.uses_skill) @@ -148,6 +178,7 @@ async fn process_attack( } else { None }; + let attack_result = if let Some(user) = user_opt { let raw_skill = *user.raw_skills.get(&weapon.uses_skill).unwrap_or(&0.0); if raw_skill >= weapon.raw_min_to_learn && raw_skill <= weapon.raw_max_to_learn { @@ -165,6 +196,8 @@ async fn process_attack( skill_check_only(&attacker_item, &weapon.uses_skill, victim_dodge_skill) }; + change_stress_considering_cool(&ctx.trans, attacker_item, 100).await?; + if dodge_result > attack_result { let msg_exp = format!( "{} dodges out of the way of {}'s attack.\n", diff --git a/blastmud_game/src/services/urges.rs b/blastmud_game/src/services/urges.rs index 4de3709..8634ce0 100644 --- a/blastmud_game/src/services/urges.rs +++ b/blastmud_game/src/services/urges.rs @@ -345,6 +345,26 @@ pub async fn set_has_urges_if_needed(trans: &DBTrans, player_item: &mut Item) -> Ok(()) } +pub async fn change_stress_considering_cool( + trans: &DBTrans, + who: &mut Item, + max_magnitude: i64, +) -> DResult<()> { + let cool = who.total_stats.get(&StatType::Cool).unwrap_or(&8.0); + let stress_factor = 1.0 - 1.0 / (1.0 + (-0.7 * (cool - 8.0)).exp()); + match who.urges.as_mut() { + None => {} + Some(urges) => { + urges.stress.last_value = urges.stress.value; + urges.stress.value = (urges.stress.value as i64 + + (max_magnitude as f64 * stress_factor) as i64) + .max(0) + .min(10000) as u16; + } + } + stress_changed(trans, who).await +} + pub async fn recalculate_urge_growth(_trans: &DBTrans, item: &mut Item) -> DResult<()> { let cool = item.total_stats.get(&StatType::Cool).unwrap_or(&8.0); let relax_action_factor = match item.action_type {