Files
Bubberstation/code/modules/art/statues.dm
LemonInTheDark f03084c1ca FOV is Dead (Long Live FOV) (#80062)
## About The Pull Request

FOV as it is currently implemented is incompatible* with wallening.
I'm doin wallening, so we gotta redo things here.

The issue is the masking of mobs. Wallening relies on sidemap (layering
based off physical position), which only works on things on the same
plane (because planes are basically sheets we render down onto)
So rather then masking mobs, let's reuse the masking idea from old fov,
and use it to cut out a bit of the game render plane, and
blur/over-saturate the bit that's masked out.

My hope is this makes things visible in light, but not as much in
darkness, alongside making more vivid shit more easily seen (just like
real life)

Here's some videos, what follows after is the commits I care about
(since I had to rip a bunch of planes to nothing, so the files changed
tab might be a bit of a mess)

Oh also I had to remove the darkness pref since the darkness is doing a
lot of the heavy lifting now. I'm sorry.

Edit:
NEW FOV SPRITES! Thanks dongle your aviator glasses will guide us to a
better future.


https://github.com/tgstation/tgstation/assets/58055496/afa9eeb8-8b7b-4364-b0c0-7ac8070b5609


https://github.com/tgstation/tgstation/assets/58055496/0eff040c-8bf1-47e4-a4f3-dac56fb2ccc8

## Commits I Care About

[Implements something like fov, but without the planes as layers
hell](a604c7b1c8)

Rather then masking out mobs standing behind us, we use a combo color
matrix and blur filter to make the stuff covered by fov harder to see.

We achive this by splitting the game plane into two, masking both by fov
(one normally and one inversely), and then applying effects to one of
the two.

I want to make the fov fullscreens more gradient, but as an effect this
is a good start

[Removes WALL_PLANE_UPPER by adding a WALL_PLANE overlay to material
walls (init cost comes
here)](2548933739)

@Mothblocks see this. comment in commit explains further but uh, we need
to draw material walls to the light mask plane so things actually can be
seen on them, but we can't do that and also have them be big, so they
get an overlay. Sorry, slight init time bump, about 0.5 seconds. I can
kill it with wallening.

[Moves SEETHROUGH_PLANE above
ABOVE_GAME_PLANE](beec4c00e0)

I don't think it actually wants to draw here
@Time-Green I think this was you so pinging for opinion

[Resprites FOV masks to be clean (and more
consistent)](f02ad13696)

[f02ad13](f02ad13696)

This is 100% donglesplonge's work, he's spent a week or so going back
and forth with me sharpening these to a mirror shine, real chill

## Why It's Good For The Game

Walls are closing in

## Changelog
🆑 LemonInTheDark, Donglesplonge
image: Redoes fov "mask" sprites. They're clean, have a very pleasant
dithering effect, and look real fuckin good!
del: Changed FOV, it no longer hides mobs, instead it blurs the hidden
area, and makes it a bit darker/oversaturated
/🆑

###### * It's technically possible if we start using render targets to
create 2 sets of sources but that's insane and we aren't doing it
2023-12-13 15:52:24 +01:00

619 lines
22 KiB
Plaintext

/// This controls the delay for the sculpt rock breaking sound
/// Every 4th iterator while sculpting will emit a sound (rougly every couple of seconds)
#define SCULPT_SOUND_INCREMENT 4
/obj/structure/statue
name = "statue"
desc = "Placeholder. Yell at Firecage if you SOMEHOW see this."
icon = 'icons/obj/art/statue.dmi'
icon_state = ""
density = TRUE
anchored = FALSE
max_integrity = 100
can_atmos_pass = ATMOS_PASS_DENSITY
material_modifier = 0.5
material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
/// Beauty component mood modifier
var/impressiveness = 15
/// Art component subtype added to this statue
var/art_type = /datum/element/art
/// Abstract root type
var/abstract_type = /obj/structure/statue
/obj/structure/statue/Initialize(mapload)
. = ..()
AddElement(art_type, impressiveness)
AddElement(/datum/element/beauty, impressiveness * 75)
AddComponent(/datum/component/simple_rotation)
/obj/structure/statue/wrench_act(mob/living/user, obj/item/tool)
. = ..()
if(obj_flags & NO_DECONSTRUCTION)
return FALSE
default_unfasten_wrench(user, tool)
return ITEM_INTERACT_SUCCESS
/obj/structure/statue/attackby(obj/item/W, mob/living/user, params)
add_fingerprint(user)
if(!(obj_flags & NO_DECONSTRUCTION))
if(W.tool_behaviour == TOOL_WELDER)
if(!W.tool_start_check(user, amount=1))
return FALSE
user.balloon_alert(user, "slicing apart...")
if(W.use_tool(src, user, 40, volume=50))
deconstruct(TRUE)
return
return ..()
/obj/structure/statue/AltClick(mob/user)
return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation
/obj/structure/statue/deconstruct(disassembled = TRUE)
if(!(obj_flags & NO_DECONSTRUCTION))
var/amount_mod = disassembled ? 0 : -2
for(var/mat in custom_materials)
var/datum/material/custom_material = GET_MATERIAL_REF(mat)
var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod)
if(amount > 0)
new custom_material.sheet_type(drop_location(), amount)
qdel(src)
//////////////////////////////////////STATUES/////////////////////////////////////////////////////////////
////////////////////////uranium///////////////////////////////////
/obj/structure/statue/uranium
max_integrity = 300
// largish, dim green glow
light_range = 3
light_power = 0.7
light_color = LIGHT_COLOR_NUCLEAR
custom_materials = list(/datum/material/uranium=SHEET_MATERIAL_AMOUNT*5)
impressiveness = 25 // radiation makes an impression
abstract_type = /obj/structure/statue/uranium
/obj/structure/statue/uranium/nuke
name = "statue of a nuclear fission explosive"
desc = "This is a grand statue of a Nuclear Explosive. It has a sickening green colour."
icon_state = "nuke"
/obj/structure/statue/uranium/eng
name = "Statue of an engineer"
desc = "This statue has a sickening green colour."
icon_state = "eng"
////////////////////////////plasma///////////////////////////////////////////////////////////////////////
/obj/structure/statue/plasma
max_integrity = 200
impressiveness = 20
desc = "This statue is suitably made from plasma."
custom_materials = list(/datum/material/plasma=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/plasma
/obj/structure/statue/plasma/scientist
name = "statue of a scientist"
icon_state = "sci"
/obj/structure/statue/plasma/xeno
name = "statue of a xenomorph"
icon_state = "xeno"
//////////////////////gold///////////////////////////////////////
/obj/structure/statue/gold
max_integrity = 300
impressiveness = 25
desc = "This is a highly valuable statue made from gold."
custom_materials = list(/datum/material/gold=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/gold
/obj/structure/statue/gold/hos
name = "statue of the head of security"
icon_state = "hos"
/obj/structure/statue/gold/hop
name = "statue of the head of personnel"
icon_state = "hop"
/obj/structure/statue/gold/cmo
name = "statue of the chief medical officer"
icon_state = "cmo"
/obj/structure/statue/gold/ce
name = "statue of the chief engineer"
icon_state = "ce"
/obj/structure/statue/gold/rd
name = "statue of the research director"
icon_state = "rd"
/obj/structure/statue/gold/qm
name = "statue of the quartermaster"
icon_state = "qm"
//////////////////////////silver///////////////////////////////////////
/obj/structure/statue/silver
max_integrity = 300
impressiveness = 25
desc = "This is a valuable statue made from silver."
custom_materials = list(/datum/material/silver=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/silver
/obj/structure/statue/silver/md
name = "statue of a medical officer"
icon_state = "md"
/obj/structure/statue/silver/janitor
name = "statue of a janitor"
icon_state = "jani"
/obj/structure/statue/silver/sec
name = "statue of a security officer"
icon_state = "sec"
/obj/structure/statue/silver/secborg
name = "statue of a security cyborg"
icon_state = "secborg"
/obj/structure/statue/silver/medborg
name = "statue of a medical cyborg"
icon_state = "medborg"
/////////////////////////diamond/////////////////////////////////////////
/obj/structure/statue/diamond
max_integrity = 1000
impressiveness = 50
desc = "This is a very expensive diamond statue."
custom_materials = list(/datum/material/diamond=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/diamond
/obj/structure/statue/diamond/captain
name = "statue of THE captain."
icon_state = "cap"
/obj/structure/statue/diamond/ai1
name = "statue of the AI hologram."
icon_state = "ai1"
/obj/structure/statue/diamond/ai2
name = "statue of the AI core."
icon_state = "ai2"
////////////////////////bananium///////////////////////////////////////
/obj/structure/statue/bananium
max_integrity = 300
impressiveness = 50
desc = "A bananium statue with a small engraving:'HOOOOOOONK'."
custom_materials = list(/datum/material/bananium=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/bananium
/obj/structure/statue/bananium/clown
name = "statue of a clown"
icon_state = "clown"
/////////////////////sandstone/////////////////////////////////////////
/obj/structure/statue/sandstone
max_integrity = 50
impressiveness = 15
custom_materials = list(/datum/material/sandstone=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/sandstone
/obj/structure/statue/sandstone/assistant
name = "statue of an assistant"
desc = "A cheap statue of sandstone for a greyshirt."
icon_state = "assist"
/obj/structure/statue/sandstone/venus //call me when we add marble i guess
name = "statue of a pure maiden"
desc = "An ancient marble statue. The subject is depicted with a floor-length braid and is wielding a toolbox. By Jove, it's easily the most gorgeous depiction of a woman you've ever seen. The artist must truly be a master of his craft. Shame about the broken arm, though."
icon = 'icons/obj/art/statuelarge.dmi'
icon_state = "venus"
/////////////////////snow/////////////////////////////////////////
/obj/structure/statue/snow
max_integrity = 50
custom_materials = list(/datum/material/snow=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/snow
/obj/structure/statue/snow/snowman
name = "snowman"
desc = "Several lumps of snow put together to form a snowman."
icon_state = "snowman"
/obj/structure/statue/snow/snowlegion
name = "snowlegion"
desc = "Looks like that weird kid with the tiger plushie has been round here again."
icon_state = "snowlegion"
///////////////////////////////bronze///////////////////////////////////
/obj/structure/statue/bronze
custom_materials = list(/datum/material/bronze=SHEET_MATERIAL_AMOUNT*5)
abstract_type = /obj/structure/statue/bronze
/obj/structure/statue/bronze/marx
name = "\improper Karl Marx bust"
desc = "A bust depicting a certain 19th century economist. You get the feeling a specter is haunting the station."
icon_state = "marx"
art_type = /datum/element/art/rev
///////////Elder Atmosian///////////////////////////////////////////
/obj/structure/statue/elder_atmosian
name = "Elder Atmosian"
desc = "A statue of an Elder Atmosian, capable of bending the laws of thermodynamics to their will."
icon_state = "eng"
custom_materials = list(/datum/material/metalhydrogen = SHEET_MATERIAL_AMOUNT*10)
max_integrity = 1000
impressiveness = 100
abstract_type = /obj/structure/statue/elder_atmosian //This one is uncarvable
///////////Goliath//////////////////////////////////////////////////
/obj/structure/statue/goliath
desc = "A lifelike statue of a horrifying monster."
icon = 'icons/mob/simple/lavaland/lavaland_monsters_wide.dmi'
icon_state = "goliath"
pixel_x = -12
base_pixel_x = -12
name = "goliath"
///////////Other Stuff//////////////////////////////////////////////
/obj/item/chisel
name = "chisel"
desc = "Breaking and making art since 4000 BC. This one uses advanced technology to allow the creation of lifelike moving statues."
icon = 'icons/obj/art/statue.dmi'
icon_state = "chisel"
inhand_icon_state = "screwdriver_nuke"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
obj_flags = CONDUCTS_ELECTRICITY
slot_flags = ITEM_SLOT_BELT
force = 5
w_class = WEIGHT_CLASS_TINY
throwforce = 5
throw_speed = 3
throw_range = 5
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*0.75)
attack_verb_continuous = list("stabs")
attack_verb_simple = list("stab")
hitsound = 'sound/weapons/bladeslice.ogg'
usesound = list('sound/effects/picaxe1.ogg', 'sound/effects/picaxe2.ogg', 'sound/effects/picaxe3.ogg')
drop_sound = 'sound/items/handling/screwdriver_drop.ogg'
pickup_sound = 'sound/items/handling/screwdriver_pickup.ogg'
sharpness = SHARP_POINTY
tool_behaviour = TOOL_RUSTSCRAPER
toolspeed = 3 // You're gonna have a bad time
/// Block we're currently carving in
var/obj/structure/carving_block/prepared_block
/// If tracked user moves we stop sculpting
var/mob/living/tracked_user
/// Currently sculpting
var/sculpting = FALSE
/obj/item/chisel/Initialize(mapload)
. = ..()
AddElement(/datum/element/eyestab)
AddElement(/datum/element/wall_engraver)
//deals 200 damage to statues, meaning you can actually kill one in ~250 hits
AddElement(/datum/element/bane, target_type = /mob/living/basic/statue, damage_multiplier = 40)
/obj/item/chisel/Destroy()
prepared_block = null
tracked_user = null
return ..()
/*
Hit the block to start
Point with the chisel at the target to choose what to sculpt or hit block to choose from preset statue types.
Hit block again to start sculpting.
Moving interrupts
*/
/obj/item/chisel/pre_attack(atom/target, mob/living/user, params)
. = ..()
if(sculpting)
return TRUE
if(istype(target, /obj/structure/carving_block))
var/obj/structure/carving_block/sculpt_block = target
if(sculpt_block.completion) // someone already started sculpting this so just finish
set_block(sculpt_block, user, silent = TRUE)
start_sculpting(user)
else if(sculpt_block == prepared_block && (prepared_block.current_target || prepared_block.current_preset_type))
start_sculpting(user)
else if(!prepared_block)
set_block(sculpt_block, user)
else if(sculpt_block == prepared_block)
show_generic_statues_prompt(user)
return TRUE
else if(prepared_block) //We're aiming at something next to us with block prepared
prepared_block.set_target(target, user)
return TRUE
// We aim at something distant.
/obj/item/chisel/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if (!sculpting && prepared_block && ismovable(target) && prepared_block.completion == 0)
prepared_block.set_target(target,user)
return . | AFTERATTACK_PROCESSED_ITEM
/// Starts or continues the sculpting action on the carving block material
/obj/item/chisel/proc/start_sculpting(mob/living/user)
user.balloon_alert(user, "sculpting block...")
playsound(src, pick(usesound), 75, TRUE)
sculpting = TRUE
//How long whole process takes
var/sculpting_time = 30 SECONDS
//Single interruptible progress period
var/sculpting_period = round(sculpting_time / world.icon_size) //this is just so it reveals pixels line by line for each.
var/interrupted = FALSE
var/remaining_time = sculpting_time - (prepared_block.completion * sculpting_time)
var/datum/progressbar/total_progress_bar = new(user, sculpting_time, prepared_block)
while(remaining_time > 0 && !interrupted)
if(do_after(user, sculpting_period, target = prepared_block, progress = FALSE))
var/time_delay = !(remaining_time % SCULPT_SOUND_INCREMENT)
if(time_delay)
playsound(src, 'sound/effects/break_stone.ogg', 50, TRUE)
remaining_time -= sculpting_period
prepared_block.set_completion((sculpting_time - remaining_time)/sculpting_time)
total_progress_bar.update(sculpting_time - remaining_time)
else
interrupted = TRUE
total_progress_bar.end_progress()
if(!interrupted && !QDELETED(prepared_block))
prepared_block.create_statue()
user.balloon_alert(user, "statue finished")
stop_sculpting(silent = !interrupted)
/// To setup the sculpting target for the carving block
/obj/item/chisel/proc/set_block(obj/structure/carving_block/B, mob/living/user, silent = FALSE)
prepared_block = B
tracked_user = user
RegisterSignal(tracked_user, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
if(!silent)
user.balloon_alert(user, "select sculpt target")
/obj/item/chisel/dropped(mob/user, silent)
. = ..()
stop_sculpting()
/// Cancel the sculpting action
/obj/item/chisel/proc/stop_sculpting(silent = FALSE)
sculpting = FALSE
if(prepared_block && prepared_block.completion == 0)
prepared_block.reset_target()
prepared_block = null
if(!silent && tracked_user)
tracked_user.balloon_alert(tracked_user, "sculpting cancelled!")
if(tracked_user)
UnregisterSignal(tracked_user, COMSIG_MOVABLE_MOVED)
tracked_user = null
/obj/item/chisel/proc/on_moved()
SIGNAL_HANDLER
stop_sculpting()
/obj/item/chisel/proc/show_generic_statues_prompt(mob/living/user)
var/list/choices = list()
for(var/statue_path in prepared_block.get_possible_statues())
var/obj/structure/statue/abstract_statue = statue_path
choices[statue_path] = image(icon = initial(abstract_statue.icon), icon_state = initial(abstract_statue.icon_state))
if(!choices.len)
user.balloon_alert(user, "no abstract statues for material!")
var/choice = show_radial_menu(user, prepared_block, choices, require_near = TRUE)
if(choice)
prepared_block.current_preset_type = choice
var/image/chosen_looks = choices[choice]
prepared_block.current_target = chosen_looks.appearance
user.balloon_alert(user, "abstract statue selected")
/obj/structure/carving_block
name = "block"
desc = "Ready for sculpting."
icon = 'icons/obj/art/statue.dmi'
icon_state = "block"
material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_ADD_PREFIX
density = TRUE
material_modifier = 0.5 //50% effectiveness of materials
/// The thing it will look like - Unmodified resulting statue appearance
var/current_target
/// Currently chosen preset statue type
var/current_preset_type
//Table of required materials for each non-abstract statue type
var/static/list/statue_costs
/// statue completion from 0 to 1.0
var/completion = 0
/// Greyscaled target with cutout filter
var/mutable_appearance/target_appearance_with_filters
/// HSV color filters parameters
var/static/list/greyscale_with_value_bump = list(0,0,0, 0,0,0, 0,0,1, 0,0,-0.05)
/obj/structure/carving_block/Destroy()
current_target = null
target_appearance_with_filters = null
return ..()
/obj/structure/carving_block/proc/set_target(atom/movable/target, mob/living/user)
if(!is_viable_target(user, target))
return
if(istype(target,/obj/structure/statue/custom))
var/obj/structure/statue/custom/original = target
current_target = original.content_ma
else
current_target = target.appearance
var/mutable_appearance/ma = current_target
user.balloon_alert(user, "sculpt target is [ma.name]")
/obj/structure/carving_block/proc/reset_target()
current_target = null
current_preset_type = null
target_appearance_with_filters = null
/obj/structure/carving_block/update_overlays()
. = ..()
if(!target_appearance_with_filters)
return
//We're only keeping one instance here that changes in the middle so we have to clone it to avoid managed overlay issues
var/mutable_appearance/clone = new(target_appearance_with_filters)
. += clone
/obj/structure/carving_block/proc/is_viable_target(mob/living/user, atom/movable/target)
//Only things on turfs
if(!isturf(target.loc))
user.balloon_alert(user, "no sculpt target!")
return FALSE
//No big icon things
var/list/icon_dimensions = get_icon_dimensions(target.icon)
if(icon_dimensions["width"] != world.icon_size || icon_dimensions["height"] != world.icon_size)
user.balloon_alert(user, "sculpt target is too big!")
return FALSE
return TRUE
/obj/structure/carving_block/proc/create_statue()
if(current_preset_type)
var/obj/structure/statue/preset_statue = new current_preset_type(get_turf(src))
preset_statue.set_custom_materials(custom_materials)
qdel(src)
else if(current_target)
var/obj/structure/statue/custom/new_statue = new(get_turf(src))
new_statue.set_visuals(current_target)
new_statue.set_custom_materials(custom_materials)
var/mutable_appearance/ma = current_target
new_statue.name = "statue of [ma.name]"
new_statue.desc = "A carved statue depicting [ma.name]."
qdel(src)
/obj/structure/carving_block/proc/set_completion(value)
if(!current_target)
return
if(!target_appearance_with_filters)
target_appearance_with_filters = new(current_target)
// KEEP_APART in case carving block gets KEEP_TOGETHER from somewhere like material texture filters.
target_appearance_with_filters.appearance_flags |= KEEP_TOGETHER | KEEP_APART
//Doesn't use filter helpers because MAs aren't atoms
target_appearance_with_filters.filters = filter(type="color",color=greyscale_with_value_bump,space=FILTER_COLOR_HSV)
completion = value
var/static/icon/white = icon('icons/effects/alphacolors.dmi', "white")
switch(value)
if(0)
//delete uncovered and reset filters
remove_filter("partial_uncover")
target_appearance_with_filters = null
else
var/mask_offset = min(world.icon_size,round(completion * world.icon_size))
remove_filter("partial_uncover")
add_filter("partial_uncover", 1, alpha_mask_filter(icon = white, y = -mask_offset))
target_appearance_with_filters.filters = filter(type="alpha",icon=white,y=-mask_offset,flags=MASK_INVERSE)
update_appearance()
/// Returns a list of preset statues carvable from this block depending on the custom materials
/obj/structure/carving_block/proc/get_possible_statues()
. = list()
if(!statue_costs)
statue_costs = build_statue_cost_table()
for(var/statue_path in statue_costs)
var/list/carving_cost = statue_costs[statue_path]
var/enough_materials = TRUE
for(var/required_material in carving_cost)
if(!has_material_type(required_material, carving_cost[required_material]))
enough_materials = FALSE
break
if(enough_materials)
. += statue_path
/obj/structure/carving_block/proc/build_statue_cost_table()
. = list()
for(var/statue_type in subtypesof(/obj/structure/statue) - /obj/structure/statue/custom)
var/obj/structure/statue/S = new statue_type()
if(!S.icon_state || S.abstract_type == S.type || !S.custom_materials)
continue
.[S.type] = S.custom_materials
qdel(S)
/obj/structure/statue/custom
name = "custom statue"
icon_state = "base"
obj_flags = CAN_BE_HIT | UNIQUE_RENAME
appearance_flags = TILE_BOUND | PIXEL_SCALE | KEEP_TOGETHER | LONG_GLIDE //Added keep together in case targets has weird layering
material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
/// primary statue overlay
var/mutable_appearance/content_ma
var/static/list/greyscale_with_value_bump = list(0,0,0, 0,0,0, 0,0,1, 0,0,-0.05)
/obj/structure/statue/custom/Destroy()
content_ma = null
return ..()
/obj/structure/statue/custom/proc/set_visuals(model_appearance)
if(content_ma)
QDEL_NULL(content_ma)
content_ma = new
content_ma.appearance = model_appearance
content_ma.pixel_x = 0
content_ma.pixel_y = 0
content_ma.alpha = 255
var/static/list/plane_whitelist = list(FLOAT_PLANE, GAME_PLANE, FLOOR_PLANE)
/// Ideally we'd have knowledge what we're removing but i'd have to be done on target appearance retrieval
var/list/overlays_to_remove = list()
for(var/mutable_appearance/special_overlay as anything in content_ma.overlays)
var/mutable_appearance/real = new()
real.appearance = special_overlay
if(PLANE_TO_TRUE(real.plane) in plane_whitelist)
continue
overlays_to_remove += real
content_ma.overlays -= overlays_to_remove
var/list/underlays_to_remove = list()
for(var/mutable_appearance/special_underlay as anything in content_ma.underlays)
var/mutable_appearance/real = new()
real.appearance = special_underlay
if(PLANE_TO_TRUE(real.plane) in plane_whitelist)
continue
underlays_to_remove += real
content_ma.underlays -= underlays_to_remove
content_ma.appearance_flags &= ~KEEP_APART //Don't want this
content_ma.filters = filter(type="color",color=greyscale_with_value_bump,space=FILTER_COLOR_HSV)
update_content_planes()
update_appearance()
/obj/structure/statue/custom/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
if(same_z_layer)
return ..()
update_content_planes()
update_appearance()
/obj/structure/statue/custom/proc/update_content_planes()
if(!content_ma)
return
var/turf/our_turf = get_turf(src)
// MA's stored in the overlays list are not actually mutable, they've been flattened
// This proc unflattens them, updates them, and then reapplies
var/list/created = update_appearance_planes(list(content_ma), GET_TURF_PLANE_OFFSET(our_turf))
content_ma = created[1]
/obj/structure/statue/custom/update_overlays()
. = ..()
if(content_ma)
. += content_ma
#undef SCULPT_SOUND_INCREMENT