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"