diff --git a/code/datums/wounds/blunt.dm b/code/datums/wounds/blunt.dm index 219b7dd8805c..e47fce542056 100644 --- a/code/datums/wounds/blunt.dm +++ b/code/datums/wounds/blunt.dm @@ -1,3 +1,10 @@ /datum/wound/blunt name = "Blunt Wound" sound_effect = 'sound/effects/wounds/crack1.ogg' + +/datum/wound/blunt/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + // oops your bone injury knocked off your gauze, gotta re-apply it + limb.remove_gauze(limb.drop_location()) + + return ..() diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index 415113c3bd77..7f6bb8e8b72d 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -9,6 +9,15 @@ a_or_from = "from" sound_effect = 'sound/effects/wounds/sizzle1.ogg' +/datum/wound/burn/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + qdel(limb.remove_gauze()) + // oops your existing gauze got burned, need a new one now + var/obj/effect/decal/cleanable/ash/ash = new(limb.drop_location()) + ash.desc += " It looks like it used to be some kind of bandage." + + return ..() + /datum/wound/burn/flesh name = "Burn (Flesh) Wound" a_or_from = "from" @@ -149,7 +158,7 @@ if(4 to INFINITY) bandage_condition = "clean" - condition += " underneath a dressing of [bandage_condition] [limb.current_gauze.name]" + condition += " underneath a dressing of [bandage_condition] [limb.current_gauze.name]." else switch(infestation) if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index f80d2adf453c..9a33c6b11cb0 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -4,6 +4,12 @@ */ /datum/wound/pierce +/datum/wound/pierce/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + // oops your existing gauze got penetrated through! need a new one now + limb.seep_gauze(initial(limb.current_gauze.absorption_capacity) * 0.8) + return ..() + /datum/wound/pierce/bleed name = "Piercing Wound" sound_effect = 'sound/weapons/slice.ogg' @@ -29,7 +35,6 @@ set_blood_flow(initial_flow) if(limb.can_bleed() && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) victim.spray_blood(attack_direction, severity) - return ..() /datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus) @@ -82,8 +87,9 @@ adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first if(limb.current_gauze) - adjust_blood_flow(-limb.current_gauze.absorption_rate * gauzed_clot_rate * seconds_per_tick) - limb.current_gauze.absorption_capacity -= limb.current_gauze.absorption_rate * seconds_per_tick + var/amt_blocking = limb.current_gauze.absorption_rate * seconds_per_tick + adjust_blood_flow(-1 * amt_blocking * gauzed_clot_rate) + limb.seep_gauze(amt_blocking) if(blood_flow <= 0) qdel(src) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 980cb7124845..8f5b589e7482 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -7,6 +7,12 @@ name = "Slashing (Cut) Wound" sound_effect = 'sound/weapons/slice.ogg' +/datum/wound/slash/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + // oops your existing gauze got cut through! need a new one now + limb.seep_gauze(initial(limb.current_gauze.absorption_capacity) * 0.8) + return ..() + /datum/wound_pregen_data/flesh_slash abstract = TRUE diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index 8a80692f1a9a..c3b81fd58c03 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -241,7 +241,7 @@ pixel_x = rand(-10, 10) pixel_y = rand(-10, 10) if(!isnull(oldname)) - desc = "The sad remains of what used to be [oldname]" + desc = "The sad remains of what used to be [oldname]." . = ..() /obj/effect/decal/cleanable/glitter diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 4713c9523390..84661e487676 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -17,6 +17,8 @@ source = /datum/robot_energy_storage/medical merge_type = /obj/item/stack/medical pickup_sound = 'maplestation_modules/sound/items/pickup/surgery_cloth.ogg' + /// Sound played when heal doafter begins + var/heal_sound /// How long it takes to apply it to yourself var/self_delay = 5 SECONDS /// How long it takes to apply it to someone else @@ -86,6 +88,8 @@ if(iscarbon(patient)) new_self_delay = looping ? clamp((self_delay - assessing_injury_delay), 0, self_delay) : self_delay new_other_delay = looping ? clamp((other_delay - assessing_injury_delay), 0, other_delay) : other_delay + if(heal_sound) + playsound(patient, heal_sound, 33, FALSE) if(patient == user) if(!silent) user.visible_message( @@ -231,15 +235,48 @@ burn_cleanliness_bonus = 0.35 merge_type = /obj/item/stack/medical/gauze drop_sound = 'sound/items/handling/cloth_drop.ogg' - var/obj/item/bodypart/gauzed_bodypart + /// tracks how many times we've been scrubbed thoroughly + var/times_cleaned = 0 -/obj/item/stack/medical/gauze/Destroy(force) +/obj/item/stack/medical/gauze/update_name(updates) . = ..() + var/base_cap = initial(absorption_capacity) + if(!base_cap) + return + + if(absorption_capacity <= 0) + name = "used [initial(name)]" + else if(absorption_capacity <= base_cap * 0.2) + name = "dirty [initial(name)]" + else if(absorption_capacity <= base_cap * 0.8) + name = "worn [initial(name)]" + else + name = initial(name) - if (gauzed_bodypart) - gauzed_bodypart.current_gauze = null - SEND_SIGNAL(gauzed_bodypart, COMSIG_BODYPART_UNGAUZED, src) - gauzed_bodypart = null +/obj/item/stack/medical/gauze/can_merge(obj/item/stack/medical/gauze/check, inhand) + . = ..() + if(!.) + return . + // need to be in +- 0.5 dirtiness of each other + // otherwise you can merge a completely used bandage with a brand new one, which would magically unuse it + if(check.absorption_capacity < absorption_capacity - 0.25 || check.absorption_capacity > absorption_capacity + 0.25) + return FALSE + return . + +/obj/item/stack/medical/gauze/wash(clean_types) + . = ..() + if(.) + return . + if(!(clean_types & CLEAN_TYPE_HARD_DECAL)) // gotta scrub realllly hard to clean gauze + return . + times_cleaned += 1 + var/clean_to = initial(absorption_capacity) * (3 / (times_cleaned + 3)) + if(absorption_capacity < clean_to) + absorption_capacity = clean_to + update_appearance(UPDATE_NAME) + . = TRUE + + return . // gauze is only relevant for wounds, which are handled in the wounds themselves /obj/item/stack/medical/gauze/try_heal(mob/living/patient, mob/user, silent, looping) @@ -248,40 +285,62 @@ var/obj/item/bodypart/limb = patient.get_bodypart(check_zone(user.zone_selected)) if(!limb) - patient.balloon_alert(user, "missing limb!") - return - if(!LAZYLEN(limb.wounds)) - patient.balloon_alert(user, "no wounds!") // good problem to have imo - return - - var/gauzeable_wound = FALSE - var/datum/wound/woundies - for(var/i in limb.wounds) - woundies = i - if(woundies.wound_flags & ACCEPTS_GAUZE) - gauzeable_wound = TRUE - break - if(!gauzeable_wound) - patient.balloon_alert(user, "can't heal those!") + patient.balloon_alert(user, "no limb!") return if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 1.2 > absorption_capacity)) // ignore if our new wrap is < 20% better than the current one, so someone doesn't bandage it 5 times in a row patient.balloon_alert(user, pick("already bandaged!", "bandage is clean!")) // good enough return - if(HAS_TRAIT(woundies, TRAIT_WOUND_SCANNED)) + var/boosted = FALSE + if(LAZYLEN(limb.wounds)) + for(var/datum/wound/wound as anything in limb.wounds) + if(HAS_TRAIT(wound, TRAIT_WOUND_SCANNED)) + boosted = TRUE + break + else + // gives you extra time so you realize you're not treating a wound + treatment_delay *= 2 + + var/whose = user == patient ? "your" : "[patient]'s" + var/theirs = user == patient ? patient.p_their() : "[patient]'s" + var/wrap_or_replace = limb.current_gauze ? "replacing [limb.current_gauze] on" : "wrapping" + var/with_what = limb.current_gauze?.type == type ? "more of [src]" : src + if(boosted) treatment_delay *= 0.5 - if(user == patient) - to_chat(user, span_notice("You keep in mind the indications from the holo-image about your injury, and expertly begin wrapping your wounds with [src].")) - else - user.visible_message(span_warning("[user] begins expertly wrapping the wounds on [patient]'s [limb.plaintext_zone] with [src]..."), span_warning("You begin quickly wrapping the wounds on [patient]'s [limb.plaintext_zone] with [src], keeping the holo-image indications in mind...")) + user.visible_message( + span_notice("[user] begins expertly [wrap_or_replace] [theirs] [limb.plaintext_zone] with [with_what]."), + span_notice("You begin quickly [wrap_or_replace] [whose] [limb.plaintext_zone] with [with_what], keeping the holo-image indications in mind..."), + ) else - user.visible_message(span_warning("[user] begins wrapping the wounds on [patient]'s [limb.plaintext_zone] with [src]..."), span_warning("You begin wrapping the wounds on [user == patient ? "your" : "[patient]'s"] [limb.plaintext_zone] with [src]...")) + user.visible_message( + span_notice("[user] begins [wrap_or_replace] [theirs] [limb.plaintext_zone] with [with_what]."), + span_notice("You begin [wrap_or_replace] [whose] [limb.plaintext_zone] with [with_what]..."), + ) + user.balloon_alert(user, "applying gauze...") + if(user != patient) + user.balloon_alert(patient, "applying gauze...") + + playsound(patient, pick( + 'maplestation_modules/sound/items/rip1.ogg', + 'maplestation_modules/sound/items/rip2.ogg', + 'maplestation_modules/sound/items/rip3.ogg', + 'maplestation_modules/sound/items/rip4.ogg', + ), 33) if(!do_after(user, treatment_delay, target = patient)) + user.balloon_alert(user, "interrupted!") return + if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 1.2 > absorption_capacity)) // double check for sanity + return + user.balloon_alert(user, "gauze applied") + if(user != patient) + user.balloon_alert(patient, "gauze applied") - user.visible_message("[user] applies [src] to [patient]'s [limb.plaintext_zone].", "You bandage the wounds on [user == patient ? "your" : "[patient]'s"] [limb.plaintext_zone].") + user.visible_message( + span_infoplain(span_green("[user] applies [src] to [theirs] [limb.plaintext_zone].")), + span_infoplain(span_green("You [limb.current_gauze?.type == type ? "replace" : "bandage"] the wounds on [whose] [limb.plaintext_zone].")), + ) limb.apply_gauze(src) /obj/item/stack/medical/gauze/twelve @@ -343,6 +402,7 @@ stop_bleeding = 0.6 grind_results = list(/datum/reagent/medicine/spaceacillin = 2) merge_type = /obj/item/stack/medical/suture + heal_sound = 'maplestation_modules/sound/items/snip.ogg' /obj/item/stack/medical/suture/emergency name = "emergency suture" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e4516eb4d22a..209789b8fb15 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -211,6 +211,14 @@ SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L) return + if(href_list["gauze_limb"]) + var/obj/item/bodypart/gauzed = locate(href_list["gauze_limb"]) in bodyparts + if(isnull(gauzed?.current_gauze)) + return + // rest of the sanity is handled in the proc itself + gauzed.help_remove_gauze(usr) + return + if(href_list["show_paper_note"]) var/obj/item/paper/paper_note = locate(href_list["show_paper_note"]) if(!paper_note) diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 5cbc3072877a..5071bdcbc1ea 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -332,20 +332,13 @@ remove_overlay(DAMAGE_LAYER) var/mutable_appearance/damage_overlay - var/digi_filter = FALSE for(var/obj/item/bodypart/iter_part as anything in bodyparts) - if(!iter_part.dmg_overlay_type) + var/list/part_overlays = iter_part.get_bodypart_damage_state() + if(!LAZYLEN(part_overlays)) continue - if(iter_part.brutestate || iter_part.burnstate) - damage_overlay ||= mutable_appearance('icons/mob/effects/dam_mob.dmi', "blank", -DAMAGE_LAYER, appearance_flags = KEEP_TOGETHER) - if(iter_part.brutestate) - damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0") //we're adding icon_states of the base image as overlays - damage_overlay.color = iter_part.damage_color - if(iter_part.burnstate) - damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_0[iter_part.burnstate]") - if(!digi_filter && damage_overlay && (iter_part.bodytype & BODYTYPE_DIGITIGRADE)) - iter_part.apply_digitigrade_filters(damage_overlay, src) - digi_filter = TRUE + + damage_overlay ||= mutable_appearance(layer = -DAMAGE_LAYER) + damage_overlay.overlays += part_overlays if(isnull(damage_overlay)) return diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 1325587a5e4b..6b28e33c06b4 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -138,23 +138,27 @@ var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) var/list/disabled = list() - for(var/X in bodyparts) - var/obj/item/bodypart/body_part = X + var/adjacent = user.Adjacent(src) + for(var/obj/item/bodypart/body_part as anything in bodyparts) if(body_part.bodypart_disabled) disabled += body_part missing -= body_part.body_zone - for(var/obj/item/I in body_part.embedded_objects) - if(I.isEmbedHarmless()) - msg += "[t_He] [t_has] [icon2html(I, user)] \a [I] stuck to [t_his] [body_part.plaintext_zone]!\n" - else - msg += "[t_He] [t_has] [icon2html(I, user)] \a [I] embedded in [t_his] [body_part.plaintext_zone]!\n" - - for(var/i in body_part.wounds) - var/datum/wound/iter_wound = i + for(var/obj/item/leftover in body_part.embedded_objects) + var/stuck_or_embedded = "embedded in" + if(leftover.isEmbedHarmless()) + stuck_or_embedded = "stuck to" + msg += "[t_He] [t_has] [icon2html(leftover, user)] \a [leftover] [stuck_or_embedded] [t_his] [body_part.plaintext_zone]!\n" + + if(body_part.current_gauze) + var/gauze_href = body_part.current_gauze.name + if(adjacent && isliving(user)) // only shows the href if we're adjacent + gauze_href = "[gauze_href]" + msg += span_notice("There is some [icon2html(body_part.current_gauze, user)] [gauze_href] wrapped around [t_his] [body_part.plaintext_zone].\n") + + for(var/datum/wound/iter_wound as anything in body_part.wounds) msg += "[iter_wound.get_examine_description(user)]\n" - for(var/X in disabled) - var/obj/item/bodypart/body_part = X + for(var/obj/item/bodypart/body_part as anything in disabled) var/damage_text if(HAS_TRAIT(body_part, TRAIT_DISABLED_BY_WOUND)) continue // skip if it's disabled by a wound (cuz we'll be able to see the bone sticking out!) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index fa96a721c8c7..82676f62eca0 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -845,7 +845,7 @@ generate/load female uniform sprites matching all previously decided variables return appearance -/obj/item/proc/apply_digitigrade_filters(mutable_appearance/appearance, mob/living/carbon/human/wearer = loc) +/obj/item/proc/apply_digitigrade_filters(mutable_appearance/appearance, mob/living/carbon/wearer = loc) if(!istype(wearer) || !(wearer.bodytype & BODYTYPE_DIGITIGRADE) || wearer.is_digitigrade_squished()) return diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 357b69e59a2d..50ac0e5021ac 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -361,6 +361,9 @@ var/stuck_word = embedded_thing.isEmbedHarmless() ? "stuck" : "embedded" check_list += "\t There is \a [embedded_thing] [stuck_word] in your [name]!" + if(current_gauze) + check_list += span_notice("\t There is some [current_gauze.name] wrapped around your [name].") + /obj/item/bodypart/blob_act() receive_damage(max_damage, wound_bonus = CANT_WOUND) @@ -894,8 +897,8 @@ set_can_be_disabled(initial(can_be_disabled)) -//Updates an organ's brute/burn states for use by update_damage_overlays() -//Returns 1 if we need to update overlays. 0 otherwise. +/// Updates an organ's brute/burn states for use by update_damage_overlays(). +/// Returns TRUE if state changed (IE, an update is needed) /obj/item/bodypart/proc/update_bodypart_damage_state() SHOULD_CALL_PARENT(TRUE) @@ -907,6 +910,45 @@ return TRUE return FALSE +/// Gets overlays to apply to the mob when damaged. +/obj/item/bodypart/proc/get_bodypart_damage_state() + if(!dmg_overlay_type) + return + + var/list/overlays + if(brutestate) + var/mutable_appearance/brute_overlay = mutable_appearance( + icon = 'icons/mob/effects/dam_mob.dmi', + icon_state = "[dmg_overlay_type]_[body_zone]_[brutestate]0", + layer = -DAMAGE_LAYER, + ) + brute_overlay.color = damage_color + LAZYADD(overlays, brute_overlay) + if(burnstate) + var/mutable_appearance/burn_overlay = mutable_appearance( + icon = 'icons/mob/effects/dam_mob.dmi', + icon_state = "[dmg_overlay_type]_[body_zone]_0[burnstate]", + layer = -DAMAGE_LAYER, + ) + LAZYADD(overlays, burn_overlay) + if(current_gauze) + var/mutable_appearance/gauze_overlay = current_gauze.build_worn_icon( + default_layer = DAMAGE_LAYER - 0.1, // proc inverts it for us + override_file = 'maplestation_modules/icons/mob/bandage.dmi', + override_state = current_gauze.worn_icon_state, // future todo : icon states for dirty bandages as well + ) + LAZYADD(overlays, gauze_overlay) + return overlays + +/obj/item/bodypart/leg/get_bodypart_damage_state() + if(!(bodytype & BODYTYPE_DIGITIGRADE) || (owner.is_digitigrade_squished())) + return ..() + + . = ..() + for(var/mutable_appearance/appearance in .) + apply_digitigrade_filters(appearance, owner) + return . + //we inform the bodypart of the changes that happened to the owner, or give it the informations from a source mob. //set is_creating to true if you want to change the appearance of the limb outside of mutation changes or forced changes. /obj/item/bodypart/proc/update_limb(dropping_limb = FALSE, is_creating = FALSE) @@ -1234,46 +1276,6 @@ return ((biological_state & BIO_BLOODED) && (!owner || !HAS_TRAIT(owner, TRAIT_NOBLOOD))) -/** - * apply_gauze() is used to- well, apply gauze to a bodypart - * - * As of the Wounds 2 PR, all bleeding is now bodypart based rather than the old bleedstacks system, and 90% of standard bleeding comes from flesh wounds (the exception is embedded weapons). - * The same way bleeding is totaled up by bodyparts, gauze now applies to all wounds on the same part. Thus, having a slash wound, a pierce wound, and a broken bone wound would have the gauze - * applying blood staunching to the first two wounds, while also acting as a sling for the third one. Once enough blood has been absorbed or all wounds with the ACCEPTS_GAUZE flag have been cleared, - * the gauze falls off. - * - * Arguments: - * * gauze- Just the gauze stack we're taking a sheet from to apply here - */ -/obj/item/bodypart/proc/apply_gauze(obj/item/stack/medical/gauze/new_gauze) - if(!istype(new_gauze) || !new_gauze.absorption_capacity) - return - var/newly_gauzed = FALSE - if(!current_gauze) - newly_gauzed = TRUE - QDEL_NULL(current_gauze) - current_gauze = new new_gauze.type(src, 1) - new_gauze.use(1) - current_gauze.gauzed_bodypart = src - if(newly_gauzed) - SEND_SIGNAL(src, COMSIG_BODYPART_GAUZED, current_gauze, new_gauze) - -/** - * seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity. - * - * The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandages falls off and we're left with nothing. - * - * Arguments: - * * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?) - */ -/obj/item/bodypart/proc/seep_gauze(seep_amt = 0) - if(!current_gauze) - return - current_gauze.absorption_capacity -= seep_amt - if(current_gauze.absorption_capacity <= 0) - owner.visible_message(span_danger("\The [current_gauze.name] on [owner]'s [name] falls away in rags."), span_warning("\The [current_gauze.name] on your [name] falls away in rags."), vision_distance=COMBAT_MESSAGE_RANGE) - QDEL_NULL(current_gauze) - ///Loops through all of the bodypart's external organs and update's their color. /obj/item/bodypart/proc/recolor_external_organs() for(var/datum/bodypart_overlay/mutant/overlay in bodypart_overlays) diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index e65177cbe544..c389537d156f 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -43,7 +43,7 @@ limb_id = SPECIES_LIZARD /// Checks if this mob is wearing anything that does not have a valid sprite set for digitigrade legs -/mob/living/carbon/human/proc/is_digitigrade_squished() +/mob/living/carbon/proc/is_digitigrade_squished() var/obj/item/clothing/shoes/worn_shoes = get_item_by_slot(ITEM_SLOT_FEET) var/obj/item/clothing/under/worn_suit = get_item_by_slot(ITEM_SLOT_OCLOTHING) var/obj/item/clothing/under/worn_uniform = get_item_by_slot(ITEM_SLOT_ICLOTHING) @@ -70,9 +70,7 @@ /obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - limb_id = human_owner.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE + limb_id = owner.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE /obj/item/bodypart/leg/right/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' @@ -82,6 +80,4 @@ /obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - limb_id = human_owner.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE + limb_id = owner.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE diff --git a/code/modules/surgery/bodyparts/wounds.dm b/code/modules/surgery/bodyparts/wounds.dm index 1fc16c7ca8f8..20764da41e72 100644 --- a/code/modules/surgery/bodyparts/wounds.dm +++ b/code/modules/surgery/bodyparts/wounds.dm @@ -316,9 +316,109 @@ for(var/datum/wound/iter_wound as anything in wounds) dam_mul *= iter_wound.damage_multiplier_penalty - if(!LAZYLEN(wounds) && current_gauze && !replaced) // no more wounds = no need for the gauze anymore - owner.visible_message(span_notice("\The [current_gauze.name] on [owner]'s [name] falls away."), span_notice("The [current_gauze.name] on your [parse_zone(body_zone)] falls away.")) - QDEL_NULL(current_gauze) - wound_damage_multiplier = dam_mul refresh_bleed_rate() + +/** + * apply_gauze() is used to- well, apply gauze to a bodypart + * + * As of the Wounds 2 PR, all bleeding is now bodypart based rather than the old bleedstacks system, and 90% of standard bleeding comes from flesh wounds (the exception is embedded weapons). + * The same way bleeding is totaled up by bodyparts, gauze now applies to all wounds on the same part. Thus, having a slash wound, a pierce wound, and a broken bone wound would have the gauze + * applying blood staunching to the first two wounds, while also acting as a sling for the third one. Once enough blood has been absorbed or all wounds with the ACCEPTS_GAUZE flag have been cleared, + * the gauze falls off. + * + * Arguments: + * * gauze- Just the gauze stack we're taking a sheet from to apply here + */ +/obj/item/bodypart/proc/apply_gauze(obj/item/stack/medical/gauze/new_gauze) + if(!istype(new_gauze) || !new_gauze.absorption_capacity || !new_gauze.use(1)) + return + if(!isnull(current_gauze)) + remove_gauze(drop_location()) + + current_gauze = new new_gauze.type(src, 1) + current_gauze.worn_icon_state = "[body_zone][rand(1, 3)]" + if(can_bleed() && (generic_bleedstacks || cached_bleed_rate)) + current_gauze.add_mob_blood(owner) + if(!QDELETED(new_gauze)) + new_gauze.add_mob_blood(owner) + SEND_SIGNAL(src, COMSIG_BODYPART_GAUZED, current_gauze, new_gauze) + owner.update_damage_overlays() + +/obj/item/bodypart/proc/remove_gauze(atom/remove_to) + SEND_SIGNAL(src, COMSIG_BODYPART_UNGAUZED, current_gauze) + if(remove_to) + current_gauze.forceMove(remove_to) + else + current_gauze.moveToNullspace() + if(can_bleed() && (generic_bleedstacks || cached_bleed_rate)) + current_gauze.add_mob_blood(owner) + current_gauze.worn_icon_state = initial(current_gauze.worn_icon_state) + current_gauze.update_appearance() + . = current_gauze + current_gauze = null + owner.update_damage_overlays() + return . + +/** + * seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity. + * + * The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandages falls off and we're left with nothing. + * + * Arguments: + * * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?) + */ +/obj/item/bodypart/proc/seep_gauze(seep_amt = 0) + if(!current_gauze) + return + current_gauze.absorption_capacity -= seep_amt + current_gauze.update_appearance(UPDATE_NAME) + if(current_gauze.absorption_capacity > 0) + return + owner.visible_message( + span_danger("[current_gauze] on [owner]'s [name] falls away in rags."), + span_warning("[current_gauze] on your [name] falls away in rags."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + remove_gauze(drop_location()) + owner.update_damage_overlays() + +/** + * Helper for someone helping to remove our gauze + */ +/obj/item/bodypart/proc/help_remove_gauze(mob/living/helper) + if(!istype(helper)) + return + if(helper.incapacitated()) + return + if(!helper.can_perform_action(owner, NEED_HANDS|FORBID_TELEKINESIS_REACH)) // telekinetic removal can be added later + return + + var/whose = helper == owner ? "your" : "[owner]'s" + helper.visible_message( + span_notice("[helper] starts carefully removing [current_gauze] from [whose] [plaintext_zone]."), + span_notice("You start carefully removing [current_gauze] from [whose] [plaintext_zone]..."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + helper.balloon_alert(helper, "removing gauze...") + if(helper != owner) + helper.balloon_alert(owner, "removing your gauze...") + + if(!do_after(helper, 3 SECONDS, owner)) + return + + if(!current_gauze) + return + + var/theirs = helper == owner ? helper.p_their() : "[owner]'s" + helper.visible_message( + span_notice("[helper] finishes removing [current_gauze] from [theirs] [plaintext_zone]."), + span_notice("You finish removing [current_gauze] from [theirs] [plaintext_zone]."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + + helper.balloon_alert(helper, "gauzed removed") + if(helper != owner) + helper.balloon_alert(owner, "gauze removed") + + helper.put_in_hands(remove_gauze()) diff --git a/maplestation_modules/icons/mob/bandage.dmi b/maplestation_modules/icons/mob/bandage.dmi new file mode 100644 index 000000000000..24b65c9c48ef Binary files /dev/null and b/maplestation_modules/icons/mob/bandage.dmi differ diff --git a/maplestation_modules/sound/attribution.txt b/maplestation_modules/sound/attribution.txt index daf8aa0c80fa..7d52f1491f43 100644 --- a/maplestation_modules/sound/attribution.txt +++ b/maplestation_modules/sound/attribution.txt @@ -5,6 +5,7 @@ - jackboot2.ogg - cig_light.ogg - cig_snuff.ogg +- rip1.ogg through rip4.ogg - inhale.ogg - the contents of `item/ambience` - the contents of `item/drop` @@ -13,10 +14,14 @@ - the contents of `item/pickup` - all healthscanner_x.oggs -Have been ported from other stations, and given a lack of existing attribution, +Have been ported from other stations, and given a lack of existing attribution, are assumed to be CC-BY-SA 3.0 unless stated otherwise below -- device2.ogg +- device2.ogg -was sampled from https://freesound.org/people/Nagwense/sounds/535375/ -and is licensed under CC-BY-SA 4.0 \ No newline at end of file +was sampled from https://freesound.org/people/Nagwense/sounds/535375/ +and is licensed under CC-BY-SA 4.0 + +- snip.ogg + +from Scissor Snip 2 by Aesterial-Arts -- https://freesound.org/s/633925/ -- License: Attribution 4.0 diff --git a/maplestation_modules/sound/items/rip1.ogg b/maplestation_modules/sound/items/rip1.ogg new file mode 100644 index 000000000000..ab0fabbb3d69 Binary files /dev/null and b/maplestation_modules/sound/items/rip1.ogg differ diff --git a/maplestation_modules/sound/items/rip2.ogg b/maplestation_modules/sound/items/rip2.ogg new file mode 100644 index 000000000000..93a5cec50f8a Binary files /dev/null and b/maplestation_modules/sound/items/rip2.ogg differ diff --git a/maplestation_modules/sound/items/rip3.ogg b/maplestation_modules/sound/items/rip3.ogg new file mode 100644 index 000000000000..82d93582923e Binary files /dev/null and b/maplestation_modules/sound/items/rip3.ogg differ diff --git a/maplestation_modules/sound/items/rip4.ogg b/maplestation_modules/sound/items/rip4.ogg new file mode 100644 index 000000000000..32c594b688d7 Binary files /dev/null and b/maplestation_modules/sound/items/rip4.ogg differ diff --git a/maplestation_modules/sound/items/snip.ogg b/maplestation_modules/sound/items/snip.ogg new file mode 100644 index 000000000000..9f499b9a2abe Binary files /dev/null and b/maplestation_modules/sound/items/snip.ogg differ