From fa573fa539bd718833e0b313fab235cbf4fd650a Mon Sep 17 00:00:00 2001 From: Y0SH1M4S73R Date: Sat, 5 Jul 2025 03:43:54 -0400 Subject: [PATCH] Adds the self-surgery skillchip as a fairly rare black market item (#91606) ## About The Pull Request This PR adds a skillchip that allows the user to perform normal surgeries on themselves, albeit with a 1.5x speed penalty and a flat 33% increase to the probability of screwing up each step. You can find this skillchip occasionally on the black market. It is also contraband, and can be detected by n-spect scanners. ## Why It's Good For The Game Provides a risky alternate means of obtaining surgical intervention, such as if you either can't trust anybody else to do surgery on you or can't be trusted to have certain surgeries done on you. ## Changelog :cl: add: The Centcom Department of Import Control has become aware of the use of highly-illegal and medically dubious self-surgery skillchips aboard company stations. We suspect they are being sold to the station through the black market. /:cl: --- .../signals/signals_mob/signals_mob_living.dm | 8 +++++ code/__DEFINES/traits/declarations.dm | 4 +++ code/_globalvars/traits/_traits.dm | 1 + code/_onclick/item_attack.dm | 2 +- code/datums/components/surgery_initiator.dm | 2 +- .../cargo/markets/market_items/misc.dm | 18 ++++++++++++ .../generic_skillchips/self_surgery.dm | 29 +++++++++++++++++++ code/modules/surgery/surgery_step.dm | 16 ++++++++-- tgstation.dme | 1 + 9 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 code/modules/library/skill_learning/generic_skillchips/self_surgery.dm diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index a6ffc9afc5a..36ef596098d 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -326,3 +326,11 @@ /// From /obj/item/book/bible/attack() : (mob/living/user, obj/item/book/bible/bible, bless_result) #define COMSIG_LIVING_BLESSED "living_blessed" + +/// From /datum/surgery_step/initiate() : (mob/living/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, datum/surgery_step/step, list/modifiers) +#define COMSIG_LIVING_INITIATE_SURGERY_STEP "living_initiate_surgery_step" +#define COMSIG_LIVING_SURGERY_STEP_INITIATED_ON "living_surgery_step_initiated_on" + /// Index in modifiers containing the modifier to failure chance + #define FAIL_PROB_INDEX 1 + /// Index in modifiers containing the modifer to surgery speed + #define SPEED_MOD_INDEX 2 diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index d6aa8c5c0e0..4124327bc58 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1530,4 +1530,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait that signals to objects on this turf that its open (has UNDERFLOOR_INTERACTIBLE) but still covers them #define TRAIT_UNCOVERED_TURF "uncovered_turf" + +/// Trait that allows mobs to perform surgery on themselves +#define TRAIT_SELF_SURGERY "self_surgery" + // END TRAIT DEFINES diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index cf0efed5edd..9215e6b5fdf 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -506,6 +506,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, "TRAIT_SEE_WORN_COLOURS" = TRAIT_SEE_WORN_COLOURS, "TRAIT_SELF_AWARE" = TRAIT_SELF_AWARE, + "TRAIT_SELF_SURGERY" = TRAIT_SELF_SURGERY, "TRAIT_SETTLER" = TRAIT_SETTLER, "TRAIT_SHAVED" = TRAIT_SHAVED, "TRAIT_SHELL_RETREATED" = TRAIT_SHELL_RETREATED, diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index a57fe7e9ab4..70221407f4b 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -183,7 +183,7 @@ for(var/datum/surgery/operation as anything in surgeries) if(IS_IN_INVALID_SURGICAL_POSITION(src, operation)) continue - if(!(operation.surgery_flags & SURGERY_SELF_OPERABLE) && (user == src)) + if(!(operation.surgery_flags & SURGERY_SELF_OPERABLE) && (user == src) && !HAS_TRAIT(user, TRAIT_SELF_SURGERY)) continue if(operation.next_step(user, modifiers)) return ITEM_INTERACT_SUCCESS diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index 46731125101..56c49e4c0ec 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -90,7 +90,7 @@ continue if(!is_type_in_list(target, surgery.target_mobtypes)) continue - if(user == target && !(surgery.surgery_flags & SURGERY_SELF_OPERABLE)) + if(user == target && !HAS_TRAIT(user, TRAIT_SELF_SURGERY) && !(surgery.surgery_flags & SURGERY_SELF_OPERABLE)) continue if(isnull(affecting)) diff --git a/code/modules/cargo/markets/market_items/misc.dm b/code/modules/cargo/markets/market_items/misc.dm index 509f499b3c2..057d94264ae 100644 --- a/code/modules/cargo/markets/market_items/misc.dm +++ b/code/modules/cargo/markets/market_items/misc.dm @@ -203,3 +203,21 @@ )) new type(C) return C + +/datum/market_item/misc/self_surgery_skillchip + name = /obj/item/skillchip/self_surgery::name + desc = "Man, the insurance companies HATE this one. Damn fat-cats can't stand the idea of people treating their own illnesses - \ + they'd rather you go to THEIR doctors, who THEY convinced to charge EXTORTIONARY prices the average Joe can't afford, all so you \ + gotta sign on to THEIR packages. Most people end up paying for NOTHING for YEARS just so that they have a CHANCE at being able to afford \ + treatment when they actually NEED it. \n\n Uh, what was I talking about again... Oh, yeah. This here skillchip'll let you put yourself under the knife. \ + A must-have for the person who can't rely on anyone else." + item = /obj/item/skillchip/self_surgery + price_min = CARGO_CRATE_VALUE * 5 + price_max = CARGO_CRATE_VALUE * 10 + stock_max = 1 + availability_prob = 15 + +/datum/market_item/misc/self_surgery_skillchip/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method, legal_status) + . = ..() + if(.) + availability_prob *= 0.5 diff --git a/code/modules/library/skill_learning/generic_skillchips/self_surgery.dm b/code/modules/library/skill_learning/generic_skillchips/self_surgery.dm new file mode 100644 index 00000000000..ba17761b8b7 --- /dev/null +++ b/code/modules/library/skill_learning/generic_skillchips/self_surgery.dm @@ -0,0 +1,29 @@ +/obj/item/skillchip/self_surgery + name = "4U70-P3R4710N skillchip" + desc = "A skillchip containing old Nanotrasen medical training protocols, which one could use to perform surgical operations on themselves. \ + This one doesn't look like it's in the best condition - bit rot has probably rendered it somewhat risky to use." + auto_traits = list(TRAIT_SELF_SURGERY) + skill_name = "Self Surgery" + skill_description = "Allows you to perform surgery on yourself." + skill_icon = FA_ICON_USER_DOCTOR + activate_message = span_notice("You realize there's nothing stopping you from performing surgery on yourself.") + deactivate_message = span_notice("You suddenly feel like you should never perform surgery on yourself.") + +/obj/item/skillchip/self_surgery/Initialize(mapload, is_removable) + . = ..() + ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT) + +/obj/item/skillchip/self_surgery/on_activate(mob/living/carbon/user, silent) + . = ..() + RegisterSignal(user, COMSIG_LIVING_INITIATE_SURGERY_STEP, PROC_REF(apply_surgery_penalty)) + +/obj/item/skillchip/self_surgery/on_deactivate(mob/living/carbon/user, silent) + . = ..() + UnregisterSignal(user, COMSIG_LIVING_INITIATE_SURGERY_STEP) + +/obj/item/skillchip/self_surgery/proc/apply_surgery_penalty(mob/living/carbon/_source, mob/living/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, datum/surgery_step/step, list/modifiers) + SIGNAL_HANDLER + if(user != target) + return + modifiers[FAIL_PROB_INDEX] += 33 + modifiers[SPEED_MOD_INDEX] *= 1.5 diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 532464e9713..25022d8d65e 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -130,8 +130,20 @@ var/modded_time = time * speed_mod - fail_prob = min(max(0, modded_time - (time * SURGERY_SLOWDOWN_CAP_MULTIPLIER)),99)//if modded_time > time * modifier, then fail_prob = modded_time - time*modifier. starts at 0, caps at 99 - modded_time = min(modded_time, time * SURGERY_SLOWDOWN_CAP_MULTIPLIER)//also if that, then cap modded_time at time*modifier + fail_prob = max(0, modded_time - (time * SURGERY_SLOWDOWN_CAP_MULTIPLIER)) //if modded_time > time * modifier, then fail_prob = modded_time - time*modifier + + var/list/user_modifiers = list(0, 1) + SEND_SIGNAL(user, COMSIG_LIVING_INITIATE_SURGERY_STEP, user, target, target_zone, tool, surgery, src, user_modifiers) + fail_prob += user_modifiers[FAIL_PROB_INDEX] + modded_time *= user_modifiers[SPEED_MOD_INDEX] + + var/list/target_modifiers = list(0, 1) + SEND_SIGNAL(target, COMSIG_LIVING_SURGERY_STEP_INITIATED_ON, user, target, target_zone, tool, surgery, src, target_modifiers) + fail_prob += target_modifiers[FAIL_PROB_INDEX] + modded_time *= target_modifiers[SPEED_MOD_INDEX] + + fail_prob = min(max(0, fail_prob),99) // clamp fail_prob between 0 and 99 + modded_time = min(modded_time, time * SURGERY_SLOWDOWN_CAP_MULTIPLIER)// cap modded_time at time*modifier if(iscyborg(user))//any immunities to surgery slowdown should go in this check. modded_time = time * tool.toolspeed diff --git a/tgstation.dme b/tgstation.dme index 6244095c2b8..001b81e54a4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4647,6 +4647,7 @@ #include "code\modules\library\skill_learning\generic_skillchips\misc.dm" #include "code\modules\library\skill_learning\generic_skillchips\musical.dm" #include "code\modules\library\skill_learning\generic_skillchips\point.dm" +#include "code\modules\library\skill_learning\generic_skillchips\self_surgery.dm" #include "code\modules\library\skill_learning\job_skillchips\_job.dm" #include "code\modules\library\skill_learning\job_skillchips\chef.dm" #include "code\modules\library\skill_learning\job_skillchips\clown.dm"