diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm index 9845593c0847..70093efa0dbb 100644 --- a/code/__HELPERS/atoms.dm +++ b/code/__HELPERS/atoms.dm @@ -335,3 +335,6 @@ rough example of the "cone" made by the 3 dirs checked "x" = icon_width > world.icon_size && pixel_x != 0 ? (icon_width - world.icon_size) * 0.5 : 0, "y" = icon_height > world.icon_size && pixel_y != 0 ? (icon_height - world.icon_size) * 0.5 : 0, ) + +/// Helper for easily adding blood from INSIDE a mob to an atom (NOT blood ON the mob) +#define add_mob_blood(from_who) add_blood_DNA(from_who.get_blood_dna_list()) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index f17ce8ef9132..8f0e3b5bd8b5 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -347,7 +347,21 @@ attacking_item.add_mob_blood(src) add_splatter_floor(get_turf(src)) if(get_dist(attacker, src) <= 1) - attacker.add_mob_blood(src) + if(ishuman(attacker)) + var/bloodied_things = ITEM_SLOT_GLOVES + if(damage_done >= 20 || (damage_done >= 15 && prob(25))) + bloodied_things |= ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING + if(prob(33) && damage_done >= 10) + bloodied_things |= ITEM_SLOT_FEET + if(prob(33) && damage_done >= 24) // fireaxe damage, because heeeeere's johnny + bloodied_things |= ITEM_SLOT_MASK + if(prob(33) && damage_done >= 30) // esword damage + bloodied_things |= ITEM_SLOT_HEAD + + var/mob/living/carbon/human/human_attacker = attacker + human_attacker.add_blood_DNA_to_items(get_blood_dna_list(), bloodied_things) + else + attacker.add_mob_blood(src) return TRUE return FALSE @@ -376,15 +390,10 @@ switch(hit_zone) if(BODY_ZONE_HEAD) if(.) - if(wear_mask) - wear_mask.add_mob_blood(src) - update_worn_mask() - if(head) - head.add_mob_blood(src) - update_worn_head() - if(glasses && prob(33)) - glasses.add_mob_blood(src) - update_worn_glasses() + var/bloodied_things = ITEM_SLOT_MASK|ITEM_SLOT_HEAD + if(prob(33)) + bloodied_things |= ITEM_SLOT_EYES + add_blood_DNA_to_items(get_blood_dna_list(), bloodied_things) if(!attacking_item.get_sharpness() && armor_block < 50 && attacking_item.damtype == BRUTE) if(prob(damage_done)) @@ -409,12 +418,7 @@ if(BODY_ZONE_CHEST) if(.) - if(wear_suit) - wear_suit.add_mob_blood(src) - update_worn_oversuit() - if(w_uniform) - w_uniform.add_mob_blood(src) - update_worn_undersuit() + add_blood_DNA_to_items(get_blood_dna_list(), ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING) if(stat == CONSCIOUS && !attacking_item.get_sharpness() && armor_block < 50 && attacking_item.damtype == BRUTE) if(prob(damage_done)) diff --git a/code/datums/components/blood_walk.dm b/code/datums/components/blood_walk.dm index 873b204d2927..7bf15e4d6f54 100644 --- a/code/datums/components/blood_walk.dm +++ b/code/datums/components/blood_walk.dm @@ -88,8 +88,6 @@ // NON-MODULE CHANGE if(transfer_blood_dna) blood.add_blood_DNA(GET_ATOM_BLOOD_DNA(movable_source)) - // if(isliving(movable_source)) - // blood.transfer_mob_blood_dna(movable_source) if(!isnull(sound_played)) playsound(movable_source, sound_played, sound_volume, TRUE, 2, TRUE) diff --git a/code/datums/components/bloody_spreader.dm b/code/datums/components/bloody_spreader.dm index 571557ab2715..a4b9c75b3c69 100644 --- a/code/datums/components/bloody_spreader.dm +++ b/code/datums/components/bloody_spreader.dm @@ -32,8 +32,13 @@ /datum/component/bloody_spreader/proc/spread_yucky_blood(atom/parent, atom/bloody_fool) SIGNAL_HANDLER - bloody_fool.add_blood_DNA(blood_dna, diseases) - blood_left -= ishuman(bloody_fool) ? 3 : 1 + if(ishuman(bloody_fool)) + var/mob/living/carbon/human/bloody_fool_human = bloody_fool + bloody_fool_human.add_blood_DNA_to_items(blood_dna, ITEM_SLOT_GLOVES) + blood_left -= 3 + else + bloody_fool.add_blood_DNA(blood_dna, diseases) + blood_left -= 1 if(blood_left <= 0) qdel(src) diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm index 28df11c69ea3..cdef0567997d 100644 --- a/code/datums/components/bloodysoles.dm +++ b/code/datums/components/bloodysoles.dm @@ -96,8 +96,17 @@ pool.adjust_bloodiness(-1 * delta) change_blood_amount(delta) - var/atom/parent_atom = parent - parent_atom.add_blood_DNA(GET_ATOM_BLOOD_DNA(pool)) + if(ishuman(parent)) + var/bloody_slots = ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING|ITEM_SLOT_FEET + var/mob/living/carbon/human/to_bloody = parent + if(to_bloody.body_position == LYING_DOWN) + bloody_slots |= ITEM_SLOT_HEAD|ITEM_SLOT_MASK|ITEM_SLOT_GLOVES + + to_bloody.add_blood_DNA_to_items(GET_ATOM_BLOOD_DNA(pool), bloody_slots) + return + + var/atom/to_bloody = parent + to_bloody.add_blood_DNA(GET_ATOM_BLOOD_DNA(pool)) /** * Adds blood to an existing (or new) footprint diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index b8a6b995c77e..88792f64114b 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -502,25 +502,6 @@ // NON-MODULE CHANGE END -///to add a mob's dna info into an object's blood_dna list. -/atom/proc/transfer_mob_blood_dna(mob/living/injected_mob) - // Returns 0 if we have that blood already - var/new_blood_dna = injected_mob.get_blood_dna_list() - if(!new_blood_dna) - return FALSE - var/old_length = GET_ATOM_BLOOD_DNA_LENGTH(src) - add_blood_DNA(new_blood_dna) - if(GET_ATOM_BLOOD_DNA_LENGTH(src) == old_length) - return FALSE - return TRUE - -///to add blood from a mob onto something, and transfer their dna info -/atom/proc/add_mob_blood(mob/living/injected_mob) - var/list/blood_dna = injected_mob.get_blood_dna_list() - if(!blood_dna) - return FALSE - return add_blood_DNA(blood_dna) - ///Is this atom in space /atom/proc/isinspace() if(isspaceturf(get_turf(src))) diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index d15f9f663f6d..06dff2460cf9 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -431,12 +431,12 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) if(splatter_strength) src.splatter_strength = splatter_strength -/obj/effect/decal/cleanable/blood/hitsplatter/Destroy() +/obj/effect/decal/cleanable/blood/hitsplatter/proc/expire() if(isturf(loc) && !skip) playsound(src, 'sound/effects/wounds/splatter.ogg', 60, TRUE, -1) if(blood_dna_info) loc.add_blood_DNA(blood_dna_info) - return ..() + qdel(src) /// Set the splatter up to fly through the air until it rounds out of steam or hits something /obj/effect/decal/cleanable/blood/hitsplatter/proc/fly_towards(turf/target_turf, range) @@ -452,42 +452,35 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) /obj/effect/decal/cleanable/blood/hitsplatter/proc/post_move(datum/move_loop/source) SIGNAL_HANDLER - for(var/atom/iter_atom in get_turf(src)) + for(var/atom/movable/iter_atom in loc) if(hit_endpoint) return + if(iter_atom == src || iter_atom.invisibility || iter_atom.alpha <= 0 || (isobj(iter_atom) && !iter_atom.density)) + continue if(splatter_strength <= 0) break - if(isitem(iter_atom)) - iter_atom.add_blood_DNA(blood_dna_info) - splatter_strength-- - else if(ishuman(iter_atom)) - var/mob/living/carbon/human/splashed_human = iter_atom - if(splashed_human.wear_suit) - splashed_human.wear_suit.add_blood_DNA(blood_dna_info) - splashed_human.update_worn_oversuit() //updates mob overlays to show the new blood (no refresh) - if(splashed_human.w_uniform) - splashed_human.w_uniform.add_blood_DNA(blood_dna_info) - splashed_human.update_worn_undersuit() //updates mob overlays to show the new blood (no refresh) - splatter_strength-- + iter_atom.add_blood_DNA(blood_dna_info) + splatter_strength-- + if(splatter_strength <= 0) // we used all the puff so we delete it. - qdel(src) + expire() /obj/effect/decal/cleanable/blood/hitsplatter/proc/loop_done(datum/source) SIGNAL_HANDLER if(!QDELETED(src)) - qdel(src) + expire() /obj/effect/decal/cleanable/blood/hitsplatter/Bump(atom/bumped_atom) if(!iswallturf(bumped_atom) && !istype(bumped_atom, /obj/structure/window)) - qdel(src) + expire() return if(istype(bumped_atom, /obj/structure/window)) var/obj/structure/window/bumped_window = bumped_atom if(!bumped_window.fulltile) hit_endpoint = TRUE - qdel(src) + expire() return hit_endpoint = TRUE @@ -505,7 +498,7 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) final_splatter.add_blood_DNA(blood_dna_info) else // This will only happen if prev_loc is not even a turf, which is highly unlikely. abstract_move(bumped_atom) - qdel(src) + expire() /// A special case for hitsplatters hitting windows, since those can actually be moved around, store it in the window and slap it in the vis_contents /obj/effect/decal/cleanable/blood/hitsplatter/proc/land_on_window(obj/structure/window/the_window) @@ -517,4 +510,4 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) final_splatter.forceMove(the_window) the_window.vis_contents += final_splatter the_window.bloodied = TRUE - qdel(src) + expire() diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 9c5b6a10ec9d..70223cc42d60 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -369,7 +369,7 @@ C.visible_message(span_danger("[H] impales [C] with [H.p_their()] [I.name]!"), span_userdanger("[H] impales you with [H.p_their()] [I.name]!")) C.apply_damage(I.force, BRUTE, BODY_ZONE_CHEST, attacking_item = I) H.do_item_attack_animation(C, used_item = I) - H.add_mob_blood(C) + H.add_blood_DNA_to_items(C.get_blood_dna_list(), ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING) playsound(get_turf(H),I.hitsound,75,TRUE) return diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm index 2d0dfb43c0ca..54aa50ccde9f 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -6,7 +6,7 @@ righthand_file = 'icons/mob/inhands/clothing/hats_righthand.dmi' body_parts_covered = HEAD slot_flags = ITEM_SLOT_HEAD - blood_overlay_type = "helmetblood" // NON-MODULE CHANGE reworking clothing blood overlays + blood_overlay_type = "helmet" // NON-MODULE CHANGE reworking clothing blood overlays drop_sound = 'maplestation_modules/sound/items/pickup/hat.ogg' pickup_sound = 'maplestation_modules/sound/items/pickup/hat.ogg' diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm index ae4e873c0064..08f8a753d311 100644 --- a/code/modules/forensics/forensics_helpers.dm +++ b/code/modules/forensics/forensics_helpers.dm @@ -150,27 +150,57 @@ /turf/closed/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) return FALSE +/obj/item/clothing/under/add_blood_DNA(list/blood_DNA_to_add) + . = ..() + if(!.) + return + for(var/obj/item/clothing/accessory/thing_accessory as anything in attached_accessories) + if(prob(66)) + continue + thing_accessory.add_blood_DNA(blood_DNA_to_add) + /mob/living/carbon/human/add_blood_DNA(list/blood_DNA_to_add, list/datum/disease/diseases) + return add_blood_DNA_to_items(blood_DNA_to_add) + +/// Adds blood DNA to certain slots the mob is wearing +/mob/living/carbon/human/proc/add_blood_DNA_to_items( + list/blood_DNA_to_add, + target_flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING|ITEM_SLOT_GLOVES|ITEM_SLOT_HEAD|ITEM_SLOT_MASK, +) if(QDELING(src)) return FALSE if(!length(blood_DNA_to_add)) return FALSE - if(wear_suit) - wear_suit.add_blood_DNA(blood_DNA_to_add) - update_worn_oversuit() - else if(w_uniform) - w_uniform.add_blood_DNA(blood_DNA_to_add) - update_worn_undersuit() - if(gloves) - var/obj/item/clothing/gloves/mob_gloves = gloves - mob_gloves.add_blood_DNA(blood_DNA_to_add) - else if(length(blood_DNA_to_add)) - if (isnull(forensics)) + + // Don't messy up our jumpsuit if we're got a coat + if((target_flags & ITEM_SLOT_OCLOTHING) && (wear_suit?.body_parts_covered & CHEST)) + target_flags &= ~ITEM_SLOT_ICLOTHING + + var/dirty_hands = !!(target_flags & (ITEM_SLOT_GLOVES|ITEM_SLOT_HANDS)) + var/dirty_feet = !!(target_flags & ITEM_SLOT_FEET) + var/slots_to_bloody = target_flags & ~check_obscured_slots() + var/list/all_worn = get_equipped_items() + for(var/obj/item/thing as anything in all_worn) + if(thing.slot_flags & slots_to_bloody) + thing.add_blood_DNA(blood_DNA_to_add) + if(thing.body_parts_covered & HANDS) + dirty_hands = FALSE + if(thing.body_parts_covered & FEET) + dirty_feet = FALSE + + if(slots_to_bloody & ITEM_SLOT_HANDS) + for(var/obj/item/thing in held_items) + thing.add_blood_DNA(blood_DNA_to_add) + + if(dirty_hands || dirty_feet || !length(all_worn)) + if(isnull(forensics)) forensics = new(src) forensics.inherit_new(blood_DNA = blood_DNA_to_add) - blood_in_hands = rand(2, 4) + if(dirty_hands) + blood_in_hands = rand(2, 4) + cached_blood_dna_color = null - update_worn_gloves() + update_clothing(slots_to_bloody) return TRUE /mob/living/add_blood_DNA(list/blood_DNA_to_add) @@ -181,6 +211,7 @@ if(isnull(forensics)) forensics = new(src) forensics.inherit_new(blood_DNA = blood_DNA_to_add) + cached_blood_dna_color = null return TRUE /* diff --git a/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm b/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm index 7c35184af371..0ac65ea6ad48 100644 --- a/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm +++ b/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm @@ -33,6 +33,8 @@ ) /// A specified wizard corpse spawner to use. If null, picks from the list above instead. var/selected_outfit + /// What's our "blood type"? So fake-humans splash blood on people in combat + var/fake_blood_type /// Typepath for the wizard's targeted spell. If null, selects randomly. var/targeted_spell_path @@ -83,6 +85,11 @@ blink_spell.Grant(src) ai_controller.set_blackboard_key(BB_WIZARD_BLINK_SPELL, blink_spell) +/mob/living/basic/wizard/get_blood_type() + if(!fake_blood_type) + fake_blood_type = random_human_blood_type() + return GLOB.blood_types[fake_blood_type] + /// Uses the colors and loadout of the original wizard simplemob /mob/living/basic/wizard/classic selected_outfit = /obj/effect/mob_spawn/corpse/human/wizard diff --git a/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm b/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm index 02faf7c2cc9f..5b454ded6a86 100644 --- a/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm +++ b/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm @@ -36,6 +36,8 @@ /obj/effect/mob_spawn/corpse/human/cat_butcher, /obj/item/circular_saw, ) + /// What's our "blood type"? So fake-humans splash blood on people in combat + var/fake_blood_type /mob/living/basic/cat_butcherer/Initialize(mapload) . = ..() @@ -44,6 +46,11 @@ AddElement(/datum/element/death_drops, drop_on_death) RegisterSignal(src, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(after_attack)) +/mob/living/basic/cat_butcherer/get_blood_type() + if(!fake_blood_type) + fake_blood_type = random_human_blood_type() + return GLOB.blood_types[fake_blood_type] + /mob/living/basic/cat_butcherer/proc/after_attack(mob/living/basic/attacker, atom/target) SIGNAL_HANDLER diff --git a/code/modules/mob/living/basic/trooper/abductor.dm b/code/modules/mob/living/basic/trooper/abductor.dm index fdb8b41cc5ec..3eaab8cc37f0 100644 --- a/code/modules/mob/living/basic/trooper/abductor.dm +++ b/code/modules/mob/living/basic/trooper/abductor.dm @@ -6,6 +6,9 @@ loot = list(/obj/effect/mob_spawn/corpse/human/abductor) mob_spawner = /obj/effect/mob_spawn/corpse/human/abductor +/mob/living/basic/trooper/abductor/get_blood_type() + return null // Ayys are noblooded + /mob/living/basic/trooper/abductor/melee melee_damage_lower = 15 melee_damage_upper = 15 diff --git a/code/modules/mob/living/basic/trooper/trooper.dm b/code/modules/mob/living/basic/trooper/trooper.dm index 1886c8fc2ff5..5d7a77cb721a 100644 --- a/code/modules/mob/living/basic/trooper/trooper.dm +++ b/code/modules/mob/living/basic/trooper/trooper.dm @@ -26,6 +26,8 @@ var/r_hand /// Path of the left hand held item we give to the mob's visuals. var/l_hand + /// What's our "blood type"? So fake-humans splash blood on people in combat + var/fake_blood_type /mob/living/basic/trooper/Initialize(mapload) . = ..() @@ -34,3 +36,8 @@ loot = string_list(loot) AddElement(/datum/element/death_drops, loot) AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_SHOE) + +/mob/living/basic/trooper/get_blood_type() + if(!fake_blood_type) + fake_blood_type = random_human_blood_type() + return GLOB.blood_types[fake_blood_type] diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 7ff1af4294f6..58df9bb19bf3 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -266,6 +266,14 @@ return null return GLOB.blood_types[/datum/blood_type/animal] +/mob/living/basic/get_blood_type() + // All basic mobs are noblood but we should still pretend + return GLOB.blood_types[/datum/blood_type/animal] + +/mob/living/simple_animal/get_blood_type() + // Same here + return GLOB.blood_types[/datum/blood_type/animal] + /mob/living/silicon/get_blood_type() return GLOB.blood_types[/datum/blood_type/oil] @@ -275,6 +283,9 @@ /mob/living/basic/bot/get_blood_type() return GLOB.blood_types[/datum/blood_type/oil] +/mob/living/basic/drone/get_blood_type() + return GLOB.blood_types[/datum/blood_type/oil] + /mob/living/carbon/alien/get_blood_type() if(HAS_TRAIT(src, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_NOBLOOD)) return null diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 1a84a3ebcd7c..e4516eb4d22a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1428,7 +1428,7 @@ /mob/living/carbon/proc/spray_blood(splatter_direction, splatter_strength = 3) if(!isturf(loc)) return - var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc) + var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc, splatter_strength) our_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) our_splatter.blood_dna_info = get_blood_dna_list() var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 89183f095f45..d60998b0204c 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -291,6 +291,23 @@ else Knockdown(stun_duration) +/// When another mob touches us, they may messy us up. +/mob/living/carbon/proc/share_blood_on_touch(mob/living/carbon/human/who_touched_us) + return + +/mob/living/carbon/human/share_blood_on_touch(mob/living/carbon/human/who_touched_us, messy_slots = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING) + if(!istype(who_touched_us) || !messy_slots) + return + + for(var/obj/item/thing as anything in who_touched_us.get_equipped_items()) + if((thing.body_parts_covered & HANDS) && prob(GET_ATOM_BLOOD_DNA_LENGTH(thing) * 25)) + add_blood_DNA_to_items(GET_ATOM_BLOOD_DNA(who_touched_us.wear_suit), messy_slots) + return + + if(prob(blood_in_hands * GET_ATOM_BLOOD_DNA_LENGTH(who_touched_us) * 10)) + add_blood_DNA_to_items(GET_ATOM_BLOOD_DNA(who_touched_us), messy_slots) + who_touched_us.blood_in_hands -= 1 + /mob/living/carbon/proc/help_shake_act(mob/living/carbon/helper) if(on_fire) to_chat(helper, span_warning("You can't put [p_them()] out with just your bare hands!")) @@ -311,12 +328,14 @@ null, span_hear("You hear the rustling of clothes."), DEFAULT_MESSAGE_RANGE, list(helper, src)) to_chat(helper, span_notice("You shake [src] trying to pick [p_them()] up!")) to_chat(src, span_notice("[helper] shakes you to get you up!")) + share_blood_on_touch(helper, ITEM_SLOT_HEAD|ITEM_SLOT_MASK) + else if(check_zone(helper.zone_selected) == BODY_ZONE_HEAD && get_bodypart(BODY_ZONE_HEAD)) //Headpats! helper.visible_message(span_notice("[helper] gives [src] a pat on the head to make [p_them()] feel better!"), \ null, span_hear("You hear a soft patter."), DEFAULT_MESSAGE_RANGE, list(helper, src)) to_chat(helper, span_notice("You give [src] a pat on the head to make [p_them()] feel better!")) to_chat(src, span_notice("[helper] gives you a pat on the head to make you feel better! ")) - + share_blood_on_touch(helper, ITEM_SLOT_HEAD|ITEM_SLOT_MASK) if(HAS_TRAIT(src, TRAIT_BADTOUCH)) to_chat(helper, span_warning("[src] looks visibly upset as you pat [p_them()] on the head.")) @@ -353,6 +372,7 @@ to_chat(helper, span_notice("You hug [src] to make [p_them()] feel better!")) to_chat(src, span_notice("[helper] hugs you to make you feel better!")) + share_blood_on_touch(helper, ITEM_SLOT_HEAD|ITEM_SLOT_MASK|ITEM_SLOT_GLOVES) // Warm them up with hugs share_bodytemperature(helper) diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index cebeab7cfcd3..5cbc3072877a 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -332,15 +332,20 @@ 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) continue - if(isnull(damage_overlay) && (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 || 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 if(isnull(damage_overlay)) return 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 3431e22150ac..fa96a721c8c7 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -845,21 +845,22 @@ generate/load female uniform sprites matching all previously decided variables return appearance -/obj/item/proc/apply_digitigrade_filters(mutable_appearance/appearance) - var/mob/living/carbon/human/wearer = loc +/obj/item/proc/apply_digitigrade_filters(mutable_appearance/appearance, mob/living/carbon/human/wearer = loc) if(!istype(wearer) || !(wearer.bodytype & BODYTYPE_DIGITIGRADE) || wearer.is_digitigrade_squished()) return - var/list/icon/masks_and_shading + var/static/list/icon/masks_and_shading if(isnull(masks_and_shading)) masks_and_shading = list( "[NORTH]" = list( "mask" = icon('icons/effects/digi_filters.dmi', "digi", NORTH), "shading" = icon('icons/effects/digi_filters.dmi', "digi_shading", NORTH), + "size" = 1, ), "[SOUTH]" = list( "mask" = icon('icons/effects/digi_filters.dmi', "digi", SOUTH), "shading" = icon('icons/effects/digi_filters.dmi', "digi_shading", SOUTH), + "size" = 1, ), "[EAST]" = list( "mask" = icon('icons/effects/digi_filters.dmi', "digi", EAST), @@ -876,10 +877,9 @@ generate/load female uniform sprites matching all previously decided variables var/dir_to_use = ISDIAGONALDIR(wearer.dir) ? (wearer.dir & (EAST|WEST)) : wearer.dir var/icon/icon_to_use = masks_and_shading["[dir_to_use]"]["mask"] var/icon/shading_to_use = masks_and_shading["[dir_to_use]"]["shading"] - var/size = masks_and_shading["[dir_to_use]"]["size"] || 1 + var/size = masks_and_shading["[dir_to_use]"]["size"] appearance.add_filter("Digitigrade", 1, displacement_map_filter(icon = icon_to_use, size = size)) - if(!isnull(shading_to_use)) - appearance.add_filter("Digitigrade_shading", 1, layering_filter(icon = shading_to_use, blend_mode = BLEND_MULTIPLY)) + appearance.add_filter("Digitigrade_shading", 1, layering_filter(icon = shading_to_use, blend_mode = BLEND_MULTIPLY)) #undef RESOLVE_ICON_STATE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index eb5584373ce3..b06ccddf5876 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -395,6 +395,7 @@ M.visible_message(span_warning("[src] grabs [M] [grabbed_by_hands ? "by their hands":"passively"]!"), \ span_warning("[src] grabs you [grabbed_by_hands ? "by your hands":"passively"]!"), null, null, src) to_chat(src, span_notice("You grab [M] [grabbed_by_hands ? "by their hands":"passively"]!")) + grabbed_human.share_blood_on_touch(src, grabbed_by_hands ? ITEM_SLOT_GLOVES : ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING) else M.visible_message(span_warning("[src] grabs [M] passively!"), \ span_warning("[src] grabs you passively!"), null, null, src) @@ -1056,7 +1057,7 @@ if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) TH.existing_dirs += newdir TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir)) - TH.transfer_mob_blood_dna(src) + TH.add_mob_blood(src) // NON-MODULE CHANGE /mob/living/carbon/human/makeTrail(turf/target_turf, turf/start, direction) diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm index f16449764de7..7b5f8c00c4a8 100644 --- a/code/modules/mob/living/simple_animal/hostile/zombie.dm +++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm @@ -26,11 +26,18 @@ var/infection_chance = 0 /// Outfit the zombie spawns with for visuals. var/outfit = /datum/outfit/corpse_doctor + /// What's our "blood type"? So fake-humans splash blood on people in combat + var/fake_blood_type /mob/living/simple_animal/hostile/zombie/Initialize(mapload) . = ..() apply_dynamic_human_appearance(src, outfit, /datum/species/zombie, bloody_slots = ITEM_SLOT_OCLOTHING) +/mob/living/simple_animal/hostile/zombie/get_blood_type() + if(!fake_blood_type) + fake_blood_type = random_human_blood_type() + return GLOB.blood_types[fake_blood_type] + /mob/living/simple_animal/hostile/zombie/AttackingTarget(atom/attacked_target) . = ..() if(. && ishuman(target) && prob(infection_chance)) diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index f19fa87dba07..15418cb6b459 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -13,7 +13,7 @@ . = ..() if(!isnull(blood_type)) var/datum/blood_type/blood = GLOB.blood_types[blood_type] - reagents.add_reagent(blood.reagent_type, 200, list("viruses" = null,"blood_DNA" = null,"blood_type" = blood_type, "resistances" = null, "trace_chem" = null)) + reagents.add_reagent(blood.reagent_type, 200, list("blood_type" = blood_type)) update_appearance() /// Handles updating the container when the reagents change. @@ -26,8 +26,7 @@ else for(var/blood_type in GLOB.blood_types) - var/datum/blood_type/blood = GLOB.blood_types[blood_type] - if(blood.reagent_type == master_reagent.type) + if(GLOB.blood_types[blood_type].reagent_type == master_reagent.type) blood_type = blood_type break diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index cafa1161693a..daf9e22ecd78 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -166,6 +166,11 @@ span_notice("[user] succeeds!"), span_notice("[user] finishes."), ) + if(ishuman(user)) + var/mob/living/carbon/human/surgeon = user + surgeon.add_blood_DNA_to_items(target.get_blood_dna_list(), ITEM_SLOT_GLOVES) + else + user.add_mob_blood(target) return TRUE /datum/surgery_step/proc/play_success_sound(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) diff --git a/maplestation_modules/code/game/objects/items/weaponry.dm b/maplestation_modules/code/game/objects/items/weaponry.dm index 604831ed4742..b8c699e47dec 100644 --- a/maplestation_modules/code/game/objects/items/weaponry.dm +++ b/maplestation_modules/code/game/objects/items/weaponry.dm @@ -65,6 +65,7 @@ light_range = 2 light_power = 1 light_on = FALSE + item_flags = NO_BLOOD_ON_ITEM ///force when active, passed onto component/transforming var/active_force = 18 ///throwforce when active, passed onto component/transforming diff --git a/maplestation_modules/code/modules/mob/living/blood.dm b/maplestation_modules/code/modules/mob/living/blood.dm index 2e47b6f239f5..366896e36a33 100644 --- a/maplestation_modules/code/modules/mob/living/blood.dm +++ b/maplestation_modules/code/modules/mob/living/blood.dm @@ -14,9 +14,9 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) /// Takes the name of a blood type and return the typepath /proc/blood_name_to_blood_type(name) - for(var/datum/blood_type/blood_type as anything in GLOB.blood_types) - if(blood_type.name == name) - return blood_type.type + for(var/blood_type in GLOB.blood_types) + if(GLOB.blood_types[blood_type].name == name) + return blood_type return null /** @@ -41,6 +41,13 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) . = ..() compatible_types |= type +/datum/blood_type/Destroy(force) + if(!force) + stack_trace("qdel called on blood type singleton! (use FORCE if necessary)") + return QDEL_HINT_LETMELIVE + + return ..() + /// Gets data to pass to a reagent /datum/blood_type/proc/get_blood_data(mob/living/sampled_from) return null @@ -82,12 +89,12 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) splatter.adjust_bloodiness(new_blood) splatter.drying_progress -= (new_blood * BLOOD_PER_UNIT_MODIFIER) splatter.update_blood_drying_effect() - splatter.transfer_mob_blood_dna(bleeding) + splatter.add_mob_blood(bleeding) return splatter drop = new(blood_turf, bleeding.get_static_viruses()) if(!QDELETED(drop)) - drop.transfer_mob_blood_dna(bleeding) + drop.add_mob_blood(bleeding) drop.random_icon_states -= drop.icon_state return drop @@ -99,11 +106,11 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) new_drop.color = color new_drop.vis_flags |= (VIS_INHERIT_LAYER|VIS_INHERIT_PLANE|VIS_INHERIT_ID) new_drop.appearance_flags |= (RESET_COLOR) - new_drop.transfer_mob_blood_dna(bleeding) + new_drop.add_mob_blood(bleeding) drop.vis_contents += new_drop // Handle adding blood to the base atom drop.adjust_bloodiness(new_blood) - drop.transfer_mob_blood_dna(bleeding) + drop.add_mob_blood(bleeding) return drop temp_blood_DNA = GET_ATOM_BLOOD_DNA(drop) //we transfer the dna from the drip to the splatter @@ -119,7 +126,7 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) splatter.adjust_bloodiness(BLOOD_AMOUNT_PER_DECAL) splatter.drying_progress -= (BLOOD_AMOUNT_PER_DECAL * BLOOD_PER_UNIT_MODIFIER) splatter.update_blood_drying_effect() - splatter.transfer_mob_blood_dna(bleeding) //give blood info to the blood decal. + splatter.add_mob_blood(bleeding) //give blood info to the blood decal. if(LAZYLEN(temp_blood_DNA)) splatter.add_blood_DNA(temp_blood_DNA) return splatter