diff --git a/blastmud_game/src/message_handler/user_commands/attack.rs b/blastmud_game/src/message_handler/user_commands/attack.rs index 1efa5ed9..f919aa75 100644 --- a/blastmud_game/src/message_handler/user_commands/attack.rs +++ b/blastmud_game/src/message_handler/user_commands/attack.rs @@ -20,7 +20,7 @@ impl UserVerb for Verb { async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("It doesn't really seem fair, but you realise you won't be able to attack anyone while you're dead!".to_string())?; } @@ -56,7 +56,7 @@ impl UserVerb for Verb { user_error(ansi!("Your wristpad vibrates and blocks you from doing that. You get a feeling that while the empire might be gone, the system to stop subjects with working wristpads from fighting each unless they have an consented is very much functional. [Try help allow]").to_string())? } - if attack_whom.is_dead { + if attack_whom.death_data.is_some() { user_error("There's no point attacking the dead!".to_string())? } diff --git a/blastmud_game/src/message_handler/user_commands/buy.rs b/blastmud_game/src/message_handler/user_commands/buy.rs index 6fde8714..e8146dc4 100644 --- a/blastmud_game/src/message_handler/user_commands/buy.rs +++ b/blastmud_game/src/message_handler/user_commands/buy.rs @@ -18,7 +18,7 @@ impl UserVerb for Verb { async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Nobody seems to listen when you try to buy... possibly because you're dead.".to_owned())? } let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen")); diff --git a/blastmud_game/src/message_handler/user_commands/drop.rs b/blastmud_game/src/message_handler/user_commands/drop.rs index 634aacfc..09f9be7f 100644 --- a/blastmud_game/src/message_handler/user_commands/drop.rs +++ b/blastmud_game/src/message_handler/user_commands/drop.rs @@ -119,7 +119,7 @@ impl QueueCommandHandler for QueueHandler { async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?; } let item_id = match command { @@ -151,7 +151,7 @@ impl QueueCommandHandler for QueueHandler { async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?; } let item_id = match command { @@ -219,7 +219,7 @@ impl UserVerb for Verb { ..ItemSearchParams::base(&player_item, &remaining) }).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?; } diff --git a/blastmud_game/src/message_handler/user_commands/get.rs b/blastmud_game/src/message_handler/user_commands/get.rs index c8383d78..87247525 100644 --- a/blastmud_game/src/message_handler/user_commands/get.rs +++ b/blastmud_game/src/message_handler/user_commands/get.rs @@ -34,7 +34,7 @@ impl QueueCommandHandler for QueueHandler { async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?; } let item_id = match command { @@ -66,7 +66,7 @@ impl QueueCommandHandler for QueueHandler { async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?; } let item_id = match command { @@ -133,7 +133,7 @@ impl UserVerb for Verb { limit: get_limit.unwrap_or(100), ..ItemSearchParams::base(&player_item, &remaining) }).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?; } diff --git a/blastmud_game/src/message_handler/user_commands/install.rs b/blastmud_game/src/message_handler/user_commands/install.rs index a2c5b966..7c8b75e7 100644 --- a/blastmud_game/src/message_handler/user_commands/install.rs +++ b/blastmud_game/src/message_handler/user_commands/install.rs @@ -21,7 +21,7 @@ impl UserVerb for Verb { Some(v) => v }; let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Apparently, you have to be alive to work as an installer.\ So discriminatory!".to_owned())?; } diff --git a/blastmud_game/src/message_handler/user_commands/inventory.rs b/blastmud_game/src/message_handler/user_commands/inventory.rs index a97cead6..887c0490 100644 --- a/blastmud_game/src/message_handler/user_commands/inventory.rs +++ b/blastmud_game/src/message_handler/user_commands/inventory.rs @@ -19,7 +19,7 @@ pub struct Verb; impl UserVerb for Verb { async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { ctx.trans.queue_for_session(ctx.session, Some("The dead don't really have an inventory.\n")).await?; } let inv = ctx.trans.find_items_by_location(&format!("{}/{}", diff --git a/blastmud_game/src/message_handler/user_commands/list.rs b/blastmud_game/src/message_handler/user_commands/list.rs index 7f162058..af3bd198 100644 --- a/blastmud_game/src/message_handler/user_commands/list.rs +++ b/blastmud_game/src/message_handler/user_commands/list.rs @@ -14,7 +14,7 @@ impl UserVerb for Verb { async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Nobody seems to offer you any prices... possibly because you're dead.".to_owned())? } let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen")); diff --git a/blastmud_game/src/message_handler/user_commands/look.rs b/blastmud_game/src/message_handler/user_commands/look.rs index c3e8abf8..826a263f 100644 --- a/blastmud_game/src/message_handler/user_commands/look.rs +++ b/blastmud_game/src/message_handler/user_commands/look.rs @@ -233,7 +233,7 @@ async fn list_room_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> URe LocationActionType::Sitting => buf.push_str("sitting "), LocationActionType::Reclining => buf.push_str("reclining "), LocationActionType::Normal | LocationActionType::Attacking(_) if is_creature => { - if head.is_dead { + if head.death_data.is_some() { buf.push_str("lying "); } else { buf.push_str("standing "); @@ -343,7 +343,7 @@ impl UserVerb for Verb { let player_item = get_player_item_or_fail(ctx).await?; let rem_trim = remaining.trim().to_lowercase(); - let use_location = if player_item.is_dead { "room/repro_xv_respawn" } else { + let use_location = if player_item.death_data.is_some() { "room/repro_xv_respawn" } else { &player_item.location }; let (heretype, herecode) = use_location.split_once("/").unwrap_or(("room", "repro_xv_chargen")); diff --git a/blastmud_game/src/message_handler/user_commands/map.rs b/blastmud_game/src/message_handler/user_commands/map.rs index 1b029122..a751e2e4 100644 --- a/blastmud_game/src/message_handler/user_commands/map.rs +++ b/blastmud_game/src/message_handler/user_commands/map.rs @@ -393,7 +393,7 @@ impl MapType for GmapType { room: &room::Room) -> UResult<()> { ctx.trans.queue_for_session( ctx.session, - Some(&render_map(room, 16, 9)) + Some(&render_map(room, 32, 18)) ).await?; Ok(()) } diff --git a/blastmud_game/src/message_handler/user_commands/movement.rs b/blastmud_game/src/message_handler/user_commands/movement.rs index 04961e64..c0613cad 100644 --- a/blastmud_game/src/message_handler/user_commands/movement.rs +++ b/blastmud_game/src/message_handler/user_commands/movement.rs @@ -181,7 +181,7 @@ pub async fn attempt_move_immediate( // for the orig_mover's queue, because might re-queue a move command. mut player_ctx: &mut Option<&mut VerbContext<'_>> ) -> UResult<()> { - let use_location = if orig_mover.is_dead { + let use_location = if orig_mover.death_data.is_some() { if orig_mover.item_type != "player" { user_error("Dead players don't move".to_owned())?; } @@ -268,7 +268,7 @@ pub async fn attempt_move_immediate( } } - if mover.is_dead { + if mover.death_data.is_some() { if !handle_resurrect(trans, &mut mover).await? { user_error("You couldn't be resurrected.".to_string())?; } diff --git a/blastmud_game/src/message_handler/user_commands/open.rs b/blastmud_game/src/message_handler/user_commands/open.rs index f9436176..167a0753 100644 --- a/blastmud_game/src/message_handler/user_commands/open.rs +++ b/blastmud_game/src/message_handler/user_commands/open.rs @@ -75,7 +75,7 @@ impl TaskHandler for SwingShutHandler { pub async fn attempt_open_immediate(trans: &DBTrans, ctx_opt: &mut Option<&mut VerbContext<'_>>, who: &Item, direction: &Direction) -> UResult<()> { - if who.is_dead { + if who.death_data.is_some() { user_error("Your ethereal hands don't seem to be able to move the door.".to_owned())?; } let (room_1, dir_in_room, room_2) = match is_door_in_direction(trans, &direction, &who).await? { diff --git a/blastmud_game/src/message_handler/user_commands/page.rs b/blastmud_game/src/message_handler/user_commands/page.rs index 048f526a..49cab40d 100644 --- a/blastmud_game/src/message_handler/user_commands/page.rs +++ b/blastmud_game/src/message_handler/user_commands/page.rs @@ -25,7 +25,7 @@ impl UserVerb for Verb { user_error("You need to provide a message to send.".to_owned())?; } let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Shush, the dead can't talk!".to_string())?; } let to_whom = search_item_for_user(ctx, &ItemSearchParams { diff --git a/blastmud_game/src/message_handler/user_commands/say.rs b/blastmud_game/src/message_handler/user_commands/say.rs index 868e26f9..32ac62ea 100644 --- a/blastmud_game/src/message_handler/user_commands/say.rs +++ b/blastmud_game/src/message_handler/user_commands/say.rs @@ -55,7 +55,7 @@ impl UserVerb for Verb { user_error("You need to provide a message to send.".to_owned())?; } let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Shush, the dead can't talk!".to_string())?; } say_to_room(ctx.trans, &player_item, &player_item.location, diff --git a/blastmud_game/src/message_handler/user_commands/uninstall.rs b/blastmud_game/src/message_handler/user_commands/uninstall.rs index a7669f6b..ed1a94e4 100644 --- a/blastmud_game/src/message_handler/user_commands/uninstall.rs +++ b/blastmud_game/src/message_handler/user_commands/uninstall.rs @@ -21,7 +21,7 @@ impl UserVerb for Verb { Some(v) => v }; let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Apparently, you have to be alive to work as an uninstaller. \ So discriminatory!".to_owned())?; } diff --git a/blastmud_game/src/message_handler/user_commands/use_cmd.rs b/blastmud_game/src/message_handler/user_commands/use_cmd.rs index b4048a54..eef13263 100644 --- a/blastmud_game/src/message_handler/user_commands/use_cmd.rs +++ b/blastmud_game/src/message_handler/user_commands/use_cmd.rs @@ -38,7 +38,7 @@ impl QueueCommandHandler for QueueHandler { async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?; } let (item_id, target_type_code) = match command { @@ -122,7 +122,7 @@ impl QueueCommandHandler for QueueHandler { async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?; } @@ -260,7 +260,7 @@ pub struct Verb; impl UserVerb for Verb { async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?; } diff --git a/blastmud_game/src/message_handler/user_commands/whisper.rs b/blastmud_game/src/message_handler/user_commands/whisper.rs index e0a71e0a..ba809236 100644 --- a/blastmud_game/src/message_handler/user_commands/whisper.rs +++ b/blastmud_game/src/message_handler/user_commands/whisper.rs @@ -17,7 +17,7 @@ impl UserVerb for Verb { user_error("You need to provide a message to send.".to_owned())?; } let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("Shush, the dead can't talk!".to_string())?; } let to_whom = search_item_for_user(ctx, &ItemSearchParams { diff --git a/blastmud_game/src/message_handler/user_commands/wield.rs b/blastmud_game/src/message_handler/user_commands/wield.rs index 85bfd7b1..a9c34bb6 100644 --- a/blastmud_game/src/message_handler/user_commands/wield.rs +++ b/blastmud_game/src/message_handler/user_commands/wield.rs @@ -33,7 +33,7 @@ impl QueueCommandHandler for QueueHandler { async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?; } let item_id = match command { @@ -80,7 +80,7 @@ impl QueueCommandHandler for QueueHandler { async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult<()> { let player_item = get_player_item_or_fail(ctx).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?; } let item_id = match command { @@ -118,7 +118,7 @@ impl UserVerb for Verb { limit: 1, ..ItemSearchParams::base(&player_item, &remaining) }).await?; - if player_item.is_dead { + if player_item.death_data.is_some() { user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?; } if weapon.action_type == LocationActionType::Wielded { diff --git a/blastmud_game/src/models/item.rs b/blastmud_game/src/models/item.rs index 5b0cc3a5..3c430d86 100644 --- a/blastmud_game/src/models/item.rs +++ b/blastmud_game/src/models/item.rs @@ -342,6 +342,20 @@ impl Default for DoorState { } } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] +#[serde(default)] +pub struct DeathData { + pub parts_remaining: Vec +} + +impl Default for DeathData { + fn default() -> Self { + Self { + parts_remaining: vec!() + } + } +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] #[serde(default)] pub struct Item { @@ -357,7 +371,7 @@ pub struct Item { pub action_type: LocationActionType, pub presence_target: Option, // e.g. what are they sitting on. pub is_static: bool, - pub is_dead: bool, + pub death_data: Option, pub species: SpeciesType, pub health: u64, pub total_xp: u64, @@ -373,13 +387,13 @@ pub struct Item { pub special_data: Option, pub dynamic_entrance: Option, pub owner: Option, - pub door_states: Option> + pub door_states: Option>, } impl Item { pub fn display_for_sentence(&self, explicit_ok: bool, pluralise: usize, caps: bool) -> String { let mut buf = String::new(); - if self.is_dead { + if self.death_data.is_some() { if pluralise > 1 { buf.push_str("the bodies of "); } else { @@ -441,7 +455,7 @@ impl Default for Item { action_type: LocationActionType::Normal, presence_target: None, is_static: false, - is_dead: false, + death_data: None, species: SpeciesType::Human, health: 24, total_xp: 0, diff --git a/blastmud_game/src/services/combat.rs b/blastmud_game/src/services/combat.rs index 28ee61f9..18cad4cd 100644 --- a/blastmud_game/src/services/combat.rs +++ b/blastmud_game/src/services/combat.rs @@ -5,12 +5,13 @@ use crate::{ skills::skill_check_only, }, models::{ - item::{Item, LocationActionType, Subattack, SkillType}, - task::{Task, TaskMeta, TaskDetails} + item::{Item, LocationActionType, Subattack, SkillType, DeathData}, + task::{Task, TaskMeta, TaskDetails}, }, static_content::{ possession_type::{WeaponData, possession_data, fist}, npc::npc_by_code, + species::species_info_map, }, message_handler::user_commands::{user_error, UResult, drop::consider_expire_job_for_item}, regular_tasks::{TaskRunContext, TaskHandler}, @@ -48,7 +49,7 @@ impl TaskHandler for AttackTaskHandler { Some(item) => (*item).clone() }; - if attacker_item.is_dead || victim_item.is_dead { + if attacker_item.death_data.is_some() || victim_item.death_data.is_some() { return Ok(None) } @@ -210,7 +211,11 @@ pub async fn handle_death(trans: &DBTrans, whom: &mut Item) -> DResult<()> { ); broadcast_to_room(trans, &whom.location, None, &msg_exp, Some(&msg_nonexp)).await?; - whom.is_dead = true; + whom.death_data = Some(DeathData { + parts_remaining: species_info_map().get(&whom.species) + .map(|sp| sp.corpse_butchers_into.clone()).unwrap_or_else(|| vec!()), + ..Default::default() + }); if let Some(ac) = &whom.active_combat { let at_str = ac.attacking.clone(); for attacker in ac.attacked_by.clone().iter() { @@ -250,7 +255,7 @@ pub async fn handle_death(trans: &DBTrans, whom: &mut Item) -> DResult<()> { pub async fn handle_resurrect(trans: &DBTrans, player: &mut Item) -> DResult { corpsify_item(trans, &player).await?; - player.is_dead = false; + player.death_data = None; let lost_xp = (player.total_xp / 200).max(10).min(player.total_xp); let (session, _) = match trans.find_session_for_player(&player.item_code).await? { None => return Ok(false), @@ -476,13 +481,13 @@ impl TaskHandler for NPCRecloneTaskHandler { Some(r) => r }; - if !npc_item.is_dead { + if npc_item.death_data.is_none() { return Ok(None); } corpsify_item(ctx.trans, &npc_item).await?; - npc_item.is_dead = false; + npc_item.death_data = None; npc_item.health = max_health(&npc_item); npc_item.location = npc.spawn_location.to_owned(); ctx.trans.save_item_model(&npc_item).await?; diff --git a/blastmud_game/src/services/comms.rs b/blastmud_game/src/services/comms.rs index cb020dfb..67a0286b 100644 --- a/blastmud_game/src/services/comms.rs +++ b/blastmud_game/src/services/comms.rs @@ -8,7 +8,7 @@ use mockall_double::double; pub async fn broadcast_to_room(trans: &DBTrans, location: &str, from_item: Option<&Item>, message_explicit_ok: &str, message_nonexplicit: Option<&str>) -> DResult<()> { for item in trans.find_items_by_location(location).await? { - if item.item_type != "player" || item.is_dead { + if item.item_type != "player" || item.death_data.is_some() { continue; } if let Some((session, session_dat)) = trans.find_session_for_player(&item.item_code).await? { diff --git a/blastmud_game/src/services/effect.rs b/blastmud_game/src/services/effect.rs index 276b924a..6a0d6e03 100644 --- a/blastmud_game/src/services/effect.rs +++ b/blastmud_game/src/services/effect.rs @@ -59,7 +59,7 @@ impl TaskHandler for DelayedHealthTaskHandler { } Some(it) => it }; - if item.is_dead { + if item.death_data.is_some() { return Ok(None); } match item_effect_series.1.pop_front() { diff --git a/blastmud_game/src/static_content/npc.rs b/blastmud_game/src/static_content/npc.rs index 39e92548..78e6db68 100644 --- a/blastmud_game/src/static_content/npc.rs +++ b/blastmud_game/src/static_content/npc.rs @@ -270,7 +270,7 @@ impl TaskHandler for NPCSayTaskHandler { Some(r) => r }; - if npc_item.is_dead { + if npc_item.death_data.is_none() { return Ok(None); } @@ -323,7 +323,7 @@ impl TaskHandler for NPCWanderTaskHandler { }, Some(r) => r }; - if item.is_dead { + if item.death_data.is_some() { return Ok(None) } let (ltype, lcode) = match item.location.split_once("/") { @@ -379,14 +379,14 @@ impl TaskHandler for NPCAggroTaskHandler { }, Some(r) => r }; - if item.is_dead || item.active_combat.as_ref().map(|ac| ac.attacking.is_some()).unwrap_or(false) { + if item.death_data.is_some() || item.active_combat.as_ref().map(|ac| ac.attacking.is_some()).unwrap_or(false) { return Ok(None); } let items_loc = ctx.trans.find_items_by_location(&item.location).await?; let vic_opt = items_loc .iter() .filter(|it| (it.item_type == "player" || it.item_type == "npc") && - !it.is_dead && (it.item_type != item.item_type || it.item_code != item.item_code)) + it.death_data.is_none() && (it.item_type != item.item_type || it.item_code != item.item_code)) .choose(&mut thread_rng()); if let Some(victim) = vic_opt { match start_attack(ctx.trans, &item, victim).await { @@ -418,13 +418,13 @@ impl TaskHandler for NPCRecloneTaskHandler { Some(r) => r }; - if !npc_item.is_dead { + if npc_item.death_data.is_none() { return Ok(None); } corpsify_item(ctx.trans, &npc_item).await?; - npc_item.is_dead = false; + npc_item.death_data = None; npc_item.health = npc.max_health; npc_item.location = npc.spawn_location.to_owned(); ctx.trans.save_item_model(&npc_item).await?; diff --git a/blastmud_game/src/static_content/possession_type.rs b/blastmud_game/src/static_content/possession_type.rs index 96985fc1..13cfa198 100644 --- a/blastmud_game/src/static_content/possession_type.rs +++ b/blastmud_game/src/static_content/possession_type.rs @@ -13,9 +13,11 @@ use async_trait::async_trait; mod fangs; mod antenna_whip; +mod blade; mod trauma_kit; mod corp_licence; mod lock; +mod meat; pub type AttackMessageChoice = Vec String + 'static + Sync + Send>>; pub type AttackMessageChoicePart = Vec String + 'static + Sync + Send>>; @@ -145,6 +147,7 @@ pub struct PossessionData { pub lockcheck_handler: Option<&'static (dyn ArglessHandler + Sync + Send)>, pub sign_handler: Option<&'static (dyn ArglessHandler + Sync + Send)>, pub write_handler: Option<&'static (dyn WriteHandler + Sync + Send)>, + pub can_butcher: bool, } impl Default for PossessionData { @@ -165,6 +168,7 @@ impl Default for PossessionData { lockcheck_handler: None, sign_handler: None, write_handler: None, + can_butcher: false, } } } @@ -203,6 +207,10 @@ pub enum PossessionType { NewCorpLicence, CertificateOfIncorporation, Scanlock, + ButcherKnife, + Steak, + AnimalSkin, + SeveredHead, } impl Into for PossessionType { @@ -266,11 +274,15 @@ pub fn possession_data() -> &'static BTreeMap { vec!( (Fangs, fangs::data()), (AntennaWhip, antenna_whip::data()), + (ButcherKnife, blade::butcher_data()), (MediumTraumaKit, trauma_kit::medium_data()), (EmptyMedicalBox, trauma_kit::empty_data()), (NewCorpLicence, corp_licence::data()), (CertificateOfIncorporation, corp_licence::cert_data()), (Scanlock, lock::scan()), + (Steak, meat::steak_data()), + (AnimalSkin, meat::skin_data()), + (SeveredHead, meat::severed_head_data()), ).into_iter().collect() }) } diff --git a/blastmud_game/src/static_content/possession_type/blade.rs b/blastmud_game/src/static_content/possession_type/blade.rs new file mode 100644 index 00000000..1697f365 --- /dev/null +++ b/blastmud_game/src/static_content/possession_type/blade.rs @@ -0,0 +1,38 @@ +use super::{PossessionData, WeaponData}; +use crate::models::item::SkillType; + +pub fn butcher_data() -> PossessionData { + PossessionData { + display: "butcher knife", + details: "A 30 cm long stainless steel blade, sharp on one edge with a pointy tip. It looks perfect for butchering things, and in a pinch you could probably fight with it too.", + aliases: vec!("butcher", "knife"), + weight: 250, + weapon_data: Some(WeaponData { + uses_skill: SkillType::Blades, + raw_min_to_learn: 0.0, + raw_max_to_learn: 2.0, + normal_attack_start_messages: vec!( + Box::new(|attacker, victim, exp| + format!("{} raises {} butcher knife menancingly, preparing to attack {}", + &attacker.display_for_sentence(exp, 1, true), + &attacker.pronouns.possessive, + &victim.display_for_sentence(exp, 1, false), + ) + ) + ), + normal_attack_success_messages: vec!( + Box::new(|attacker, victim, part, exp| + format!("{}'s butcher knife cuts into {}'s {}", + &attacker.display_for_sentence(exp, 1, true), + &victim.display_for_sentence(exp, 1, false), + &part.display(victim.sex.clone()) + ) + ) + ), + normal_attack_mean_damage: 2.0, + normal_attack_stdev_damage: 2.0, + ..Default::default() + }), + ..Default::default() + } +} diff --git a/blastmud_game/src/static_content/possession_type/meat.rs b/blastmud_game/src/static_content/possession_type/meat.rs new file mode 100644 index 00000000..46784f62 --- /dev/null +++ b/blastmud_game/src/static_content/possession_type/meat.rs @@ -0,0 +1,28 @@ +use super::PossessionData; + +pub fn skin_data() -> PossessionData { + PossessionData { + display: "animal skin", + details: "The skin of an animal of some kind. It looks like you could make something out of this", + weight: 100, + ..Default::default() + } +} + +pub fn steak_data() -> PossessionData { + PossessionData { + display: "steak", + details: "A hunk of raw red meat, dripping with blood", + weight: 100, + ..Default::default() + } +} + +pub fn severed_head_data() -> PossessionData { + PossessionData { + display: "steak", + details: "A head that has been chopped clean from the body", + weight: 250, + ..Default::default() + } +} diff --git a/blastmud_game/src/static_content/possession_type/trauma_kit.rs b/blastmud_game/src/static_content/possession_type/trauma_kit.rs index 0981d4ac..3364f2fb 100644 --- a/blastmud_game/src/static_content/possession_type/trauma_kit.rs +++ b/blastmud_game/src/static_content/possession_type/trauma_kit.rs @@ -212,7 +212,7 @@ pub fn medium_data() -> PossessionData { task_ref: "bandage", errorf: Box::new( |_item, target| - if target.is_dead { + if target.death_data.is_some() { Some(format!("It is too late, {}'s dead", target.pronouns.subject)) } else if target.item_type != "player" && target.item_type != "npc" { Some("It only works on animals.".to_owned()) diff --git a/blastmud_game/src/static_content/room/melbs.rs b/blastmud_game/src/static_content/room/melbs.rs index a0c4b69e..03250497 100644 --- a/blastmud_game/src/static_content/room/melbs.rs +++ b/blastmud_game/src/static_content/room/melbs.rs @@ -2527,6 +2527,11 @@ pub fn room_list() -> Vec { target: ExitTarget::UseGPS, exit_type: ExitType::Free }, + Exit { + direction: Direction::SOUTH, + target: ExitTarget::UseGPS, + exit_type: ExitType::Free + }, ), should_caption: false, ..Default::default() @@ -2557,6 +2562,32 @@ pub fn room_list() -> Vec { should_caption: true, ..Default::default() }, + Room { + zone: "melbs", + secondary_zones: vec!(), + code: "melbs_grande_outdoors", + name: "Grande Outdoors", + short: ansi!("GO"), + description: "A shop that looks like it once helped people camp for fun, its clientele now days are probably more focused on just surviving! A weary looking woman with calloused, grease covered hands paces the shop floor, prepared to spring on you and hype up whatever merchandise you look at as the best thing ever", + description_less_explicit: None, + grid_coords: GridCoords { x: 3, y: 4, z: 0 }, + exits: vec!( + Exit { + direction: Direction::NORTH, + target: ExitTarget::UseGPS, + exit_type: ExitType::Free + }, + ), + stock_list: vec!( + RoomStock { + possession_type: PossessionType::ButcherKnife, + list_price: 120, + ..Default::default() + } + ), + should_caption: true, + ..Default::default() + }, Room { zone: "melbs", secondary_zones: vec!(), diff --git a/blastmud_game/src/static_content/species.rs b/blastmud_game/src/static_content/species.rs index 2826d3f8..bdae2a2d 100644 --- a/blastmud_game/src/static_content/species.rs +++ b/blastmud_game/src/static_content/species.rs @@ -2,7 +2,8 @@ use once_cell::sync::OnceCell; use serde::{Serialize, Deserialize}; use std::collections::BTreeMap; use crate::{ - models::item::Sex + models::item::Sex, + static_content::possession_type::PossessionType, }; use rand::seq::IteratorRandom; @@ -57,7 +58,8 @@ impl BodyPart { } pub struct SpeciesInfo { - body_parts: Vec, + pub body_parts: Vec, + pub corpse_butchers_into: Vec, } @@ -76,7 +78,13 @@ pub fn species_info_map() -> &'static BTreeMap { BodyPart::Arms, BodyPart::Legs, BodyPart::Feet - ) + ), + corpse_butchers_into: vec!( + PossessionType::Steak, + PossessionType::Steak, + PossessionType::AnimalSkin, + PossessionType::SeveredHead, + ), } ), (SpeciesType::Dog, @@ -89,7 +97,12 @@ pub fn species_info_map() -> &'static BTreeMap { BodyPart::Groin, BodyPart::Legs, BodyPart::Feet - ) + ), + corpse_butchers_into: vec!( + PossessionType::Steak, + PossessionType::AnimalSkin, + PossessionType::SeveredHead, + ), } ), ).into_iter().collect()