Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Elementize decals. #27104

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions code/__DEFINES/dcs/atom_signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

// /atom

// from SSatoms InitAtom - Only if the atom was not deleted or failed initialization
#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE "atom_init_success"
///from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMSIG_PARENT_ATTACKBY "atom_attackby"
///Return this in response if you don't want afterattack to be called
Expand Down Expand Up @@ -69,6 +71,8 @@
#define COMSIG_ATOM_SET_LIGHT "atom_set_light"
///from base of atom/setDir(): (old_dir, new_dir)
#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change"
///from [/datum/controller/subsystem/processing/dcs/proc/rotate_decals]: (list/datum/element/decal/rotating)
#define COMSIG_ATOM_DECALS_ROTATING "atom_decals_rotating"
///from base of atom/has_gravity(): (turf/location, list/forced_gravities)
#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity"
///from proc/get_rad_contents(): ()
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/basetype_signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@

///from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
#define COMSIG_TURF_CHANGE "turf_change"
///from base of turf/proc/onShuttleMove(): (turf/new_turf)
#define COMSIG_TURF_ON_SHUTTLE_MOVE "turf_on_shuttle_move"
6 changes: 4 additions & 2 deletions code/__DEFINES/dcs/datum_signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@
#define COMSIG_SONG_END "song_end"


// /datum/component/decal
// /datum/element/decal

///called on an object to clean it of cleanables. Usualy with soap: (num/strength)
///called on an object to clean it of cleanables.
#define COMSIG_COMPONENT_CLEAN_ACT "clean_act"
///Returned by cleanable components when they are cleaned.
#define COMPONENT_CLEANED (1<<0)


// /datum/component/two_handed
Expand Down
3 changes: 3 additions & 0 deletions code/__DEFINES/flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
#define INFORM_ADMINS_ON_RELOCATE_2 (1<<5)
#define BANG_PROTECT_2 (1<<6)
#define BLOCKS_LIGHT_2 (1<<7) // Light sources placed in anything with that flag will not emit light through them.
/// Whether a decal element's parent has already been initialized and thus has already had its decals attached.
/// see https://github.com/tgstation/tgstation/pull/71658 for a detailed explanation of the flag.
#define DECAL_INIT_UPDATE_EXPERIENCED_2 (1<<8)

// A mob with OMNITONGUE has no restriction in the ability to speak
// languages that they know. So even if they wouldn't normally be able to
Expand Down
8 changes: 0 additions & 8 deletions code/__DEFINES/misc_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -466,14 +466,6 @@
#define PLACE_SPACE_RUIN "space"
#define PLACE_LAVA_RUIN "lavaland"

//Cleaning tool strength
// 1 is also a valid cleaning strength but completely unused so left undefined
#define CLEAN_WEAK 2
#define CLEAN_MEDIUM 3 // Acceptable tools
#define CLEAN_STRONG 4 // Industrial strength
#define CLEAN_IMPRESSIVE 5 // Cleaning strong enough your granny would be proud
#define CLEAN_GOD 6 // Cleans things spotless down to the atomic structure

//Ghost orbit types:
#define GHOST_ORBIT_CIRCLE "circle"
#define GHOST_ORBIT_TRIANGLE "triangle"
Expand Down
2 changes: 2 additions & 0 deletions code/controllers/subsystem/non_firing/SSatoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ SUBSYSTEM_DEF(atoms)
qdeleted = TRUE
else if(!A.initialized)
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
else
SEND_SIGNAL(A, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)

return qdeleted || QDELING(A)

Expand Down
75 changes: 0 additions & 75 deletions code/datums/components/decal.dm

This file was deleted.

177 changes: 177 additions & 0 deletions code/datums/elements/decal_element.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// NOTE:
// This is an incredibly piecemeal port of /tg/'s decal element.
// It does not include several pieces of functionality that exist in /tg/.
//
// Namely:
// - It does not support smoothing decals
// - It does not send a signal when a decal is detached (used for trapdoors on /tg/)
// - It does not support custom plane configuration as this behavior seems primarily concerned with multi-z

/datum/element/decal
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH_ON_HOST_DESTROY
argument_hash_start_idx = 2
/// Whether this decal can be cleaned.
var/cleanable
/// A description this decal appends to the target's examine message.
var/description
/// If true this was initialized with no set direction - will follow the parent dir.
var/directional
/// The base icon state that this decal was initialized with.
var/base_icon_state
/// The overlay applied by this decal to the target.
var/mutable_appearance/pic

/datum/element/decal/Attach(atom/target, _icon, _icon_state, _dir, _layer=TURF_LAYER, _alpha=255, _color, _cleanable=FALSE, _description, mutable_appearance/_pic)
. = ..()
if(!isatom(target))
return ELEMENT_INCOMPATIBLE
if(_pic)
pic = _pic
else if(!generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha, target))
return ELEMENT_INCOMPATIBLE
description = _description
cleanable = _cleanable
directional = _dir
base_icon_state = _icon_state

RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(apply_overlay), TRUE)
if(target.initialized)
target.update_appearance(UPDATE_OVERLAYS) //could use some queuing here now maybe.
else
RegisterSignal(target, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE, PROC_REF(late_update_icon), TRUE)
if(isitem(target))
INVOKE_ASYNC(target, TYPE_PROC_REF(/obj/item/, update_slot_icon), TRUE)
if(_dir)
RegisterSignal(target, COMSIG_ATOM_DECALS_ROTATING, PROC_REF(shuttle_rotate), TRUE)
SSdcs.RegisterSignal(target, COMSIG_ATOM_DIR_CHANGE, TYPE_PROC_REF(/datum/controller/subsystem/processing/dcs, rotate_decals), override=TRUE)
if(_cleanable)
RegisterSignal(target, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean_react), TRUE)
if(_description)
RegisterSignal(target, COMSIG_PARENT_EXAMINE, PROC_REF(examine), TRUE)

RegisterSignal(target, COMSIG_TURF_ON_SHUTTLE_MOVE, PROC_REF(shuttle_move_react), TRUE)

/// Remove old decals and apply new decals after rotation as necessary
/datum/controller/subsystem/processing/dcs/proc/rotate_decals(datum/source, old_dir, new_dir)
SIGNAL_HANDLER // COMSIG_ATOM_DIR_CHANGE

if(old_dir == new_dir)
return

var/list/datum/element/decal/old_decals = list() //instances
SEND_SIGNAL(source, COMSIG_ATOM_DECALS_ROTATING, old_decals)

if(!length(old_decals))
UnregisterSignal(source, COMSIG_ATOM_DIR_CHANGE)
return

var/list/resulting_decals_params = list() // param lists
for(var/datum/element/decal/rotating as anything in old_decals)
resulting_decals_params += list(rotating.get_rotated_parameters(old_dir,new_dir))

//Instead we could generate ids and only remove duplicates to save on churn on four-corners symmetry ?
for(var/datum/element/decal/decal in old_decals)
decal.Detach(source)

for(var/result in resulting_decals_params)
source.AddElement(/datum/element/decal, result["icon"], result["icon_state"], result["dir"], result["layer"], result["alpha"], result["color"], result["cleanable"], result["desc"])

/datum/element/decal/proc/get_rotated_parameters(old_dir,new_dir)
var/rotation = 0
if(directional) //Even when the dirs are the same rotation is coming out as not 0 for some reason
rotation = SIMPLIFY_DEGREES(dir2angle(new_dir)-dir2angle(old_dir))
new_dir = turn(pic.dir,-rotation)
return list(
"icon" = pic.icon,
"icon_state" = base_icon_state,
"dir" = new_dir,
"plane" = pic.plane,
"layer" = pic.layer,
"alpha" = pic.alpha,
"color" = pic.color,
"cleanable" = cleanable,
"desc" = description
)

/datum/element/decal/proc/late_update_icon(atom/source)
SIGNAL_HANDLER // COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE

if(istype(source) && !(source.flags_2 & DECAL_INIT_UPDATE_EXPERIENCED_2))
source.flags_2 |= DECAL_INIT_UPDATE_EXPERIENCED_2
source.update_appearance(UPDATE_OVERLAYS)
UnregisterSignal(source, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)

/**
* If the decal was not given an appearance, it will generate one based on the other given arguments.
* element won't be compatible if it cannot do either
* all args are fed into creating an image, they are byond vars for images you'll recognize in the byond docs
* (except source, source is the object whose appearance we're copying.)
*/
/datum/element/decal/proc/generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha, source)
if(!_icon || !_icon_state)
return FALSE
var/temp_image = image(_icon, null, _icon_state, _layer, _dir)
pic = new(temp_image)
pic.color = _color
pic.alpha = _alpha
return TRUE

/datum/element/decal/Detach(atom/source)
UnregisterSignal(source, list(
COMSIG_ATOM_DIR_CHANGE,
COMSIG_COMPONENT_CLEAN_ACT,
COMSIG_PARENT_EXAMINE,
COMSIG_ATOM_UPDATE_OVERLAYS,
COMSIG_TURF_ON_SHUTTLE_MOVE,
COMSIG_ATOM_DECALS_ROTATING
))
SSdcs.UnregisterSignal(source, COMSIG_ATOM_DIR_CHANGE)
source.update_appearance(UPDATE_OVERLAYS)
if(isitem(source))
INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item/, update_slot_icon))
return ..()

/datum/element/decal/proc/apply_overlay(atom/source)
SIGNAL_HANDLER // COMSIG_ATOM_UPDATE_OVERLAYS

source.add_overlay(pic)
// TODO: Fix this disgusting hack
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noting the todo here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. left as an exercise for the next poor sap to touch this code (probably me)

//
// `COMSIG_ATOM_UPDATE_OVERLAYS` is sent at the end of
// /atom/proc/update_icon's stanza for updating overlays, instead
// somewhere useful, like, during it. /tg/ handles this by sending
// a list of overlays with the signal, allowing receivers to add to
// the list, instead of returning their own.
//
// This is much saner and more flexible, but would require refactoring
// many many uses of update_overlay() across the code base, which is left
// as an exercise for the next poor sap to touch this code (probably me).
if(source.managed_overlays && !islist(source.managed_overlays))
source.managed_overlays = list(source.managed_overlays, pic)
else
LAZYDISTINCTADD(source.managed_overlays, pic)

/datum/element/decal/proc/clean_react(datum/source, clean_types)
SIGNAL_HANDLER // COMSIG_COMPONENT_CLEAN_ACT

if(clean_types & cleanable)
Detach(source)
return COMPONENT_CLEANED
return NONE

/datum/element/decal/proc/examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER // COMSIG_PARENT_EXAMINE

examine_list += description

/datum/element/decal/proc/shuttle_move_react(datum/source, turf/new_turf)
SIGNAL_HANDLER // COMSIG_TURF_ON_SHUTTLE_MOVE

if(new_turf == source)
return
Detach(source)
new_turf.AddElement(type, pic.icon, base_icon_state, directional, pic.layer, pic.alpha, pic.color, cleanable, description)

/datum/element/decal/proc/shuttle_rotate(datum/source, list/datum/element/decal/rotating)
SIGNAL_HANDLER // COMSIG_ATOM_DECALS_ROTATING
rotating += src
3 changes: 2 additions & 1 deletion code/game/objects/effects/decals/turf_decal.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
var/turf/T = loc
if(!istype(T)) //you know this will happen somehow
CRASH("Turf decal initialized in an object/nullspace")
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)

T.AddElement(/datum/element/decal, icon, icon_state, dir, layer, alpha, color, FALSE, null)
2 changes: 2 additions & 0 deletions code/modules/shuttle/shuttle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,8 @@
continue
AM.onShuttleMove(T0, T1, rotation, mobile_port.last_caller)

SEND_SIGNAL(T0, COMSIG_TURF_ON_SHUTTLE_MOVE, T1)

if(rotation)
T1.shuttleRotate(rotation)

Expand Down
2 changes: 1 addition & 1 deletion paradise.dme
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,6 @@
#include "code\datums\components\cult_held_body.dm"
#include "code\datums\components\deadchat_control.dm"
#include "code\datums\components\debris.dm"
#include "code\datums\components\decal.dm"
#include "code\datums\components\defibrillator.dm"
#include "code\datums\components\ducttape.dm"
#include "code\datums\components\edit_complainer.dm"
Expand Down Expand Up @@ -525,6 +524,7 @@
#include "code\datums\elements\atmos_requirements.dm"
#include "code\datums\elements\body_temperature.dm"
#include "code\datums\elements\bombable_turf.dm"
#include "code\datums\elements\decal_element.dm"
#include "code\datums\elements\earhealing.dm"
#include "code\datums\elements\rad_insulation.dm"
#include "code\datums\elements\ridable.dm"
Expand Down