diff --git a/code/__HELPERS/mob_helpers.dm b/code/__HELPERS/mob_helpers.dm index 1728382defb..fb2e078e9fd 100644 --- a/code/__HELPERS/mob_helpers.dm +++ b/code/__HELPERS/mob_helpers.dm @@ -498,6 +498,14 @@ GLOBAL_LIST_EMPTY(do_after_once_tracker) . = do_after(user, delay, needhand, target, progress, allow_moving, must_be_held, extra_checks = list(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(do_after_once_checks), cache_key, hidden)), interaction_key = interaction_key) GLOB.do_after_once_tracker[cache_key] = FALSE +// Please don't use this unless you absolutely need to. Just have a direct call to do_after_once whenever possible. +/proc/interrupt_do_after_once(mob/user, atom/target, special_identifier) + var/cache_key = "[user.UID()][target.UID()][special_identifier]" + if(GLOB.do_after_once_tracker[cache_key]) + GLOB.do_after_once_tracker[cache_key] = DOAFTERONCE_MAGIC + return TRUE + return FALSE + /proc/do_after_once_checks(cache_key) if(GLOB.do_after_once_tracker[cache_key] && GLOB.do_after_once_tracker[cache_key] == DOAFTERONCE_MAGIC) GLOB.do_after_once_tracker[cache_key] = FALSE diff --git a/code/__HELPERS/pronouns.dm b/code/__HELPERS/pronouns.dm index 2b3d41437c8..7d0c7e07487 100644 --- a/code/__HELPERS/pronouns.dm +++ b/code/__HELPERS/pronouns.dm @@ -248,6 +248,44 @@ if(temp_gender != PLURAL) . = "s" +// Internal dialogue pronouns. This allow replacements of "their" with "your", if the user and target are the same. Src should always be considered the "target". +/mob/proc/i_you(user, capitalized) + ASSERT(user) + if(src != user) + return p_they(capitalized) + . = "you" + if(capitalized) + . = capitalize(.) + +/mob/proc/i_your(user, capitalized) + ASSERT(user) + if(src != user) + return p_their(capitalized) + . = "your" + if(capitalized) + . = capitalize(.) + +/mob/proc/i_yourself(user, capitalized) + ASSERT(user) + if(src != user) + return src // don't say "himself", just refer to them by name + . = "yourself" + if(capitalized) + . = capitalize(.) + +/mob/proc/i_do(user) + ASSERT(user) + if(src != user) + return p_do() + . = "do" + +// External dialogue pronouns, similar to internal dialogue pronouns but for when the observer is a 3rd party. These should only really be used in visible_message() +/mob/proc/e_themselves(user, capitalized) + ASSERT(user) + if(src != user) + return src // refer to them by name, since its user acting on src + return p_themselves(capitalized) + ////////////////////////////// // MARK: Human procs ////////////////////////////// diff --git a/code/game/objects/items/stacks/medical_packs.dm b/code/game/objects/items/stacks/medical_packs.dm index e3840dbda7d..df59f896313 100644 --- a/code/game/objects/items/stacks/medical_packs.dm +++ b/code/game/objects/items/stacks/medical_packs.dm @@ -368,80 +368,95 @@ icon_state = "suture" gender = PLURAL merge_type = /obj/item/stack/medical/suture - healverb = "suturing" amount = 10 max_amount = 10 heal_brute = 10 stop_bleeding = 1200 dynamic_icon_state = TRUE delay = 1 SECONDS + healverb = "suturing" + var/healverb_past = "sutured" var/self_delay = 3 SECONDS - var/applying = FALSE + var/mob/current_target /obj/item/stack/medical/suture/apply(mob/living/carbon/human/target, mob/user) . = TRUE - if(applying) - to_chat(user, "You're already applying [src].") + if(current_target) + if(current_target != target) + to_chat(user, "You're already suturing [current_target].") + return + // Allow for cancelling of the target by clicking again + interrupt_do_after_once(user, current_target) + to_chat(user, "You stop [healverb] [target.i_yourself(user)].") return if(!ishuman(target) || !target.can_inject(user, TRUE)) return var/heal_type = (heal_brute ? BRUTE : BURN) var/heal_display = (heal_brute ? BRUTE : "burn") if(!target.get_damage_amount(heal_type)) - if(target == user) - to_chat(user, "You don't have any [heal_display] damage.") - else - to_chat(user, "They don't have any [heal_display] damage.") + to_chat(user, "[target.i_you(user, TRUE)] [target.i_do(user)]n't have any [heal_display] damage.") return var/obj/item/organ/external/current_limb = target.get_organ(user.zone_selected) if(!current_limb) - to_chat(user, "That limb is missing!") + to_chat(user, "That limb is missing!") return if(current_limb.is_robotic()) - to_chat(user, "This can't be used on a robotic limb.") + to_chat(user, "This can't be used on a robotic limb.") + return + // Swap to another limb if the current one has no damage. + if(!most_damaged_limb(target)) + to_chat(user, "[target.i_you(user, TRUE)] [target.i_do(user)]n't have any [heal_display] damage that could be [healverb_past].") return - if((heal_brute > 0 && !current_limb.brute_dam) || (heal_burn > 0 && !current_limb.burn_dam)) - if(!do_after(user, delay / 2, target = target)) - return - current_limb = most_damaged_limb(target) var/mend_time = delay if(target == user) - target.visible_message("[user] begins [healverb] [user.p_themselves()] with [src].", "You begin [healverb] your [current_limb.name] with [src].") mend_time = self_delay - else - user.visible_message("[user] begins [healverb] [target] with [src].", "You begin [healverb] [target.p_their()] [current_limb.name] with [src].") - applying = TRUE - while(do_after(user, mend_time, target = target)) - if(!target.can_inject(user, TRUE)) + user.visible_message("[user] begins [healverb] [target.e_themselves(user)] with [src].", "You begin [healverb] [target.i_your(user)] [current_limb.name] with [src].") + current_limb = try_swap_to_most_damaged_limb(target, user, current_limb) + if(!current_limb) + return + + var/last_targetted_zone = user.zone_selected + current_target = target + while(do_after_once(user, mend_time, target = target)) + if(!target.can_inject(user, TRUE, current_limb.limb_name)) break + var/cut_open = FALSE if(stop_bleeding) for(var/obj/item/organ/external/E in target.bodyparts) if(E.open >= ORGAN_ORGANIC_OPEN) cut_open = TRUE - to_chat(user, "[target]'s [E.name] is cut open, you'll need more than some [name] to stop their bleeding.") + to_chat(user, "[target]'s [E.name] is cut open, you'll need more than some [name] to stop [target.i_your(user)] bleeding.") break if(!apply_to(target, user, current_limb, !cut_open)) break if(is_zero_amount(TRUE)) break - if((heal_brute > 0 && !current_limb.brute_dam) || (heal_burn > 0 && !current_limb.burn_dam)) - if(!target.get_damage_amount(heal_type)) - if(target == user) - target.visible_message("[user] finishes [healverb] [user.p_themselves()] with [src].", "You finish [healverb] yourself with [src].") - else - user.visible_message("[user] finishes [healverb] [target] with [src].", "You finish [healverb] [target] with [src].") - break - if(!do_after(user, delay / 2, target = target)) - break - current_limb = most_damaged_limb(target) - to_chat(user, "You begin [healverb] [target == user ? "your" : target.p_their()] [current_limb.name] with [src].") - if(!target.can_inject(user, TRUE)) + if(!target.get_damage_amount(heal_type)) + user.visible_message("[user] finishes [healverb] [target.e_themselves(user)] with [src].", "You finish [healverb] [target.i_yourself(user)] with [src].") break - applying = FALSE + + var/skip_swap = FALSE + if(last_targetted_zone != user.zone_selected) + last_targetted_zone = user.zone_selected + var/new_limb = on_target_zone_change(target, user) + if(new_limb && current_limb != new_limb) + current_limb = new_limb + skip_swap = TRUE + to_chat(user, "You switch to [healverb] [target.i_your(user)] [current_limb.name].") + + if(!skip_swap) + current_limb = try_swap_to_most_damaged_limb(target, user, current_limb) + if(!current_limb) + user.visible_message("[user] finishes [healverb] [target.e_themselves(user)] with [src].", "You finish [healverb] [target.i_yourself(user)] with [src].") + break + + if(!target.can_inject(user, TRUE, current_limb.limb_name)) + break + current_target = null user.changeNext_move(CLICK_CD_MELEE) /obj/item/stack/medical/suture/proc/apply_to(mob/living/carbon/human/target, mob/user, obj/item/organ/external/current_limb, allow_stop_bleeding = TRUE) @@ -449,6 +464,7 @@ return FALSE current_limb.heal_damage(heal_brute, heal_burn, FALSE, FALSE, updating_health = TRUE) + target.UpdateDamageIcon() if(stop_bleeding && !target.bleedsuppress && allow_stop_bleeding) target.suppress_bloodloss(stop_bleeding) @@ -459,6 +475,10 @@ var/most_damaged_amount = 0 var/focus_brute = (heal_brute > 0) for(var/obj/item/organ/external/E in target.bodyparts) + if(QDELETED(E)) + continue + if(E.is_robotic()) + continue if(focus_brute) if(E.brute_dam > most_damaged_amount) most_damaged = E @@ -468,10 +488,41 @@ most_damaged_amount = E.burn_dam return most_damaged +/obj/item/stack/medical/suture/proc/try_swap_to_most_damaged_limb(mob/living/carbon/human/target, mob/user, obj/item/organ/external/current_limb) + if(heal_brute && current_limb.brute_dam) + return current_limb + if(heal_burn && current_limb.burn_dam) + return current_limb + + var/obj/item/organ/external/new_limb = most_damaged_limb(target) + if(!new_limb) + return + if(current_limb != new_limb) + to_chat(user, "You begin [healverb] [target.i_your(user)] [new_limb.name].") + if(!do_after(user, delay / 2, target = target)) + return + return new_limb + +/obj/item/stack/medical/suture/proc/on_target_zone_change(mob/living/carbon/human/target, mob/user) + var/obj/item/organ/external/new_limb = target.get_organ(user.zone_selected) + if(!new_limb) + to_chat(user, "That limb is missing!") + return FALSE + if(new_limb.is_robotic()) + to_chat(user, "This can't be used on a robotic limb.") + return FALSE + + if(heal_brute && new_limb.brute_dam) + return new_limb + if(heal_burn && new_limb.burn_dam) + return new_limb + return FALSE + /obj/item/stack/medical/suture/emergency name = "emergency sutures" singular_name = "emergency suture" desc = "A small bundle of cheap sutures. They're not pretty, but still quite effective at keeping the blood inside your body." + icon_state = "suture_emer" merge_type = /obj/item/stack/medical/suture/emergency heal_brute = 5 @@ -491,6 +542,7 @@ icon_state = "regen_mesh" merge_type = /obj/item/stack/medical/suture/regen_mesh healverb = "grafting" + healverb_past = "grafted" heal_brute = 0 heal_burn = 10 /// This var determines if the sterile packaging of the mesh has been opened. diff --git a/icons/obj/medical.dmi b/icons/obj/medical.dmi index 348a22f61ca..23f67c06c1c 100644 Binary files a/icons/obj/medical.dmi and b/icons/obj/medical.dmi differ