Add beach towels. (#31667)

* Add beach towels.

* Add basic towel. Attempt absorbency. Add towel names.

* Make towels pick up and spread blood.
Move towel place-on-floor function to beach towels.

* Move amount to base cleanable. Refine towel procs.

* Ensure towel picks up blood.

* Add species sprites and inhands.

* Apply suggestions from code review.

* Fix ussp space ruin.

* Whitespace.

* Prevent picking up blood DNA already on the towel from mobs/items without decal amounts.
This commit is contained in:
Alan
2026-04-14 16:24:53 +00:00
committed by GitHub
parent 1895ea77cb
commit a714de9149
23 changed files with 338 additions and 40 deletions
@@ -6,7 +6,7 @@
/obj/effect/decal/cleanable/blood/xeno/splatter
random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
amount = 2
cleanable_amount = 2
/obj/effect/decal/cleanable/blood/gibs/xeno
name = "xeno gibs"
@@ -46,7 +46,7 @@
/obj/effect/decal/cleanable/blood/slime/streak
random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
amount = 2
cleanable_amount = 2
/obj/effect/decal/cleanable/blood/vox
name = "vox blood"
@@ -2,16 +2,16 @@
//Liquid fuel is used for things that used to rely on volatile fuels or plasma being contained to a couple tiles.
icon_state = "fuel"
layer = ABOVE_NORMAL_TURF_LAYER
var/amount = 1 //Basically moles.
cleanable_amount = 1 //Basically moles.
/obj/effect/decal/cleanable/liquid_fuel/Initialize(mapload, amt = 1)
. = ..()
amount = amt
cleanable_amount = amt
//Be absorbed by any other liquid fuel in the tile.
for(var/obj/effect/decal/cleanable/liquid_fuel/other in loc)
if(other != src)
other.amount += amount
other.cleanable_amount += cleanable_amount
spawn other.Spread()
qdel(src)
@@ -19,7 +19,7 @@
/obj/effect/decal/cleanable/liquid_fuel/proc/Spread()
//Allows liquid fuels to sometimes flow into other tiles.
if(amount < 0.5)
if(cleanable_amount < 0.5)
return
var/turf/simulated/S = loc
if(!istype(S))
@@ -30,8 +30,8 @@
var/turf/simulated/origin = get_turf(src)
if(origin.CanPass(null, target, 0, 0) && target.CanPass(null, origin, 0, 0))
if(!locate(/obj/effect/decal/cleanable/liquid_fuel) in target)
new/obj/effect/decal/cleanable/liquid_fuel(target, amount * 0.25)
amount *= 0.75
new/obj/effect/decal/cleanable/liquid_fuel(target, cleanable_amount * 0.25)
cleanable_amount *= 0.75
/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel
icon_state = "mustard"
@@ -43,7 +43,7 @@
/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/Spread()
//The spread for flamethrower fuel is much more precise, to create a wide fire pattern.
if(amount < 0.1)
if(cleanable_amount < 0.1)
return
var/turf/simulated/S = loc
if(!istype(S))
@@ -54,7 +54,7 @@
if(locate(/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel) in O)
continue
if(O.CanPass(null, S, 0, 0) && S.CanPass(null, O, 0, 0))
new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O, amount * 0.25, d)
new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O, cleanable_amount * 0.25, d)
O.hotspot_expose((T20C*2) + 380,500) //Light flamethrower fuel on fire immediately.
amount *= 0.25
cleanable_amount *= 0.25
@@ -1,4 +1,4 @@
#define DRYING_TIME 5 MINUTES //for 1 unit of depth in puddle (amount var)
#define DRYING_TIME 5 MINUTES //for 1 unit of depth in puddle (cleanable_amount var)
#define ALWAYS_IN_GRAVITY 2
/obj/effect/decal/cleanable/blood
@@ -17,7 +17,7 @@
var/blood_state = BLOOD_STATE_HUMAN
bloodiness = BLOOD_AMOUNT_PER_DECAL
var/basecolor = "#A10808" // Color when wet.
var/amount = 5
cleanable_amount = 5
var/dry_timer = 0
var/off_floor = FALSE
var/image/weightless_image
@@ -50,12 +50,12 @@
if(gravity_check)
if(!. && !QDELETED(src))
dry_timer = addtimer(CALLBACK(src, PROC_REF(dry)), DRYING_TIME * (amount+1), TIMER_STOPPABLE)
dry_timer = addtimer(CALLBACK(src, PROC_REF(dry)), DRYING_TIME * (cleanable_amount + 1), TIMER_STOPPABLE)
else
if(prob(50))
animate_float(src, -1, rand(30,120))
animate_float(src, -1, rand(30, 120))
else
animate_levitate(src, -1, rand(30,120))
animate_levitate(src, -1, rand(30, 120))
//weightless blood cannot dry
return
@@ -106,7 +106,7 @@
name = dryname
desc = drydesc
color = adjust_brightness(color, -50)
amount = 0
cleanable_amount = 0
gravity_check = ALWAYS_IN_GRAVITY
animate(src)
@@ -162,7 +162,7 @@
// they were going in.
var/list/obj/item/things_to_potentially_bloody = list()
var/count = amount + 1
var/count = cleanable_amount + 1
for(var/obj/item/i in H.contents)
things_to_potentially_bloody += i
@@ -177,12 +177,12 @@
/obj/effect/decal/cleanable/blood/attack_hand(mob/living/carbon/human/user)
..()
if(amount && istype(user))
if(cleanable_amount && istype(user))
add_fingerprint(user)
if(user.gloves)
return
var/taken = rand(1,amount)
amount -= taken
var/taken = rand(1,cleanable_amount)
cleanable_amount -= taken
to_chat(user, SPAN_NOTICE("You get some of \the [src] on your hands."))
if(!user.blood_DNA)
user.blood_DNA = list()
@@ -200,7 +200,7 @@
/obj/effect/decal/cleanable/blood/splatter
random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
amount = 2
cleanable_amount = 2
/obj/effect/decal/cleanable/blood/drip
name = "drips of blood"
@@ -208,7 +208,7 @@
icon = 'icons/effects/drip.dmi'
icon_state = "1"
random_icon_states = list("1", "2", "3", "4", "5")
amount = 0
cleanable_amount = 0
bloodiness = 0
var/drips = 1
@@ -234,7 +234,7 @@
desc = "It looks like a writing in blood."
gender = NEUTER
random_icon_states = list("writing1", "writing2", "writing3", "writing4", "writing5")
amount = 0
cleanable_amount = 0
var/message
/obj/effect/decal/cleanable/blood/writing/Initialize(mapload)
@@ -49,6 +49,7 @@
smoothing_groups = list(SMOOTH_GROUP_CLEANABLE_DIRT)
canSmoothWith = list(SMOOTH_GROUP_CLEANABLE_DIRT, SMOOTH_GROUP_WALLS)
mouse_opacity = FALSE
cleanable_amount = 1
/obj/effect/decal/cleanable/dirt/Initialize(mapload)
. = ..()
@@ -74,6 +75,7 @@
gender = PLURAL
layer = TURF_LAYER
icon_state = "flour"
cleanable_amount = 1
/obj/effect/decal/cleanable/flour/nanofrost
name = "nanofrost residue"
@@ -138,6 +140,7 @@
random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
no_clear = TRUE
scoop_reagents = list("vomit" = 5)
cleanable_amount = 2
/obj/effect/decal/cleanable/vomit/Initialize(mapload)
@@ -254,12 +257,14 @@
layer = TURF_LAYER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
cleanable_amount = 1
/obj/effect/decal/cleanable/plant_smudge
name = "plant smudge"
layer = TURF_LAYER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("smashed_plant")
cleanable_amount = 1
/obj/effect/decal/cleanable/egg_smudge
name = "smashed egg"
@@ -267,6 +272,7 @@
layer = TURF_LAYER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3")
cleanable_amount = 1
/// honk
/obj/effect/decal/cleanable/pie_smudge
@@ -275,6 +281,7 @@
layer = TURF_LAYER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("smashed_pie")
cleanable_amount = 2
/obj/effect/decal/cleanable/paint_splat
name = "paint splat"
@@ -284,6 +291,7 @@
icon_state = "splatter-1"
random_icon_states = list("splatter-1", "splatter-2", "splatter-3")
mergeable_decal = FALSE
cleanable_amount = 1
/obj/effect/decal/cleanable/paint_splat/Initialize(mapload)
pixel_x = rand(-10, 10)
@@ -339,6 +347,7 @@
icon = 'icons/effects/blood.dmi'
icon_state = "xfloor1"
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
cleanable_amount = 2
/obj/effect/decal/cleanable/reagent
name = "fluid"
@@ -347,7 +356,7 @@
icon_state = "xfloor1"
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
var/basecolor = "#909090"
var/amount = 10
cleanable_amount = 5
/obj/effect/decal/cleanable/reagent/Initialize(mapload, decal_color)
. = ..()
@@ -362,6 +371,6 @@
icon = 'icons/effects/drip.dmi'
icon_state = "1"
random_icon_states = list("1", "2", "3", "4", "5")
amount = 1
cleanable_amount = 1
#undef ALWAYS_IN_GRAVITY
@@ -59,4 +59,4 @@
/obj/effect/decal/cleanable/blood/oil/streak
random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
amount = 2
cleanable_amount = 2
@@ -3,6 +3,7 @@
name = "tar"
desc = "A sticky substance."
icon_state = "tar2"
cleanable_amount = 5
/// The turf that the tar is sitting on
var/turf/simulated/target
@@ -14,7 +14,7 @@ GLOBAL_LIST_EMPTY(fluidtrack_cache)
drydesc = "Whoops..."
icon_state = "wheels1"
random_icon_states = null
amount = 0
cleanable_amount = 0
gravity_check = ALWAYS_IN_GRAVITY
/// Subtype of tracks used for decorating maps.
+12 -9
View File
@@ -1,14 +1,17 @@
#define ALWAYS_IN_GRAVITY 2
/obj/effect/decal/cleanable
///when Initialized() its icon_state will be chosen from this list
/// when Initialized() its icon_state will be chosen from this list
var/list/random_icon_states = list()
///0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
/// 0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
var/bloodiness = 0
///when another of the same type is made on the same tile will they merge --- YES=TRUE; NO=FLASE
/// How much yuck there is this decal, usually from 0-5.
/// Used to calculate drying times, blood writing uses, and similar things.
var/cleanable_amount = 0
/// when another of the same type is made on the same tile will they merge --- YES=TRUE; NO=FLASE
var/mergeable_decal = TRUE
///prevents Ambient Occlusion effects around it ; Set to GAME_PLANE in Initialize() if on a wall
///for blood n vomit in zero G --- IN GRAVITY=TRUE; NO GRAVITY=FALSE
/// prevents Ambient Occlusion effects around it ; Set to GAME_PLANE in Initialize() if on a wall
/// for blood n vomit in zero G --- IN GRAVITY=TRUE; NO GRAVITY=FALSE
var/gravity_check = TRUE
hud_possible = list(JANI_HUD)
@@ -24,8 +27,8 @@
else
..()
//Add "bloodiness" of this blood's type, to the human's shoes
//This is on /cleanable because fuck this ancient mess
// Add "bloodiness" of this blood's type, to the human's shoes
// This is on /cleanable because fuck this ancient mess
/obj/effect/decal/cleanable/blood/proc/on_atom_entered(datum/source, atom/movable/entered)
if(!ishuman(entered))
return
@@ -52,7 +55,7 @@
add_blood = bloodiness
bloodiness -= add_blood
S.bloody_shoes[blood_state] = min(MAX_SHOE_BLOODINESS, S.bloody_shoes[blood_state] + add_blood)
S.bloody_shoes[BLOOD_BASE_ALPHA] = BLOODY_FOOTPRINT_BASE_ALPHA * (alpha/255)
S.bloody_shoes[BLOOD_BASE_ALPHA] = BLOODY_FOOTPRINT_BASE_ALPHA * (alpha / 255)
if(length(blood_DNA))
S.add_blood(blood_DNA, basecolor)
S.blood_state = blood_state
@@ -67,7 +70,7 @@
add_blood = bloodiness
bloodiness -= add_blood
H.bloody_feet[blood_state] = min(MAX_SHOE_BLOODINESS, H.bloody_feet[blood_state] + add_blood)
H.bloody_feet[BLOOD_BASE_ALPHA] = BLOODY_FOOTPRINT_BASE_ALPHA * (alpha/255)
H.bloody_feet[BLOOD_BASE_ALPHA] = BLOODY_FOOTPRINT_BASE_ALPHA * (alpha / 255)
if(!H.feet_blood_DNA)
H.feet_blood_DNA = list()
H.blood_state = blood_state