diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index a7a2c72..3376097 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -1001,38 +1001,38 @@ impl DBTrans { if search.include_contents { ctes.push(format!("contents AS (\ - SELECT details, details->'aliases' AS aliases FROM items WHERE details->>'location' = ${}\ + SELECT item_id, details, details->'aliases' AS aliases FROM items WHERE details->>'location' = ${}\ )", param_no)); param_no += 1; params.push(&player_desig); - include_tables.push("SELECT details, aliases FROM contents"); + include_tables.push("SELECT item_id, details, aliases FROM contents"); } if search.include_loc_contents { ctes.push(format!("loc_contents AS (\ - SELECT details, details->'aliases' AS aliases FROM items WHERE details->>'location' = ${}\ + SELECT item_id, details, details->'aliases' AS aliases FROM items WHERE details->>'location' = ${}\ )", param_no)); #[allow(dropping_copy_types)] drop(param_no); // or increment if this is a problem. params.push(&player_loc); - include_tables.push("SELECT details, aliases FROM loc_contents"); + include_tables.push("SELECT item_id, details, aliases FROM loc_contents"); } if search.include_active_players { ctes.push( "active_players AS (\ - SELECT i.details, ('[]'::JSONB) AS aliases FROM items i \ + SELECT i.item_id, i.details, ('[]'::JSONB) AS aliases FROM items i \ JOIN users u ON u.username = i.details->>'item_code' \ WHERE i.details->>'item_type' = 'player' \ AND u.current_session IS NOT NULL \ )" .to_owned(), ); - include_tables.push("SELECT details, aliases FROM active_players"); + include_tables.push("SELECT item_id, details, aliases FROM active_players"); } if search.include_all_players { ctes.push("all_players AS (\ - SELECT details, ('[]'::JSONB) AS aliases FROM items WHERE details->>'item_type' = 'player' + SELECT item_id, details, ('[]'::JSONB) AS aliases FROM items WHERE details->>'item_type' = 'player' )".to_owned()); - include_tables.push("SELECT details, aliases FROM all_players"); + include_tables.push("SELECT item_id, details, aliases FROM all_players"); } ctes.push(format!( "relevant_items AS ({})", @@ -1050,7 +1050,7 @@ impl DBTrans { (lower(details->>'display') LIKE $1) \ OR EXISTS (SELECT 1 FROM jsonb_array_elements(aliases) AS al(alias) WHERE \ LOWER(alias#>>'{{}}') LIKE $1) {} \ - ORDER BY {} ABS(length(details->>'display')-$3) ASC \ + ORDER BY {} ABS(length(details->>'display')-$3) ASC, item_id ASC \ LIMIT $4 OFFSET $2", &cte_str, &extra_where, &extra_order ), diff --git a/blastmud_game/src/services/effect.rs b/blastmud_game/src/services/effect.rs index 1627caa..cccecd4 100644 --- a/blastmud_game/src/services/effect.rs +++ b/blastmud_game/src/services/effect.rs @@ -668,18 +668,6 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) ) }, - Effect::ChangeTargetParameter { - delay_secs: 10, - base_effect: -12, - skill_multiplier: 0.0, - max_effect: -12, - parameter: EffectParameter::Health, - message: Box::new(|target| - format!("{} howls out in pain from a sting", - target.display_for_sentence(1, false), - ) - ) - }, Effect::ChangeTargetParameter { delay_secs: 20, base_effect: -12, @@ -692,68 +680,56 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) ) }, - Effect::ChangeTargetParameter { - delay_secs: 30, - base_effect: -8, - skill_multiplier: 0.0, - max_effect: -12, - parameter: EffectParameter::Health, - message: Box::new(|target| - format!("{} yelps in pain from the sting", - target.display_for_sentence(1, false), - ) - ) - }, Effect::ChangeTargetParameter { delay_secs: 40, - base_effect: -8, + base_effect: -12, skill_multiplier: 0.0, max_effect: -12, parameter: EffectParameter::Health, message: Box::new(|target| - format!("{} yelps in pain from the sting", - target.display_for_sentence(1, false), - ) - ) - }, - Effect::ChangeTargetParameter { - delay_secs: 50, - base_effect: -8, - skill_multiplier: 0.0, - max_effect: -12, - parameter: EffectParameter::Health, - message: Box::new(|target| - format!("{} yelps in pain from the sting", + format!("{} howls out in pain from a sting", target.display_for_sentence(1, false), ) ) }, Effect::ChangeTargetParameter { delay_secs: 60, - base_effect: -6, + base_effect: -8, skill_multiplier: 0.0, - max_effect: -10, + max_effect: -12, parameter: EffectParameter::Health, message: Box::new(|target| - format!("{}'s cries as the sting really hurts", - target.display_for_sentence(1, false), - ) - ) - }, - Effect::ChangeTargetParameter { - delay_secs: 70, - base_effect: -6, - skill_multiplier: 0.0, - max_effect: -10, - parameter: EffectParameter::Health, - message: Box::new(|target| - format!("{}'s cries as the sting really hurts", + format!("{} yelps in pain from the sting", target.display_for_sentence(1, false), ) ) }, Effect::ChangeTargetParameter { delay_secs: 80, + base_effect: -8, + skill_multiplier: 0.0, + max_effect: -12, + parameter: EffectParameter::Health, + message: Box::new(|target| + format!("{} yelps in pain from the sting", + target.display_for_sentence(1, false), + ) + ) + }, + Effect::ChangeTargetParameter { + delay_secs: 100, + base_effect: -8, + skill_multiplier: 0.0, + max_effect: -12, + parameter: EffectParameter::Health, + message: Box::new(|target| + format!("{} yelps in pain from the sting", + target.display_for_sentence(1, false), + ) + ) + }, + Effect::ChangeTargetParameter { + delay_secs: 120, base_effect: -6, skill_multiplier: 0.0, max_effect: -10, @@ -765,7 +741,31 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) }, Effect::ChangeTargetParameter { - delay_secs: 90, + delay_secs: 140, + base_effect: -6, + skill_multiplier: 0.0, + max_effect: -10, + parameter: EffectParameter::Health, + message: Box::new(|target| + format!("{}'s cries as the sting really hurts", + target.display_for_sentence(1, false), + ) + ) + }, + Effect::ChangeTargetParameter { + delay_secs: 160, + base_effect: -6, + skill_multiplier: 0.0, + max_effect: -10, + parameter: EffectParameter::Health, + message: Box::new(|target| + format!("{}'s cries as the sting really hurts", + target.display_for_sentence(1, false), + ) + ) + }, + Effect::ChangeTargetParameter { + delay_secs: 170, base_effect: -4, skill_multiplier: 0.0, max_effect: -8, @@ -777,7 +777,7 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) }, Effect::ChangeTargetParameter { - delay_secs: 100, + delay_secs: 180, base_effect: -4, skill_multiplier: 0.0, max_effect: -8, @@ -789,7 +789,7 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) }, Effect::ChangeTargetParameter { - delay_secs: 110, + delay_secs: 190, base_effect: -4, skill_multiplier: 0.0, max_effect: -8, @@ -801,7 +801,7 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) }, Effect::ChangeTargetParameter { - delay_secs: 120, + delay_secs: 200, base_effect: -2, skill_multiplier: 0.0, max_effect: -8, @@ -813,7 +813,7 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) }, Effect::ChangeTargetParameter { - delay_secs: 130, + delay_secs: 220, base_effect: -2, skill_multiplier: 0.0, max_effect: -8, @@ -825,7 +825,7 @@ pub fn default_effects_for_type() -> &'static BTreeMap { ) }, Effect::ChangeTargetParameter { - delay_secs: 140, + delay_secs: 230, base_effect: -2, skill_multiplier: 0.0, max_effect: -8, diff --git a/blastmud_game/src/services/environment.rs b/blastmud_game/src/services/environment.rs index aca6d8b..ec74463 100644 --- a/blastmud_game/src/services/environment.rs +++ b/blastmud_game/src/services/environment.rs @@ -51,7 +51,7 @@ pub async fn ensure_appropriate_environment_handler_after_movement( MaterialType::WaterSurface | MaterialType::Underwater => true, _ => false, }; - let env_effects = room.environment.radiation > 0; + let env_effects = room.environment.radiation > 0 || room.environment.passive_health != 0; water_effects || env_effects }; @@ -126,7 +126,8 @@ impl TaskHandler for EffectEnvironmentHandler { }; let need_save = water_environment_effects(ctx, &room, &mut player).await? - || rad_environment_effects(ctx, &room, &mut player).await?; + || rad_environment_effects(ctx, &room, &mut player).await? + || passive_health_environment_effects(ctx, &room, &mut player).await?; if need_save { ctx.trans.save_item_model(&player).await?; @@ -306,6 +307,31 @@ pub async fn rad_environment_effects( Ok(true) } +pub async fn passive_health_environment_effects( + ctx: &mut TaskRunContext<'_>, + room: &Room, + player_item: &mut Item, +) -> DResult { + if room.environment.passive_health == 0 { + return Ok(false); + } + + let msg = format!( + "{} {}", + player_item.display_for_sentence(1, true), + room.environment.passive_health_message + ); + change_health( + ctx.trans, + room.environment.passive_health as i64, + player_item, + &msg, + ) + .await?; + + Ok(true) +} + pub static EFFECT_TASK_HANDLER: &'static (dyn TaskHandler + Sync + Send) = &EffectEnvironmentHandler; pub static CONSEQUENCE_TASK_HANDLER: &'static (dyn TaskHandler + Sync + Send) = diff --git a/blastmud_game/src/services/spawn.rs b/blastmud_game/src/services/spawn.rs index 84cc58e..d8c9d25 100644 --- a/blastmud_game/src/services/spawn.rs +++ b/blastmud_game/src/services/spawn.rs @@ -150,6 +150,18 @@ fn spawn_list() -> &'static BTreeMap<&'static str, SpawnDistribution> { )], }, ), + ( + "fixed_item/ronalds_health_room_fountain", + SpawnDistribution::SpawnOne { + pvec: vec![( + 1.0, + Box::new(SpawnDistribution::SpawnLiquid { + what: LiquidType::Water, + how_much: 1000000, + }), + )], + }, + ), ] .into_iter() .collect() diff --git a/blastmud_game/src/static_content/fixed_item.rs b/blastmud_game/src/static_content/fixed_item.rs index 4f7e0d4..fa87c7a 100644 --- a/blastmud_game/src/static_content/fixed_item.rs +++ b/blastmud_game/src/static_content/fixed_item.rs @@ -2,7 +2,7 @@ use super::{possession_type::PossessionData, StaticItem}; use crate::{ models::item::{Item, ItemStaticSpecialData, LocationActionType, Pronouns}, - static_content::room::{computer_museum, melbs, northern_radfields}, + static_content::room::{computer_museum, melbs, northern_radfields, ronalds_house}, }; use ansi::ansi; use once_cell::sync::OnceCell; @@ -64,6 +64,7 @@ fn fixed_item_list() -> &'static Vec { .chain(computer_museum::fixed_items().into_iter()) .chain(melbs::fixed_items().into_iter()) .chain(northern_radfields::fixed_items().into_iter()) + .chain(ronalds_house::fixed_items().into_iter()) .collect() }) } @@ -75,6 +76,8 @@ pub fn fixed_item_properties() -> &'static BTreeMap<&'static str, PossessionData .into_iter() .chain(computer_museum::fixed_item_properties().into_iter()) .chain(melbs::fixed_item_properties().into_iter()) + .chain(northern_radfields::fixed_item_properties().into_iter()) + .chain(ronalds_house::fixed_item_properties().into_iter()) .collect() }) } diff --git a/blastmud_game/src/static_content/room.rs b/blastmud_game/src/static_content/room.rs index 461f6ef..6f4c0f2 100644 --- a/blastmud_game/src/static_content/room.rs +++ b/blastmud_game/src/static_content/room.rs @@ -31,6 +31,7 @@ pub mod melbs; pub mod melbs_sewers; pub mod northern_radfields; mod repro_xv; +pub mod ronalds_house; mod special; pub struct Zone { @@ -91,13 +92,18 @@ pub fn zone_details() -> &'static BTreeMap<&'static str, Zone> { Zone { code: "northern_radfields", display: "Northern Radfields", - outdoors: false, + outdoors: true, }, Zone { code: "oorans", display: "OORANS", outdoors: false, }, + Zone { + code: "ronalds_house", + display: "Ronald's House", + outdoors: false, + }, ] .into_iter() .map(|x| (x.code, x)) @@ -581,6 +587,8 @@ impl Default for Room { pub struct RoomEnvironment { pub radiation: u64, // mSv/10s tick pub temperature: u16, // in 100ths of degrees celsius. + pub passive_health_message: String, + pub passive_health: i16, // in health points/10s tick. Can be negative to harm. } impl Default for RoomEnvironment { @@ -588,6 +596,8 @@ impl Default for RoomEnvironment { Self { radiation: 0, temperature: 2000, // 20 degrees celsius + passive_health_message: "feels healthy".to_owned(), + passive_health: 0, } } } @@ -711,6 +721,7 @@ pub fn room_list() -> &'static Vec { rooms.append(&mut general_hospital::room_list()); rooms.append(&mut melbs_sewers::room_list()); rooms.append(&mut northern_radfields::room_list()); + rooms.append(&mut ronalds_house::room_list()); rooms.into_iter().collect() }) } diff --git a/blastmud_game/src/static_content/room/northern_radfields.rs b/blastmud_game/src/static_content/room/northern_radfields.rs index ff452dc..b883100 100644 --- a/blastmud_game/src/static_content/room/northern_radfields.rs +++ b/blastmud_game/src/static_content/room/northern_radfields.rs @@ -1,4 +1,10 @@ -use crate::static_content::fixed_item::FixedItem; +use crate::{ + models::item::LiquidType, + static_content::{ + fixed_item::FixedItem, + possession_type::{LiquidContainerData, PossessionData}, + }, +}; use super::{Room, SimpleRoom}; use ansi::ansi; @@ -25,3 +31,17 @@ pub fn fixed_items() -> Vec { }, ] } + +pub fn fixed_item_properties() -> Vec<(&'static str, PossessionData)> { + vec![( + "northrad_oasis_billabong", + PossessionData { + liquid_container_data: Some(LiquidContainerData { + capacity: 5000000, // mL + allowed_contents: Some(vec![LiquidType::Water]), + ..Default::default() + }), + ..Default::default() + }, + )] +} diff --git a/blastmud_game/src/static_content/room/northern_radfields.yaml b/blastmud_game/src/static_content/room/northern_radfields.yaml index f164aa5..3b62a8a 100644 --- a/blastmud_game/src/static_content/room/northern_radfields.yaml +++ b/blastmud_game/src/static_content/room/northern_radfields.yaml @@ -295,10 +295,17 @@ your skin" x: 4 y: 7 z: 0 - description: A narrow rocky passage winds its way through the desert here, offering some shelter from the relentless sun and wind. It smells dusty here. To the south you can barely make out a building of some kind + description: A flat open structure, made of a large array of solar panels supported on ornately decorated carved stone pillars. The structure protects the entrance to what appears to be a well-maintained primarily subterranean dwelling. A staircase leading down into the ground appears to be the primary entrance. Outside the structure is a cobweb covered and clearly long-disused letterbox. On a sign hanging below the letterbox, and gentling clinking in the hot desert breeze, you can make out the words "Ronald Fairburn's Outback Abode. Trespass met with lethal force". Some additional words at the bottom of the sign have been painted over, but you can make out "Regional Praefect of His Majesty the Emperor" environment: radiation: 120 temperature: 4210 + secondary_zones: + - zone: ronalds_house + short: EX + grid_coords: + x: 0 + y: 0 + z: 1 exits: - direction: north - direction: northeast @@ -307,6 +314,8 @@ your skin" - direction: south - direction: southwest - direction: west + - direction: down + target: !Custom room/ronalds_entrance_hallway - zone: northern_radfields code: northrad_g5 name: Dust plain diff --git a/blastmud_game/src/static_content/room/ronalds_house.rs b/blastmud_game/src/static_content/room/ronalds_house.rs new file mode 100644 index 0000000..ad290c2 --- /dev/null +++ b/blastmud_game/src/static_content/room/ronalds_house.rs @@ -0,0 +1,62 @@ +use super::{Room, SimpleRoom}; +use crate::{ + models::item::{LiquidType, Scavtype}, + static_content::{ + fixed_item::FixedItem, + possession_type::{LiquidContainerData, PossessionData, PossessionType}, + scavtable::Scavinfo, + }, +}; +use ansi::ansi; +use serde_yaml::from_str as from_yaml_str; + +pub fn ronalds_house_scavtable() -> Vec { + vec![Scavinfo { + possession_type: PossessionType::RustySpike, + p_present: 1.0, + difficulty_mean: 7.0, + difficulty_stdev: 1.0, + scavtype: Scavtype::Scavenge, + }] +} + +pub fn fixed_items() -> Vec { + vec![ + FixedItem { + code: "ronalds_health_room_fountain".to_owned(), + name: "water fountain".to_owned(), + description: ansi!("A large round white stone carved fountain in the centre of the \ + room. Ornate carved seahorses eject jets of water which \ + recirculates into a pool of clear water around the outside \ + of the fountain. The air feels moist here from tiny droplets of water. \ + [Try drink from fountain or, if you have a suitable \ + container, fill container from fountain].").to_owned(), + location: "room/ronalds_health_room".to_owned(), + proper_noun: false, + aliases: vec!["fountain".to_owned()], + ..Default::default() + }, + ] +} + +pub fn fixed_item_properties() -> Vec<(&'static str, PossessionData)> { + vec![( + "ronalds_health_room_fountain", + PossessionData { + liquid_container_data: Some(LiquidContainerData { + capacity: 5000000, // mL + allowed_contents: Some(vec![LiquidType::Water]), + ..Default::default() + }), + ..Default::default() + }, + )] +} + +pub fn room_list() -> Vec { + from_yaml_str::>>(include_str!("ronalds_house.yaml")) + .unwrap() + .into_iter() + .map(|r| r.into()) + .collect() +} diff --git a/blastmud_game/src/static_content/room/ronalds_house.yaml b/blastmud_game/src/static_content/room/ronalds_house.yaml new file mode 100644 index 0000000..b4841f9 --- /dev/null +++ b/blastmud_game/src/static_content/room/ronalds_house.yaml @@ -0,0 +1,28 @@ +- zone: ronalds_house + code: ronalds_entrance_hallway + name: Ronald's Vestibule + description: An ornate entrance hall in Ronald's subterranean home. The air here is cool, despite the location in the desert. Artistically designed glass panels with colourful swirly shapes line the walls, and the floor is covered with marble tiles + short: VE + grid_coords: + x: 0 + y: 0 + z: 0 + exits: + - direction: up + target: !Custom room/northrad_g4 + - direction: north + repel_npc: true +- zone: ronalds_house + code: ronalds_health_room + name: Health Room + short: HR + grid_coords: + x: 0 + y: -1 + z: 0 + description: A large round room, the walls lined with fish tanks filled with brightly coloured fish slowly swimming around. The room has something of a serene feel. A sign indicates that this room has a field that activates nanites from the wristpad implant to heal + exits: + - direction: south + environment: + passive_health: 10 + passive_health_message: feels healthy diff --git a/blastmud_game/src/static_content/scavtable.rs b/blastmud_game/src/static_content/scavtable.rs index c37907c..6724a4d 100644 --- a/blastmud_game/src/static_content/scavtable.rs +++ b/blastmud_game/src/static_content/scavtable.rs @@ -1,4 +1,7 @@ -use crate::{models::item::Scavtype, static_content::room::melbs_sewers::sewer_scavtable}; +use crate::{ + models::item::Scavtype, + static_content::room::{melbs_sewers::sewer_scavtable, ronalds_house::ronalds_house_scavtable}, +}; use super::{possession_type::PossessionType, room::melbs::street_scavtable}; use std::collections::BTreeMap; @@ -19,6 +22,7 @@ pub enum ScavtableType { Nothing, CityStreet, CitySewer, + RonaldsHouse, } pub fn scavtable_map() -> &'static BTreeMap> { @@ -28,6 +32,7 @@ pub fn scavtable_map() -> &'static BTreeMap> { (ScavtableType::Nothing, vec![]), (ScavtableType::CityStreet, street_scavtable()), (ScavtableType::CitySewer, sewer_scavtable()), + (ScavtableType::RonaldsHouse, ronalds_house_scavtable()), ] .into_iter() .collect()