Implement radiation damage

This commit is contained in:
Condorra 2024-03-22 22:20:26 +11:00
parent 5a270b50dc
commit f37baf187e
9 changed files with 157 additions and 8 deletions

View File

@ -736,6 +736,7 @@ pub struct Item {
pub total_xp: u64, pub total_xp: u64,
pub urges: Option<Urges>, pub urges: Option<Urges>,
pub weight: u64, pub weight: u64,
pub raddamage: u64,
} }
impl Item { impl Item {
@ -834,6 +835,7 @@ impl Default for Item {
presence_target: None, presence_target: None,
pronouns: Pronouns::default_inanimate(), pronouns: Pronouns::default_inanimate(),
queue: VecDeque::new(), queue: VecDeque::new(),
raddamage: 0,
sex: None, sex: None,
special_data: None, special_data: None,
static_special_data: None, static_special_data: None,

View File

@ -80,10 +80,16 @@ pub enum TaskDetails {
ChargeItem { ChargeItem {
item: String, item: String,
}, },
// Environment impacting the player hidden variables
ApplyEnvironmentalEffects { ApplyEnvironmentalEffects {
on_player_type: String, on_player_type: String,
on_player_code: String, on_player_code: String,
}, },
// Player hidden variables from environment impacting health + themselves
ApplyEnvironmentalConsequences {
on_player_type: String,
on_player_code: String,
},
} }
impl TaskDetails { impl TaskDetails {
pub fn name(self: &Self) -> &'static str { pub fn name(self: &Self) -> &'static str {
@ -114,6 +120,7 @@ impl TaskDetails {
DischargeLight { .. } => "DischargeLight", DischargeLight { .. } => "DischargeLight",
ChargeItem { .. } => "ChargeItem", ChargeItem { .. } => "ChargeItem",
ApplyEnvironmentalEffects { .. } => "ApplyEnvironmentalEffects", ApplyEnvironmentalEffects { .. } => "ApplyEnvironmentalEffects",
ApplyEnvironmentalConsequences { .. } => "ApplyEnvironmentalConsequences",
// Don't forget to add to TASK_HANDLER_REGISTRY in regular_tasks.rs too. // Don't forget to add to TASK_HANDLER_REGISTRY in regular_tasks.rs too.
} }
} }

View File

@ -72,7 +72,14 @@ fn task_handler_registry(
("ExpireBuff", tempbuff::EXPIRE_BUFF_TASK), ("ExpireBuff", tempbuff::EXPIRE_BUFF_TASK),
("DischargeLight", lights::DISCHARGE_TASK), ("DischargeLight", lights::DISCHARGE_TASK),
("ChargeItem", charging::TASK_HANDLER), ("ChargeItem", charging::TASK_HANDLER),
("ApplyEnvironmentalEffects", environment::TASK_HANDLER), (
"ApplyEnvironmentalEffects",
environment::EFFECT_TASK_HANDLER,
),
(
"ApplyEnvironmentalConsequences",
environment::CONSEQUENCE_TASK_HANDLER,
),
] ]
.into_iter() .into_iter()
.collect() .collect()

View File

@ -761,6 +761,7 @@ pub async fn handle_resurrect(trans: &DBTrans, player: &mut Item) -> DResult<boo
if player.active_conversation.is_some() { if player.active_conversation.is_some() {
stop_conversation_mut(trans, player, "stops talking on account of being dead").await?; stop_conversation_mut(trans, player, "stops talking on account of being dead").await?;
} }
player.raddamage = 0;
player.active_effects = vec![]; player.active_effects = vec![];
calculate_total_stats_skills_for_user(player, &user); calculate_total_stats_skills_for_user(player, &user);
recalculate_urge_growth(trans, player).await?; recalculate_urge_growth(trans, player).await?;

View File

@ -23,7 +23,8 @@ use crate::{
use super::{combat::change_health, comms::broadcast_to_room, skills::skill_check_and_grind}; use super::{combat::change_health, comms::broadcast_to_room, skills::skill_check_and_grind};
pub struct EnvironmentHandler; pub struct EffectEnvironmentHandler;
pub struct ConsequenceEnvironmentHandler;
pub async fn ensure_appropriate_environment_handler_after_movement( pub async fn ensure_appropriate_environment_handler_after_movement(
ctx: &mut QueuedCommandContext<'_>, ctx: &mut QueuedCommandContext<'_>,
@ -42,10 +43,12 @@ pub async fn ensure_appropriate_environment_handler_after_movement(
None => return Ok(()), None => return Ok(()),
Some(r) => r, Some(r) => r,
}; };
match room.material_type { let water_effects = match room.material_type {
MaterialType::WaterSurface | MaterialType::Underwater => true, MaterialType::WaterSurface | MaterialType::Underwater => true,
_ => false, _ => false,
} };
let env_effects = room.environment.radiation > 0;
water_effects || env_effects
}; };
let existing_task = ctx let existing_task = ctx
@ -79,7 +82,7 @@ pub async fn ensure_appropriate_environment_handler_after_movement(
} }
#[async_trait] #[async_trait]
impl TaskHandler for EnvironmentHandler { impl TaskHandler for EffectEnvironmentHandler {
async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> { async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> {
let (player_type, player_code) = match &ctx.task.details { let (player_type, player_code) = match &ctx.task.details {
TaskDetails::ApplyEnvironmentalEffects { TaskDetails::ApplyEnvironmentalEffects {
@ -118,7 +121,8 @@ impl TaskHandler for EnvironmentHandler {
Some(r) => r, Some(r) => r,
}; };
let need_save = water_environment_effects(ctx, &room, &mut player).await?; let need_save = water_environment_effects(ctx, &room, &mut player).await?
|| rad_environment_effects(ctx, &room, &mut player).await?;
if need_save { if need_save {
ctx.trans.save_item_model(&player).await?; ctx.trans.save_item_model(&player).await?;
@ -128,6 +132,56 @@ impl TaskHandler for EnvironmentHandler {
} }
} }
#[async_trait]
impl TaskHandler for ConsequenceEnvironmentHandler {
async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> {
let (player_type, player_code) = match &ctx.task.details {
TaskDetails::ApplyEnvironmentalConsequences {
on_player_type,
on_player_code,
} => (on_player_type, on_player_code),
x => {
warn!(
"ConsequenceEnvironmentHandler called with bad TaskDetail type: {:#?}",
x
);
return Ok(None);
}
};
let player = match ctx
.trans
.find_item_by_type_code(&player_type, &player_code)
.await?
{
None => return Ok(None),
Some(p) => p,
};
let mut player = (*player).clone();
let mut anything_left = false;
if player.raddamage > 0 {
if player.raddamage <= 100 {
player.raddamage = 0;
} else {
anything_left = true;
if player.raddamage > 2000 {
let damage = (player.raddamage - 1000) / 1000;
let msg = format!("{} feels unwell", &player.display_for_sentence(1, true));
change_health(ctx.trans, -(damage as i64), &mut player, &msg).await?;
}
player.raddamage -= 100;
}
}
ctx.trans.save_item_model(&player).await?;
Ok(if anything_left {
Some(time::Duration::from_secs(60))
} else {
None
})
}
}
pub async fn water_environment_effects( pub async fn water_environment_effects(
ctx: &mut TaskRunContext<'_>, ctx: &mut TaskRunContext<'_>,
room: &Room, room: &Room,
@ -194,4 +248,40 @@ pub async fn water_environment_effects(
Ok(true) Ok(true)
} }
pub static TASK_HANDLER: &'static (dyn TaskHandler + Sync + Send) = &EnvironmentHandler; pub async fn rad_environment_effects(
ctx: &mut TaskRunContext<'_>,
room: &Room,
player_item: &mut Item,
) -> DResult<bool> {
if room.environment.radiation == 0 {
return Ok(false);
}
player_item.raddamage += room.environment.radiation;
let existing_task = ctx
.trans
.fetch_specific_task("ApplyEnvironmentalConsequences", &player_item.refstr())
.await?;
if existing_task.is_none() {
ctx.trans
.upsert_task(&Task {
meta: TaskMeta {
task_code: player_item.refstr(),
next_scheduled: Utc::now() + chrono::TimeDelta::try_seconds(60).unwrap(),
..Default::default()
},
details: TaskDetails::ApplyEnvironmentalConsequences {
on_player_type: player_item.item_type.clone(),
on_player_code: player_item.item_code.clone(),
},
})
.await?;
}
Ok(true)
}
pub static EFFECT_TASK_HANDLER: &'static (dyn TaskHandler + Sync + Send) =
&EffectEnvironmentHandler;
pub static CONSEQUENCE_TASK_HANDLER: &'static (dyn TaskHandler + Sync + Send) =
&ConsequenceEnvironmentHandler;

View File

@ -51,6 +51,7 @@ fn room_to_simpleroom(room: &Room) -> Option<SimpleRoom<()>> {
scavtable: room.scavtable.clone(), scavtable: room.scavtable.clone(),
scan_code: room.scan_code.clone(), scan_code: room.scan_code.clone(),
effects: None, effects: None,
environment: room.environment.clone(),
extra: (), extra: (),
}) })
} }

View File

@ -542,6 +542,7 @@ pub struct Room {
pub exit_trigger: Option<Box<dyn RoomExitTrigger + Sync + Send>>, pub exit_trigger: Option<Box<dyn RoomExitTrigger + Sync + Send>>,
pub sell_trigger: Option<Box<dyn RoomSellTrigger + Sync + Send>>, pub sell_trigger: Option<Box<dyn RoomSellTrigger + Sync + Send>>,
pub scavtable: ScavtableType, pub scavtable: ScavtableType,
pub environment: RoomEnvironment,
} }
impl Default for Room { impl Default for Room {
@ -570,10 +571,23 @@ impl Default for Room {
exit_trigger: None, exit_trigger: None,
sell_trigger: None, sell_trigger: None,
scavtable: ScavtableType::Nothing, scavtable: ScavtableType::Nothing,
environment: Default::default(),
} }
} }
} }
#[derive(Serialize, Deserialize, Clone)]
#[serde(default)]
pub struct RoomEnvironment {
pub radiation: u64, // mSv/10s tick
}
impl Default for RoomEnvironment {
fn default() -> Self {
Self { radiation: 0 }
}
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct SimpleRoom<T> { pub struct SimpleRoom<T> {
@ -601,6 +615,7 @@ pub struct SimpleRoom<T> {
pub journal: Option<JournalType>, pub journal: Option<JournalType>,
pub scavtable: ScavtableType, pub scavtable: ScavtableType,
pub effects: Option<Vec<SimpleEffect>>, pub effects: Option<Vec<SimpleEffect>>,
pub environment: RoomEnvironment,
pub extra: T, pub extra: T,
} }
@ -645,6 +660,7 @@ impl<T> Into<Room> for SimpleRoom<T> {
}), }),
sell_trigger: None, sell_trigger: None,
scavtable: self.scavtable, scavtable: self.scavtable,
environment: self.environment,
} }
} }
} }
@ -674,6 +690,7 @@ impl<'a, T: Default> Default for SimpleRoom<T> {
scavtable: ScavtableType::Nothing, scavtable: ScavtableType::Nothing,
effects: None, effects: None,
extra: Default::default(), extra: Default::default(),
environment: Default::default(),
} }
} }
} }

View File

@ -1682,6 +1682,21 @@
stock_list: stock_list:
- possession_type: !RadSafetyTest - possession_type: !RadSafetyTest
list_price: 1000 list_price: 1000
- zone: oorans
code: oorans_gift
name: OORANS Gift Shop
description: |-
A brightly coloured room, each wall a different primary colour. Rows of merchandise hang neatly on racks, while a shop keeper stands near the front, his hands clasped in anticipation of a sale
short: <bgred><green>G$<reset>
grid_coords:
x: 1
y: 1
z: 0
exits:
- direction: north
stock_list:
- possession_type: !RadSafetyTest
list_price: 1000
- zone: melbs - zone: melbs
code: melbs_williamsst_collinsst code: melbs_williamsst_collinsst
name: Williams St & Collins St name: Williams St & Collins St

View File

@ -34,6 +34,8 @@
exits: exits:
- direction: north - direction: north
- direction: south - direction: south
environment:
radiation: 50
- zone: northern_radfields - zone: northern_radfields
code: northrad_r6 code: northrad_r6
name: Outside the abandoned windfarm name: Outside the abandoned windfarm
@ -46,6 +48,8 @@
exits: exits:
- direction: north - direction: north
- direction: south - direction: south
environment:
radiation: 150
- zone: northern_radfields - zone: northern_radfields
code: northrad_q6 code: northrad_q6
name: Crystal clear pond name: Crystal clear pond
@ -58,6 +62,8 @@
exits: exits:
- direction: northwest - direction: northwest
- direction: south - direction: south
environment:
radiation: 300
- zone: northern_radfields - zone: northern_radfields
code: northrad_p5 code: northrad_p5
name: The Bend Community Hall name: The Bend Community Hall
@ -70,6 +76,8 @@
exits: exits:
- direction: north - direction: north
- direction: southeast - direction: southeast
environment:
radiation: 205
- zone: northern_radfields - zone: northern_radfields
code: northrad_o5 code: northrad_o5
name: Gorge Southbank name: Gorge Southbank
@ -85,6 +93,8 @@
height: -10 height: -10
difficulty: 10 difficulty: 10
- direction: south - direction: south
environment:
radiation: 150
- zone: northern_radfields - zone: northern_radfields
code: northrad_n5 code: northrad_n5
name: Gorge River name: Gorge River
@ -113,4 +123,3 @@
material_type: !Underwater material_type: !Underwater
exits: exits:
- direction: up - direction: up