Files
Bubberstation/code/game/objects/effects/decals/cleanable.dm
LemonInTheDark e90a9b4b68 Flattens The Floor Plane (Camera Update Too) (#84350)
## About The Pull Request

Ok so like, side map right? It makes things higher up in the world
render above things lower down in the world.

Most of the time this is what we want, but it is NOT what we want for
floors.
Floors are allowed to be larger then 32x32, and if they are we want them
to render based off JUST their layer.
If we don't allow this grass turfs and others get cut off on their
bottom edge, which looks WEIRD.

In order to make this happen, we can add TOPDOWN_LAYER to every layer on
the floor plane and disable sidemap.

I've added documentation for this to VISUALS.md, and have also
implemented unit test errors to prevent mixing TOPDOWN layers with non
topdown planes (or vis versa).
This new test adds ~1 second to tests, which is I think a perfectly
scrumpulent number.

EDIT:

I nerd sniped myself and implemented sidemap layering and lighting for
cameras (also larger then 32x32 icon support for getflat)
The lighting isn't perfect, we don't handle things displaying in the
void all that well (I am convinced getflat blending is broken but I have
no debugger so I can't fix it properly), but it'll do.

This came up cause I had to fix another layering issue in cameras and
thought I might as well go all in.

![image](https://github.com/tgstation/tgstation/assets/58055496/601b422c-f6aa-42ba-bcd9-b1faebe236e3)


## Why It's Good For The Game

Old:

![image](https://github.com/tgstation/tgstation/assets/58055496/d4102386-420d-4346-b05c-b819e62d98d0)

New:

![image](https://github.com/tgstation/tgstation/assets/58055496/1f5e303e-adee-427d-8fe3-76c8f2dbe098)


## Changelog
🆑
fix: Grass turfs will render properly now. Reworked how floors render,
please report any bugs!
fix: Cameras now properly capture lighting
fix: The layering seen in photos should better match the actual game
/🆑
2024-07-04 12:10:41 -07:00

146 lines
5.2 KiB
Plaintext

/obj/effect/decal/cleanable
gender = PLURAL
plane = GAME_PLANE
layer = FLOOR_CLEAN_LAYER
var/list/random_icon_states = null
///I'm sorry but cleanable/blood code is ass, and so is blood_DNA
var/blood_state = ""
///0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
var/bloodiness = 0
///When two of these are on a same tile or do we need to merge them into just one?
var/mergeable_decal = TRUE
var/beauty = 0
///The type of cleaning required to clean the decal. See __DEFINES/cleaning.dm for the options
var/clean_type = CLEAN_TYPE_LIGHT_DECAL
///The reagent this decal holds. Leave blank for none.
var/datum/reagent/decal_reagent
///The amount of reagent this decal holds, if decal_reagent is defined
var/reagent_amount = 0
/// Creates a cleanable decal on a turf
/// Use this if your decal is one of one, and thus we should not spawn it if it's there already
/// Returns either the existing cleanable, the one we created, or null if we can't spawn on that turf
/turf/proc/spawn_unique_cleanable(obj/effect/decal/cleanable/cleanable_type)
// There is no need to spam unique cleanables, they don't stack and it just chews cpu
var/obj/effect/decal/cleanable/existing = locate(cleanable_type) in src
if(existing)
return existing
return new cleanable_type(src)
/obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases)
. = ..()
if (random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0)
icon_state = pick(random_icon_states)
create_reagents(300)
if(decal_reagent)
reagents.add_reagent(decal_reagent, reagent_amount)
if(loc && isturf(loc))
for(var/obj/effect/decal/cleanable/C in loc)
if(C != src && C.type == type && !QDELETED(C))
if (replace_decal(C))
handle_merge_decal(C)
return INITIALIZE_HINT_QDEL
if(LAZYLEN(diseases))
var/list/datum/disease/diseases_to_add = list()
for(var/datum/disease/D in diseases)
if(D.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)
diseases_to_add += D
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
AddElement(/datum/element/beauty, beauty)
var/turf/T = get_turf(src)
if(T && is_station_level(T.z))
SSblackbox.record_feedback("tally", "station_mess_created", 1, name)
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/decal/cleanable/Destroy()
var/turf/T = get_turf(src)
if(T && is_station_level(T.z))
SSblackbox.record_feedback("tally", "station_mess_destroyed", 1, name)
return ..()
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
return TRUE
/obj/effect/decal/cleanable/attackby(obj/item/W, mob/user, params)
if((istype(W, /obj/item/reagent_containers/cup) && !istype(W, /obj/item/reagent_containers/cup/rag)) || istype(W, /obj/item/reagent_containers/cup/glass))
if(src.reagents && W.reagents)
. = 1 //so the containers don't splash their content on the src while scooping.
if(!src.reagents.total_volume)
to_chat(user, span_notice("[src] isn't thick enough to scoop up!"))
return
if(W.reagents.total_volume >= W.reagents.maximum_volume)
to_chat(user, span_notice("[W] is full!"))
return
to_chat(user, span_notice("You scoop up [src] into [W]!"))
reagents.trans_to(W, reagents.total_volume, transferred_by = user)
if(!reagents.total_volume) //scooped up all of it
qdel(src)
return
if(W.get_temperature()) //todo: make heating a reagent holder proc
if(istype(W, /obj/item/cigarette))
return
else
var/hotness = W.get_temperature()
reagents.expose_temperature(hotness)
to_chat(user, span_notice("You heat [name] with [W]!"))
else
return ..()
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
if(reagents)
reagents.expose_temperature(exposed_temperature)
..()
//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/proc/on_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
if(iscarbon(AM) && blood_state && bloodiness >= 40)
SEND_SIGNAL(AM, COMSIG_STEP_ON_BLOOD, src)
update_appearance()
/obj/effect/decal/cleanable/wash(clean_types)
. = ..()
if (. || (clean_types & clean_type))
qdel(src)
return TRUE
return .
/**
* Checks if this decal is a valid decal that can be blood crawled in.
*/
/obj/effect/decal/cleanable/proc/can_bloodcrawl_in()
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
return bloodiness
return FALSE
/**
* Gets the color associated with the any blood present on this decal. If there is no blood, returns null.
*/
/obj/effect/decal/cleanable/proc/get_blood_color()
switch(blood_state)
if(BLOOD_STATE_HUMAN)
return rgb(149, 10, 10)
if(BLOOD_STATE_XENO)
return rgb(43, 186, 0)
if(BLOOD_STATE_OIL)
return rgb(22, 22, 22)
return null
/obj/effect/decal/cleanable/proc/handle_merge_decal(obj/effect/decal/cleanable/merger)
if(!merger)
return
if(merger.reagents && reagents)
reagents.trans_to(merger, reagents.total_volume)