Skip to content

Commit

Permalink
Merge pull request #4695 from MistakeNot4892/feature/yuck
Browse files Browse the repository at this point in the history
Vomit and mud can now be tracked around the floor.
  • Loading branch information
out-of-phaze authored Jan 7, 2025
2 parents 8be5534 + 7679349 commit 102483c
Show file tree
Hide file tree
Showing 22 changed files with 150 additions and 101 deletions.
11 changes: 10 additions & 1 deletion code/_helpers/global_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,13 @@ var/global/list/bodytype_species_pairs = list() // A list of bodytypes -> specie
. = global.playable_species
/proc/get_bodytype_species_pairs()
build_species_lists()
. = global.bodytype_species_pairs
. = global.bodytype_species_pairs

// Used to avoid constantly generating new lists during movement.
var/global/list/all_stance_limbs = list(
ORGAN_CATEGORY_STANCE,
ORGAN_CATEGORY_STANCE_ROOT
)
var/global/list/child_stance_limbs = list(
ORGAN_CATEGORY_STANCE
)
26 changes: 6 additions & 20 deletions code/game/objects/effects/decals/Cleanable/humans.dm
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,12 @@
/obj/effect/decal/cleanable/blood/Crossed(atom/movable/AM)
if(!isliving(AM) || amount < 1)
return

var/mob/living/M = AM
var/obj/item/organ/external/l_foot = GET_EXTERNAL_ORGAN(M, BP_L_FOOT)
var/obj/item/organ/external/r_foot = GET_EXTERNAL_ORGAN(M, BP_R_FOOT)
var/hasfeet = l_foot && r_foot

var/transferred_data = blood_data ? blood_data[pick(blood_data)] : null
var/obj/item/clothing/shoes/shoes = M.get_equipped_item(slot_shoes_str)
if(istype(shoes) && !M.buckled)//Adding blood to shoes
shoes.add_coating(chemical, amount, transferred_data)
else if (hasfeet)//Or feet
if(l_foot)
l_foot.add_coating(chemical, amount, transferred_data)
if(r_foot)
r_foot.add_coating(chemical, amount, transferred_data)
else if (M.buckled && istype(M.buckled, /obj/structure/bed/chair/wheelchair))
var/obj/structure/bed/chair/wheelchair/W = M.buckled
W.bloodiness = 4

M.update_equipment_overlay(slot_shoes_str)
var/mob/living/walker = AM
if(istype(walker.buckled, /obj/structure/bed/chair/wheelchair))
var/obj/structure/bed/chair/wheelchair/wheelchair = walker.buckled
wheelchair.bloodiness = 4
else
walker.add_walking_contaminant(chemical, amount, (blood_data ? blood_data[pick(blood_data)] : null))
amount--

/obj/effect/decal/cleanable/blood/proc/dry()
Expand Down
13 changes: 12 additions & 1 deletion code/game/objects/effects/decals/Cleanable/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,20 @@
if(prob(75))
set_rotation(pick(90, 180, 270))

/obj/effect/decal/cleanable/vomit/mapped/Initialize(ml, _age)
. = ..()
add_to_reagents(/decl/material/liquid/acid/stomach, rand(3,5))
add_to_reagents(/decl/material/liquid/nutriment, rand(5,8))

/obj/effect/decal/cleanable/vomit/on_update_icon()
. = ..()
color = reagents.get_color()
color = reagents?.get_color()

/obj/effect/decal/cleanable/vomit/Crossed(atom/movable/AM)
. = ..()
if(!QDELETED(src) && reagents?.total_volume >= 1 && isliving(AM))
var/mob/living/walker = AM
walker.add_walking_contaminant(reagents, rand(2, 3))

/obj/effect/decal/cleanable/tomato_smudge
name = "tomato smudge"
Expand Down
45 changes: 24 additions & 21 deletions code/game/objects/items/__item.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
/// Set to false to skip state checking and never draw an icon on the mob (except when held)
var/draw_on_mob_when_equipped = TRUE

var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
/// this saves our blood splatter/coating overlay, which will be processed not to go over the edges of the sprite.
var/image/coating_overlay
var/randpixel = 6
var/material_health_multiplier = 0.2
var/hitsound
Expand Down Expand Up @@ -245,7 +246,7 @@
/obj/item/PopulateClone(obj/item/clone)
clone = ..()
clone.contaminated = contaminated
clone.blood_overlay = image(blood_overlay)
clone.coating_overlay = image(coating_overlay)
clone.current_health = current_health

//#TODO: once item damage in, check health!
Expand Down Expand Up @@ -790,7 +791,7 @@
if(was_bloodied && !fluorescent)
fluorescent = FLUORESCENT_GLOWS
blood_color = COLOR_LUMINOL
blood_overlay.color = COLOR_LUMINOL
coating_overlay.color = COLOR_LUMINOL
update_icon()

/obj/item/add_blood(mob/living/M, amount = 2, list/blood_data)
Expand All @@ -814,21 +815,21 @@
LAZYSET(blood_DNA, unique_enzymes, blood_type)
return TRUE

var/global/list/_blood_overlay_cache = list()
var/global/icon/_item_blood_mask = icon('icons/effects/blood.dmi', "itemblood")
/obj/item/proc/generate_blood_overlay(force = FALSE)
if(blood_overlay && !force)
var/global/list/_coating_overlay_cache = list()
var/global/icon/_item_coating_mask = icon('icons/effects/blood.dmi', "itemblood")
/obj/item/proc/generate_coating_overlay(force = FALSE)
if(coating_overlay && !force)
return
var/cache_key = "[icon]-[icon_state]"
if(global._blood_overlay_cache[cache_key])
blood_overlay = global._blood_overlay_cache[cache_key]
if(global._coating_overlay_cache[cache_key])
coating_overlay = global._coating_overlay_cache[cache_key]
return
var/icon/I = new /icon(icon, icon_state)
I.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) // Sets the icon RGB channel to pure white.
I.Blend(global._item_blood_mask, ICON_MULTIPLY) // Masks the blood overlay against the generated mask.
blood_overlay = image(I)
blood_overlay.appearance_flags |= NO_CLIENT_COLOR|RESET_COLOR
global._blood_overlay_cache[cache_key] = blood_overlay
I.Blend(global._item_coating_mask, ICON_MULTIPLY) // Masks the coating overlay against the generated mask.
coating_overlay = image(I)
coating_overlay.appearance_flags |= NO_CLIENT_COLOR|RESET_COLOR
global._coating_overlay_cache[cache_key] = coating_overlay

/obj/item/proc/showoff(mob/user)
for(var/mob/M in view(user))
Expand Down Expand Up @@ -1018,13 +1019,15 @@ modules/mob/living/human/life.dm if you die, you will be zoomed out.

/obj/item/proc/add_coating(reagent_type, amount, data)
if(!coating)
coating = new/datum/reagents(10, src)
coating.add_reagent(reagent_type, amount, data)

if(!blood_overlay)
generate_blood_overlay()
blood_overlay.color = coating.get_color()

coating = new /datum/reagents(10, src)
if(ispath(reagent_type))
coating.add_reagent(reagent_type, amount, data)
else if(istype(reagent_type, /datum/reagents))
var/datum/reagents/source = reagent_type
source.trans_to_holder(coating, amount)
if(!coating_overlay)
generate_coating_overlay()
coating_overlay.color = coating.get_color()
update_icon()

/obj/item/proc/remove_coating(amount)
Expand All @@ -1037,7 +1040,7 @@ modules/mob/living/human/life.dm if you die, you will be zoomed out.
/obj/item/clean(clean_forensics=TRUE)
. = ..()
QDEL_NULL(coating)
blood_overlay = null
coating_overlay = null
if(clean_forensics)
var/datum/extension/forensic_evidence/forensics = get_extension(src, /datum/extension/forensic_evidence)
if(forensics)
Expand Down
4 changes: 2 additions & 2 deletions code/game/objects/items/_item_materials.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
if((material_alteration & MAT_FLAG_ALTERATION_COLOR) && material)
alpha = 100 + material.opacity * 255
color = get_color() // avoiding set_color() here as that will set it on paint_color
if(blood_overlay)
add_overlay(blood_overlay)
if(coating_overlay)
add_overlay(coating_overlay)
if(global.contamination_overlay && contaminated)
add_overlay(global.contamination_overlay)

Expand Down
4 changes: 2 additions & 2 deletions code/game/objects/items/weapons/swords_axes_etc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
update_held_icon()

/obj/item/telebaton/on_update_icon()
if(length(blood_DNA))
generate_blood_overlay(TRUE) // Force recheck.
if(coating?.total_volume || blood_DNA)
generate_coating_overlay(TRUE) // Force recheck.
. = ..()
if(on)
icon = 'icons/obj/items/weapon/telebaton_extended.dmi'
Expand Down
6 changes: 6 additions & 0 deletions code/game/turfs/flooring/_flooring.dm
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,9 @@ var/global/list/flooring_cache = list()

/decl/flooring/proc/handle_turf_digging(turf/floor/target)
return TRUE

/decl/flooring/proc/turf_crossed(atom/movable/crosser)
return

/decl/flooring/proc/can_show_footsteps(turf/target)
return TRUE
9 changes: 9 additions & 0 deletions code/game/turfs/flooring/flooring_mud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
return
return ..()

/decl/flooring/mud/turf_crossed(atom/movable/crosser)
if(!isliving(crosser))
return
var/mob/living/walker = crosser
walker.add_walking_contaminant(/decl/material/solid/soil, rand(2,3))

/decl/flooring/mud/can_show_footsteps(turf/target)
return FALSE // So we don't end up covered in a million footsteps that we provided.

/decl/flooring/dry_mud
name = "dry mud"
desc = "This was once mud, but forgot to keep hydrated."
Expand Down
8 changes: 8 additions & 0 deletions code/game/turfs/floors/_floor.dm
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,11 @@
/turf/floor/get_plant_growth_rate()
var/decl/flooring/flooring = get_topmost_flooring()
return flooring ? flooring.growth_value : ..()

/turf/floor/Crossed(atom/movable/AM)
var/decl/flooring/flooring = get_topmost_flooring()
flooring?.turf_crossed(AM)
return ..()

/turf/floor/can_show_footsteps()
return ..() && get_topmost_flooring()?.can_show_footsteps(src)
3 changes: 3 additions & 0 deletions code/game/turfs/turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,9 @@
if(IS_HOE(held) && can_dig_farm(held.material?.hardness))
LAZYDISTINCTADD(., /decl/interaction_handler/dig/farm)

/turf/proc/can_show_footsteps()
return simulated

/decl/interaction_handler/show_turf_contents
name = "Show Turf Contents"
expected_user_type = /mob
Expand Down
7 changes: 4 additions & 3 deletions code/modules/detectivework/tools/uvlight.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
add_overlay(emissive_overlay(icon, "[icon_state]-on"))
z_flags |= ZMM_MANGLE_PLANES

// TODO: does this even work with SSoverlays?
/obj/item/uv_light/proc/clear_last_scan()
if(scanned.len)
for(var/atom/O in scanned)
Expand All @@ -62,7 +63,7 @@
stored_alpha.Cut()
if(reset_objects.len)
for(var/obj/item/I in reset_objects)
I.overlays -= I.blood_overlay
I.overlays -= I.coating_overlay
if(I.fluorescent == FLUORESCENT_GLOWING)
I.fluorescent = FLUORESCENT_GLOWS
reset_objects.Cut()
Expand All @@ -86,6 +87,6 @@
A.alpha = use_alpha
if(istype(A, /obj/item))
var/obj/item/O = A
if(O.was_bloodied && !(O.blood_overlay in O.overlays))
O.overlays |= O.blood_overlay
if(O.was_bloodied && !(O.coating_overlay in O.overlays))
O.overlays |= O.coating_overlay
reset_objects |= O
34 changes: 0 additions & 34 deletions code/modules/mob/living/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1071,40 +1071,6 @@
var/datum/appearance_descriptor/age = LAZYACCESS(bodytype.appearance_descriptors, "age")
LAZYSET(appearance_descriptors, "age", (age ? age.sanitize_value(val) : 30))

/mob/living/human/HandleBloodTrail(turf/T, old_loc)
// Tracking blood
var/obj/item/source
var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str)
if(istype(shoes))
shoes.handle_movement(src, MOVING_QUICKLY(src))
if(shoes.coating && shoes.coating.total_volume > 1)
source = shoes
else
for(var/foot_tag in list(BP_L_FOOT, BP_R_FOOT))
var/obj/item/organ/external/stomper = GET_EXTERNAL_ORGAN(src, foot_tag)
if(stomper && stomper.coating && stomper.coating.total_volume > 1)
source = stomper
if(!source)
species.handle_trail(src, T, old_loc)
return

var/list/bloodDNA
var/bloodcolor
var/list/blood_data = REAGENT_DATA(source.coating, /decl/material/liquid/blood)
if(blood_data)
bloodDNA = list(blood_data[DATA_BLOOD_DNA] = blood_data[DATA_BLOOD_TYPE])
else
bloodDNA = list()
bloodcolor = source.coating.get_color()
source.remove_coating(1)
update_equipment_overlay(slot_shoes_str)

if(species.get_move_trail(src))
T.AddTracks(species.get_move_trail(src),bloodDNA, dir, 0, bloodcolor) // Coming
if(isturf(old_loc))
var/turf/old_turf = old_loc
old_turf.AddTracks(species.get_move_trail(src), bloodDNA, 0, dir, bloodcolor) // Going

/mob/living/human/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected)
if((. = ..()) && !surgical_removal)
shock_stage += 20
Expand Down
5 changes: 2 additions & 3 deletions code/modules/mob/living/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,7 @@
if(!root_bodytype)
return

var/static/list/all_stance_limbs = list(ORGAN_CATEGORY_STANCE, ORGAN_CATEGORY_STANCE_ROOT)
var/expected_limbs_for_bodytype = root_bodytype.get_expected_organ_count_for_categories(all_stance_limbs)
var/expected_limbs_for_bodytype = root_bodytype.get_expected_organ_count_for_categories(global.all_stance_limbs)
if(expected_limbs_for_bodytype <= 0)
return // we don't care about stance for whatever reason.

Expand All @@ -598,7 +597,7 @@

var/found_limbs = 0
var/had_limb_pain = FALSE
for(var/obj/item/organ/external/limb in get_organs_by_categories(all_stance_limbs))
for(var/obj/item/organ/external/limb in get_organs_by_categories(global.all_stance_limbs))
found_limbs++
var/add_stance_damage = 0
if(limb.is_malfunctioning())
Expand Down
54 changes: 51 additions & 3 deletions code/modules/mob/living/living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1552,7 +1552,7 @@ default behaviour is:
/mob/living/OnSimulatedTurfEntered(turf/T, old_loc)
T.add_dirt(0.5)

HandleBloodTrail(T, old_loc)
handle_walking_tracks(T, old_loc)

if(current_posture.prone)
return
Expand Down Expand Up @@ -1583,8 +1583,46 @@ default behaviour is:
step(src, dir)
sleep(1)

/mob/living/proc/HandleBloodTrail(turf/T, old_loc)
return
/mob/living/proc/handle_walking_tracks(turf/T, old_loc)

if(!T.can_show_footsteps())
return

// Tracking blood or other contaminants
var/obj/item/source
var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str)
if(istype(shoes))
shoes.handle_movement(src, MOVING_QUICKLY(src))
if(shoes.coating && shoes.coating.total_volume > 1)
source = shoes
else
for(var/obj/item/organ/external/stomper in get_organs_by_categories(global.child_stance_limbs))
if(stomper.coating?.total_volume > 1)
source = stomper
break

var/decl/species/my_species = get_species()
if(!source)
my_species?.handle_trail(src, T, old_loc)
return

var/list/bloodDNA
var/bloodcolor
var/list/blood_data = REAGENT_DATA(source.coating, /decl/material/liquid/blood)
if(blood_data)
bloodDNA = list(blood_data[DATA_BLOOD_DNA] = blood_data[DATA_BLOOD_TYPE])
else
bloodDNA = list()
bloodcolor = source.coating.get_color()
source.remove_coating(1)
update_equipment_overlay(slot_shoes_str)

var/use_move_trail = my_species?.get_move_trail(src)
if(use_move_trail)
T.AddTracks(use_move_trail, bloodDNA, dir, 0, bloodcolor) // Coming
if(isturf(old_loc))
var/turf/old_turf = old_loc
old_turf.AddTracks(use_move_trail, bloodDNA, 0, dir, bloodcolor) // Going

/mob/living/proc/handle_general_grooming(user, obj/item/grooming/tool)
if(tool.grooming_flags & (GROOMABLE_BRUSH|GROOMABLE_COMB))
Expand Down Expand Up @@ -1944,3 +1982,13 @@ default behaviour is:

/mob/living/proc/get_age()
. = LAZYACCESS(appearance_descriptors, "age") || 30

/mob/living/proc/add_walking_contaminant(material_type, amount, data)
var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str)
if(istype(shoes))
if(!buckled)
shoes.add_coating(material_type, amount, data)
else
for(var/obj/item/organ/external/limb in get_organs_by_categories(global.child_stance_limbs))
limb.add_coating(material_type, amount, data)
update_equipment_overlay(slot_shoes_str)
Loading

0 comments on commit 102483c

Please sign in to comment.