From b5f101661da571a6084dfc23cd9ebadc56a04265 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Fri, 5 Feb 2021 22:19:35 +0100 Subject: [PATCH] [MIRROR] You can now remove embedded objects directly with a hemostat (#3097) * You can now remove embedded objects directly with a hemostat (#56637) * You can now remove embedded objects directly with a hemostat Co-authored-by: Ryll Ryll <3589655+Ryll-Ryll@users.noreply.github.com> --- code/__DEFINES/combat.dm | 22 ++++---- code/datums/components/embedded.dm | 56 +++++++++++++++++-- code/datums/elements/embed.dm | 3 + .../modules/projectiles/projectile/bullets.dm | 4 +- .../projectile/bullets/revolver.dm | 7 ++- strings/tips.txt | 1 + tgstation.dme | 1 - 7 files changed, 73 insertions(+), 21 deletions(-) diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 1df651a2f71..4b64d381334 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -150,27 +150,29 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( //Embedded objects ///Chance for embedded objects to cause pain (damage user) -#define EMBEDDED_PAIN_CHANCE 15 +#define EMBEDDED_PAIN_CHANCE 15 ///Chance for embedded object to fall out (causing pain but removing the object) -#define EMBEDDED_ITEM_FALLOUT 5 +#define EMBEDDED_ITEM_FALLOUT 5 ///Chance for an object to embed into somebody when thrown -#define EMBED_CHANCE 45 +#define EMBED_CHANCE 45 ///Coefficient of multiplication for the damage the item does while embedded (this*item.w_class) -#define EMBEDDED_PAIN_MULTIPLIER 2 +#define EMBEDDED_PAIN_MULTIPLIER 2 ///Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class) -#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 +#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 ///The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1) -#define EMBED_THROWSPEED_THRESHOLD 4 +#define EMBED_THROWSPEED_THRESHOLD 4 ///Coefficient of multiplication for the damage the item does when it falls out or is removed without a surgery (this*item.w_class) #define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 6 ///A Time in ticks, total removal time = (this*item.w_class) -#define EMBEDDED_UNSAFE_REMOVAL_TIME 30 +#define EMBEDDED_UNSAFE_REMOVAL_TIME 30 ///Chance for embedded objects to cause pain every time they move (jostle) -#define EMBEDDED_JOSTLE_CHANCE 5 +#define EMBEDDED_JOSTLE_CHANCE 5 ///Coefficient of multiplication for the damage the item does while -#define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1 +#define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1 ///This percentage of all pain will be dealt as stam damage rather than brute (0-1) -#define EMBEDDED_PAIN_STAM_PCT 0.0 +#define EMBEDDED_PAIN_STAM_PCT 0.0 +///For thrown weapons, every extra speed it's thrown at above its normal throwspeed will add this to the embed chance +#define EMBED_CHANCE_SPEED_BONUS 10 #define EMBED_HARMLESS list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE) #define EMBED_HARMLESS_SUPERIOR list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE, "embed_chance" = 100, "fall_chance" = 0.1) diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index 396a5836129..50929b09983 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -116,9 +116,10 @@ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck) RegisterSignal(parent, COMSIG_CARBON_EMBED_RIP, .proc/ripOut) RegisterSignal(parent, COMSIG_CARBON_EMBED_REMOVAL, .proc/safeRemove) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/checkTweeze) /datum/component/embedded/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL)) + UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL, COMSIG_PARENT_ATTACKBY)) /datum/component/embedded/process(delta_time) var/mob/living/carbon/victim = parent @@ -202,11 +203,11 @@ victim.emote("scream") victim.visible_message("[victim] successfully rips [weapon] [harmful ? "out" : "off"] of [victim.p_their()] [limb.name]!", "You successfully remove [weapon] from your [limb.name].") - safeRemove(TRUE) + safeRemove(victim) /// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely. -/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out -/datum/component/embedded/proc/safeRemove(to_hands) +/// If you want the thing to go into someone's hands rather than the floor, pass them in to_hands +/datum/component/embedded/proc/safeRemove(mob/to_hands) SIGNAL_HANDLER var/mob/living/carbon/victim = parent @@ -216,7 +217,7 @@ if(!weapon.unembedded()) // if it hasn't deleted itself due to drop del UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) if(to_hands) - INVOKE_ASYNC(victim, /mob.proc/put_in_hands, weapon) + INVOKE_ASYNC(to_hands, /mob.proc/put_in_hands, weapon) else weapon.forceMove(get_turf(victim)) @@ -233,3 +234,48 @@ to_chat(victim, "\The [weapon] that was embedded in your [limb.name] disappears!") qdel(src) + +/// The signal for listening to see if someone is using a hemostat on us to pluck out this object +/datum/component/embedded/proc/checkTweeze(mob/living/carbon/victim, obj/item/possible_tweezers, mob/user) + SIGNAL_HANDLER + + if(!istype(victim) || possible_tweezers.tool_behaviour != TOOL_HEMOSTAT || user.zone_selected != limb.body_zone) + return + + if(weapon != limb.embedded_objects[1]) // just pluck the first one, since we can't easily coordinate with other embedded components affecting this limb who is highest priority + return + + if(ishuman(victim)) // check to see if the limb is actually exposed + var/mob/living/carbon/human/victim_human = victim + if(!victim_human.can_inject(user, TRUE, limb.body_zone, ignore_species = TRUE)) + return TRUE + + INVOKE_ASYNC(src, .proc/tweezePluck, possible_tweezers, user) + return COMPONENT_NO_AFTERATTACK + +/// The actual action for pulling out an embedded object with a hemostat +/datum/component/embedded/proc/tweezePluck(obj/item/possible_tweezers, mob/user) + var/mob/living/carbon/victim = parent + + var/self_pluck = (user == victim) + + if(self_pluck) + user.visible_message("[user] begins plucking [weapon] from [user.p_their()] [limb.name]", "You start plucking [weapon] from your [limb.name]...",\ + vision_distance=COMBAT_MESSAGE_RANGE, ignored_mobs=victim) + else + user.visible_message("[user] begins plucking [weapon] from [victim]'s [limb.name]","You start plucking [weapon] from [victim]'s [limb.name]...", \ + vision_distance=COMBAT_MESSAGE_RANGE, ignored_mobs=victim) + to_chat(victim, "[user] begins plucking [weapon] from your [limb.name]...") + + var/pluck_time = 2.5 SECONDS * weapon.w_class * (self_pluck ? 2 : 1) + if(!do_after(user, pluck_time, victim)) + if(self_pluck) + to_chat(user, "You fail to pluck [weapon] from your [limb.name].") + else + to_chat(user, "You fail to pluck [weapon] from [victim]'s [limb.name].") + to_chat(victim, "[user] fails to pluck [weapon] from your [limb.name].") + return + + to_chat(user, "You successfully pluck [weapon] from [victim]'s [limb.name].") + to_chat(victim, "[user] plucks [weapon] from your [limb.name].") + safeRemove(user) diff --git a/code/datums/elements/embed.dm b/code/datums/elements/embed.dm index 3f0b245f980..cf66e6f53db 100644 --- a/code/datums/elements/embed.dm +++ b/code/datums/elements/embed.dm @@ -75,6 +75,9 @@ var/actual_chance = embed_chance + if(throwingdatum?.speed > weapon.throw_speed) + actual_chance += (throwingdatum.speed - weapon.throw_speed) * EMBED_CHANCE_SPEED_BONUS + if(!weapon.isEmbedHarmless()) // all the armor in the world won't save you from a kick me sign var/armor = max(victim.run_armor_check(hit_zone, BULLET, silent=TRUE), victim.run_armor_check(hit_zone, BOMB, silent=TRUE)) * 0.5 // we'll be nice and take the better of bullet and bomb armor, halved diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 9ec4d3cd5a2..e4eb8e8ac25 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -9,9 +9,9 @@ sharpness = SHARP_POINTY impact_effect_type = /obj/effect/temp_visual/impact_effect shrapnel_type = /obj/item/shrapnel/bullet - embedding = list(embed_chance=15, fall_chance=2, jostle_chance=0, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=3, rip_time=10) + embedding = list(embed_chance=20, fall_chance=2, jostle_chance=0, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=3, rip_time=10) wound_falloff_tile = -5 - embed_falloff_tile = -5 + embed_falloff_tile = -3 /obj/projectile/bullet/smite name = "divine retribution" diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm index ac4d3ef9f6f..9eb39b94acd 100644 --- a/code/modules/projectiles/projectile/bullets/revolver.dm +++ b/code/modules/projectiles/projectile/bullets/revolver.dm @@ -21,7 +21,8 @@ ricochet_auto_aim_range = 3 wound_bonus = -20 bare_wound_bonus = 10 - embedding = list(embed_chance=15, fall_chance=2, jostle_chance=2, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=5, rip_time=10) + embedding = list(embed_chance=25, fall_chance=2, jostle_chance=2, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=5, rip_time=1 SECONDS) + embed_falloff_tile = -4 /obj/projectile/bullet/c38/match name = ".38 Match bullet" @@ -55,7 +56,7 @@ sharpness = SHARP_EDGED wound_bonus = 20 bare_wound_bonus = 20 - embedding = list(embed_chance=75, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) + embedding = list(embed_chance=75, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=1 SECONDS) wound_falloff_tile = -5 embed_falloff_tile = -15 @@ -106,7 +107,7 @@ /obj/projectile/bullet/a357 name = ".357 bullet" damage = 60 - wound_bonus = -70 + wound_bonus = -30 // admin only really, for ocelot memes /obj/projectile/bullet/a357/match diff --git a/strings/tips.txt b/strings/tips.txt index e0d36562c68..becbc14e615 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -55,6 +55,7 @@ As a Medical Doctor, Critical Slash wounds are one of the most dangerous conditi As a Medical Doctor, Saline-Glucose not only acts as a temporary boost to a patient's blood level, it also speeds blood regeneration! Perfect for drained patients! As a Medical Doctor, almost every type of wound can be treated at least temporarily with gauze. When in doubt, wrap it up! As a Paramedic, your UV penlight can be used to stem infections in burn wounds! Just target the infected limb and use it on the patient. +As a Paramedic, embedded objects in a patient can be safely extracted by targeting the affected limb and using a hemostat on the patient. As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment! As a Chemist, some chemicals can only be synthesized by heating up the contents with a chemical heater or manually with lighters and similar tools. As a Chemist, you will be expected to supply crew with certain chemicals. For example, clonexadone and mannitol for the cryo tubes, unstable mutagen and saltpetre for botany as well as healing pills and patches for the front desk. diff --git a/tgstation.dme b/tgstation.dme index 3363ed29139..e5311b62813 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3193,7 +3193,6 @@ #include "code\modules\surgery\organic_steps.dm" #include "code\modules\surgery\plastic_surgery.dm" #include "code\modules\surgery\prosthetic_replacement.dm" -#include "code\modules\surgery\remove_embedded_object.dm" #include "code\modules\surgery\repair_puncture.dm" #include "code\modules\surgery\revival.dm" #include "code\modules\surgery\stomachpump.dm"