Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions code/__DEFINES/cleaning.dm
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@
#define CLEAN_SCRUB (CLEAN_WASH | CLEAN_TYPE_FINGERPRINTS | CLEAN_TYPE_FIBERS | CLEAN_TYPE_HARD_DECAL)
#define CLEAN_RAD CLEAN_TYPE_RADIATION
#define CLEAN_ALL (ALL & ~CLEAN_TYPE_WEAK)

// Footprint sprites to use when making footprints in blood, oil, etc.
#define FOOTPRINT_SPRITE_SHOES "shoes"
#define FOOTPRINT_SPRITE_PAWS "paws"
#define FOOTPRINT_SPRITE_CLAWS "claws"
15 changes: 15 additions & 0 deletions code/__DEFINES/flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,21 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define AA_TARGET_SEE_APPEARANCE (1<<0)
#define AA_MATCH_TARGET_OVERLAYS (1<<1)

#define KEEP_TOGETHER_ORIGINAL "keep_together_original"

//setter for KEEP_TOGETHER to allow for multiple sources to set and unset it
#define ADD_KEEP_TOGETHER(x, source)\
if ((x.appearance_flags & KEEP_TOGETHER) && !HAS_TRAIT(x, TRAIT_KEEP_TOGETHER)) ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL); \
ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
x.appearance_flags |= KEEP_TOGETHER

#define REMOVE_KEEP_TOGETHER(x, source)\
REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
if(HAS_TRAIT_FROM_ONLY(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL))\
REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL);\
else if(!HAS_TRAIT(x, TRAIT_KEEP_TOGETHER))\
x.appearance_flags &= ~KEEP_TOGETHER

//religious_tool flags
#define RELIGION_TOOL_INVOKE (1<<0)
#define RELIGION_TOOL_SACRIFICE (1<<1)
Expand Down
5 changes: 3 additions & 2 deletions code/__HELPERS/type2type.dm
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,9 @@
if(337.5 to 360)
return NORTH

/proc/angle2dir_cardinal(angle)
switch(round(angle, 0.1))
/proc/angle2dir_cardinal(degree)
degree = SIMPLIFY_DEGREES(degree)
switch(round(degree, 0.1))
if(315.5 to 360, 0 to 45.5)
return NORTH
if(45.6 to 135.5)
Expand Down
19 changes: 11 additions & 8 deletions code/datums/components/bloodysoles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
/// The world.time when we last picked up blood
var/last_pickup

var/footprint_sprite = FOOTPRINT_SPRITE_SHOES

/datum/component/bloodysoles/Initialize()
if(!isclothing(parent))
return COMPONENT_INCOMPATIBLE
Expand Down Expand Up @@ -69,9 +71,9 @@

//Find a blood decal on a turf that matches our last_blood_state

/datum/component/bloodysoles/proc/find_pool_by_blood_state(turf/turfLoc, typeFilter = null)
/datum/component/bloodysoles/proc/find_pool_by_blood_state(turf/turfLoc, typeFilter = null, footprint_sprite)
for(var/obj/effect/decal/cleanable/blood/pool in turfLoc)
if(pool.blood_state == last_blood_state && (!typeFilter || istype(pool, typeFilter)))
if(pool.blood_state == last_blood_state && pool.footprint_sprite == footprint_sprite && (!typeFilter || istype(pool, typeFilter)))
return pool


Expand Down Expand Up @@ -123,24 +125,24 @@ Used to make bloody footprints on the ground
return

var/half_our_blood = bloody_shoes[last_blood_state] / 2

var/footprint_sprite = wielder.get_footprint_sprite()
// Add footprints in old loc if we have enough cream
if(half_our_blood >= BLOOD_FOOTPRINTS_MIN)
var/turf/oldLocTurf = get_turf(OldLoc)
var/obj/effect/decal/cleanable/blood/footprints/oldLocFP = find_pool_by_blood_state(oldLocTurf, /obj/effect/decal/cleanable/blood/footprints)
var/obj/effect/decal/cleanable/blood/footprints/oldLocFP = find_pool_by_blood_state(oldLocTurf, /obj/effect/decal/cleanable/blood/footprints, footprint_sprite)
if(oldLocFP)
// Footprints found in the tile we left, add us to it
add_parent_to_footprint(oldLocFP)
if (!(oldLocFP.exited_dirs & wielder.dir))
oldLocFP.exited_dirs |= wielder.dir
oldLocFP.update_icon()
else if(find_pool_by_blood_state(oldLocTurf))
else if(find_pool_by_blood_state(oldLocTurf, footprint_sprite = footprint_sprite))
// No footprints in the tile we left, but there was some other blood pool there. Add exit footprints on it
bloody_shoes[last_blood_state] -= half_our_blood
update_icon()


oldLocFP = new(oldLocTurf)
oldLocFP = new(oldLocTurf, footprint_sprite)
if(!QDELETED(oldLocFP)) ///prints merged
oldLocFP.blood_state = last_blood_state
oldLocFP.exited_dirs |= wielder.dir
Expand All @@ -160,7 +162,7 @@ Used to make bloody footprints on the ground
bloody_shoes[last_blood_state] -= half_our_blood
update_icon()

var/obj/effect/decal/cleanable/blood/footprints/FP = new(get_turf(parent_atom))
var/obj/effect/decal/cleanable/blood/footprints/FP = new(get_turf(parent_atom), footprint_sprite)
if(!QDELETED(FP)) ///prints merged
FP.blood_state = last_blood_state
FP.entered_dirs |= wielder.dir
Expand Down Expand Up @@ -220,7 +222,8 @@ Like its parent but can be applied to carbon mobs instead of clothing items
return COMPONENT_INCOMPATIBLE
parent_atom = parent
wielder = parent

if(footprint_sprite)
src.footprint_sprite = footprint_sprite
if(!bloody_feet)
bloody_feet = mutable_appearance('icons/effects/blood.dmi', "shoeblood", SHOES_LAYER)

Expand Down
1 change: 1 addition & 0 deletions code/datums/elements/decals/blood.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

/datum/element/decal/blood/generate_appearance(_icon, _icon_state, _dir, _plane, _layer, _color, _alpha, _smoothing, source)
var/obj/item/I = source
ADD_KEEP_TOGETHER(I, "item_blood_overlay")
if(!_color)
_color = COLOR_BLOOD
var/icon = I.icon
Expand Down
70 changes: 57 additions & 13 deletions code/game/objects/effects/decals/cleanable/humans.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
var/dryname = "dried blood" //when the blood lasts long enough, it becomes dry and gets a new name
var/drydesc = "Looks like it's been here a while. Eew." //as above
var/drytime = 0
var/footprint_sprite = null

/obj/effect/decal/cleanable/blood/Initialize(mapload)
. = ..()
Expand Down Expand Up @@ -205,9 +206,8 @@
/obj/effect/decal/cleanable/blood/footprints
name = "footprints"
icon = 'icons/effects/footprints.dmi'
icon_state = "nothingwhatsoever"
desc = "WHOSE FOOTPRINTS ARE THESE?"
icon_state = "blood1"
icon_state = "blood_shoes_enter"
random_icon_states = null
blood_state = BLOOD_STATE_HUMAN //the icon state to load images from
var/entered_dirs = 0
Expand All @@ -220,28 +220,72 @@
dryname = "dried footprints"
drydesc = "HMM... SOMEONE WAS HERE!"

/obj/effect/decal/cleanable/blood/footprints/Initialize(mapload, footprint_sprite)
src.footprint_sprite = footprint_sprite
. = ..()
icon_state = "" //All of the footprint visuals come from overlays
if(mapload)
entered_dirs |= dir //Keep the same appearance as in the map editor
update_appearance(mapload ? (ALL) : (UPDATE_NAME | UPDATE_DESC))

//Rotate all of the footprint directions too
/obj/effect/decal/cleanable/blood/footprints/setDir(newdir)
if(dir == newdir)
return ..()

var/ang_change = dir2angle(newdir) - dir2angle(dir)
var/old_entered_dirs = entered_dirs
var/old_exited_dirs = exited_dirs
entered_dirs = 0
exited_dirs = 0

for(var/Ddir in GLOB.cardinals)
if(old_entered_dirs & Ddir)
entered_dirs |= angle2dir_cardinal(dir2angle(Ddir) + ang_change)
if(old_exited_dirs & Ddir)
exited_dirs |= angle2dir_cardinal(dir2angle(Ddir) + ang_change)

update_appearance()
return ..()

/obj/effect/decal/cleanable/blood/footprints/update_name(updates)
switch(footprint_sprite)
if(FOOTPRINT_SPRITE_CLAWS)
name = "clawprints"
if(FOOTPRINT_SPRITE_SHOES)
name = "footprints"
if(FOOTPRINT_SPRITE_PAWS)
name = "pawprints"
dryname = "dried [name]"
return ..()

/obj/effect/decal/cleanable/blood/footprints/update_desc(updates)
desc = "WHOSE [uppertext(name)] ARE THESE?"
return ..()

/obj/effect/decal/cleanable/blood/footprints/update_icon()
. = ..()
alpha = min(BLOODY_FOOTPRINT_BASE_ALPHA + (255 - BLOODY_FOOTPRINT_BASE_ALPHA) * bloodiness / (BLOOD_ITEM_MAX / 2), 255)

/obj/effect/decal/cleanable/blood/footprints/update_overlays()
. = ..()

for(var/Ddir in GLOB.cardinals)
if(entered_dirs & Ddir)
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["entered-[blood_state]-[Ddir]"]
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["entered-[footprint_sprite]-[blood_state]-[Ddir]"]
if(!bloodstep_overlay)
GLOB.bloody_footprints_cache["entered-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]1", dir = Ddir)
GLOB.bloody_footprints_cache["entered-[footprint_sprite]-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]_[footprint_sprite]_enter", dir = Ddir)
. += bloodstep_overlay
if(exited_dirs & Ddir)
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["exited-[blood_state]-[Ddir]"]
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["exited-[footprint_sprite]-[blood_state]-[Ddir]"]
if(!bloodstep_overlay)
GLOB.bloody_footprints_cache["exited-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]2", dir = Ddir)
GLOB.bloody_footprints_cache["exited-[footprint_sprite]-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]_[footprint_sprite]_exit", dir = Ddir)
. += bloodstep_overlay

alpha = min(BLOODY_FOOTPRINT_BASE_ALPHA + (255 - BLOODY_FOOTPRINT_BASE_ALPHA) * bloodiness / (BLOOD_ITEM_MAX / 2), 255)


/obj/effect/decal/cleanable/blood/footprints/examine(mob/user)
. = ..()
if((shoe_types.len + species_types.len) > 0)
. += "You recognise the footprints as belonging to:"
. += "You recognise the [name] as belonging to:"
for(var/sole in shoe_types)
var/obj/item/clothing/item = sole
var/article = initial(item.gender) == PLURAL ? "Some" : "A"
Expand All @@ -251,14 +295,14 @@
if(species == "unknown")
. += "Some <B>feet</B>."
else if(species == "monkey")
. += "[icon2html('icons/mob/monkey.dmi', user, "monkey1")] Some <B>monkey feet</B>."
. += "[icon2html('icons/mob/monkey.dmi', user, "monkey1")] Some <B>monkey paws</B>."
else if(species == "human")
. += "[icon2html('icons/mob/human_parts.dmi', user, "default_human_l_leg")] Some <B>human feet</B>."
else
. += "[icon2html('icons/mob/human_parts.dmi', user, "[species]_l_leg")] Some <B>[species] feet</B>."

/obj/effect/decal/cleanable/blood/footprints/replace_decal(obj/effect/decal/cleanable/C)
if(blood_state != C.blood_state) //We only replace footprints of the same type as us
/obj/effect/decal/cleanable/blood/footprints/replace_decal(obj/effect/decal/cleanable/blood/blood_decal)
if(blood_state != blood_decal.blood_state || footprint_sprite != blood_decal.footprint_sprite) //We only replace footprints of the same type as us
return FALSE
return ..()

Expand Down
2 changes: 1 addition & 1 deletion code/modules/clothing/shoes/_shoes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
slot_flags = ITEM_SLOT_FEET

slowdown = SHOES_SLOWDOWN

var/footprint_sprite = FOOTPRINT_SPRITE_SHOES
var/offset = 0
var/equipped_before_drop = FALSE
var/xenoshoe = NO_DIGIT // Check for if shoes can be worn by straight legs (NO_DIGIT) which is default, both / hybrid (EITHER_STYLE), or digitigrade only (YES_DIGIT)
Expand Down
3 changes: 3 additions & 0 deletions code/modules/mob/living/carbon/carbon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,9 @@
var/obj/item/organ/I = X
I.Insert(src)

/mob/living/carbon/proc/get_footprint_sprite()
return FOOTPRINT_SPRITE_PAWS

/mob/living/carbon/vv_get_dropdown()
. = ..()
VV_DROPDOWN_SEPERATOR
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/carbon_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
var/obj/item/clothing/head = null

var/obj/item/clothing/gloves = null //only used by humans
var/obj/item/clothing/shoes = null //only used by humans.
var/obj/item/clothing/shoes/shoes = null //only used by humans.
var/obj/item/clothing/glasses/glasses = null //only used by humans.
var/obj/item/clothing/ears = null //only used by humans.

Expand Down
7 changes: 6 additions & 1 deletion code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_FACE_ACT, PROC_REF(clean_face))
AddComponent(/datum/component/personal_crafting)
AddElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6)
AddComponent(/datum/component/bloodysoles/feet)
AddComponent(/datum/component/bloodysoles/feet, FOOTPRINT_SPRITE_SHOES)

/mob/living/carbon/human/proc/setup_human_dna()
//initialize dna. for spawned humans; overwritten by other code
Expand Down Expand Up @@ -547,6 +547,11 @@
// Might need re-wording.
to_chat(user, span_alert("There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"]."))

/mob/living/carbon/human/get_footprint_sprite()
var/obj/item/bodypart/l_leg/left_leg = get_bodypart(BODY_ZONE_L_LEG)
var/obj/item/bodypart/r_leg/right_leg = get_bodypart(BODY_ZONE_R_LEG)
return shoes?.footprint_sprite || left_leg?.footprint_sprite || right_leg?.footprint_sprite

/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
if(judgement_criteria & JUDGE_EMAGGED)
return 10 //Everyone is a criminal!
Expand Down
6 changes: 6 additions & 0 deletions code/modules/surgery/bodyparts/parts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@
px_y = 12
max_stamina_damage = 50
can_be_disabled = TRUE
/// Used by the bloodysoles component to make footprints
var/footprint_sprite = FOOTPRINT_SPRITE_SHOES

/obj/item/bodypart/l_leg/set_owner(new_owner)
. = ..()
Expand Down Expand Up @@ -315,6 +317,7 @@
animal_origin = MONKEY_BODYPART
wound_resistance = -10
px_y = 4
footprint_sprite = FOOTPRINT_SPRITE_PAWS

/obj/item/bodypart/l_leg/alien
icon = 'icons/mob/animal_parts.dmi'
Expand Down Expand Up @@ -348,6 +351,8 @@
px_y = 12
max_stamina_damage = 50
can_be_disabled = TRUE
/// Used by the bloodysoles component to make footprints
var/footprint_sprite = FOOTPRINT_SPRITE_SHOES

/obj/item/bodypart/r_leg/set_owner(new_owner)
. = ..()
Expand Down Expand Up @@ -404,6 +409,7 @@
animal_origin = MONKEY_BODYPART
wound_resistance = -10
px_y = 4
footprint_sprite = FOOTPRINT_SPRITE_PAWS

/obj/item/bodypart/r_leg/alien
icon = 'icons/mob/animal_parts.dmi'
Expand Down
Binary file modified icons/effects/footprints.dmi
Binary file not shown.