mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-18 03:26:31 +01:00
useless update_appearance reduction, emissive_blocker micro optimization (saves a second of init) (#71658)
## About The Pull Request [Saves 0.2 seconds of init time. 50% of emissive blockers](https://github.com/tgstation/tgstation/commit/8318b648f6d32844aacbfb4c309152cd45801f5c) Emissive blockers are a decent expense during init, even these, which are the ones that update outside of initialize. I've inlined them, removed some redundant vars and checks, reduced the arg count, and shifted some things around. This ends up saving 200ms, or 50% of its total cost. I also shifted mutable_appearance about a bit. it's not a massive saving, but it is technically faster [Prevents a few redundant appearance_updates, saves 0.8 seconds of init](https://github.com/tgstation/tgstation/commit/5475cd778b66b22b1e2c8d86b2c6d59fb84f219a) Prequisit info: update_appearance is decently expensive It's good then to only do it if we have a reason to, right? Me and moth were shooting the shit about just general init time, and we came up with the idea of tracking which update_appearances actually "worked" and which didn't. That bit comes later, let's enjoy the fruits of that work first First, holograms were calling update_appearance on process, for almost no reason. I patched the one event they don't already "react" to, and then locked it behind a change decection if. good for live, doesn't impact init. Next, decals. If you add a decal to something before it inits, it'll react to the after successful init signal. The trouble is the same atom could have its appearance updated from this MORE then once, since decals can be stacked on tiles, and signal unregisters don't work once the signal is sent. So we add a flag to track if we've had this happen to us or not, so it only happens once. saves 80 ms Power! lots of things call power_change on init, often more then once. We'll update appearance for each of those calls, even if only one is an actual change. That's silly, better to track what sort of power we're using for our appearance and go off that changing This was taking about 300ms. Really stupid Icon smoothing. After emissive blockers were added, any change to something's icon smoothing would lead to an update_appearance call. Nasty shit, specially cause of walls, which don't even use emissive blockers. Ok then, so we'll always update appearance for movables, and will allow turfs that are interested to hook it manually. Not many of those anyhow This is slightly a dev ux thing, but it saves 600ms so I think it's worth it. Rare case anyway Telecomms: telecomm machines were updating appearance on process. This is to cover for them turning on/off on process. Better then to just check if on actually changed. This cost adds up midgame, doesn't impact init tho Materials: There's this update_appearance call in material on_apply. it doesn't do anything. The logs will lie to you and say it does, but it's just like reapplying emissives. It doesn't need to exist Saves like 50ms Canisters: Live thing, lots of time wasted updating appearance for no reason, lets see if we change anything first yes? [Uses defines to wrap update_appearance for tracking](https://github.com/tgstation/tgstation/commit/4fa82e1c9d93577aadb3c743f17196331f62e67c) [Undoes _update_appearance changes, instead reccomends 2 regexes to use](https://github.com/tgstation/tgstation/commit/a8c8fec57a4e43d1fa636b5ac68459903faa9fc5) I need file and line number for my tracking, so I need to override update_appearance calls, and also preferably not require every override of update_appearance to handle dummy file + line args. So instead, I created a wrapper proc that checks to see if appearanaces match (they're unique remember, the two of the same visual appearance will be equivalent) The trouble is I can't intercept JUST proc calls, or JUST function definitions with defines. it needs to be both. So I renamed the /update_appearance proc to /_update_appearance this way I can capture old uses, and don't need to worry about merge/dev brain skew ~~It does mean that all update_appearance proc definitions now look weird tho. My profiling is leaking into dev ux. I wish I had better templating.~~ **The above is no longer being pr'd**, it's instead just recommended via a few regexes adjacent to the define. Smelled wrong anyhow [Adds a setter for panel_open, so I can update_appearance on it](https://github.com/tgstation/tgstation/pull/71658/commits/cf1df8a69fc1a816391d085ee7419b14f9fe9167) ## Why It's Good For The Game Speed
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
// wrapper for update_appearance that lets me capture it in debug mode
|
||||
// Does not work for callbacks unfortunately, not sure how to feel about that
|
||||
// This only works if definitions of the proc get changed to _update_appearance with REGEX
|
||||
// See the _compile_options comment for the regexes to use for that
|
||||
#ifdef APPEARANCE_SUCCESS_TRACKING
|
||||
#define update_appearance(arguments...) wrap_update_appearance(__FILE__, __LINE__, ##arguments)
|
||||
#endif
|
||||
@@ -56,8 +56,13 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
|
||||
#define IS_PLAYER_COLORABLE_1 (1<<17)
|
||||
/// Whether or not this atom has contextual screentips when hovered OVER
|
||||
#define HAS_CONTEXTUAL_SCREENTIPS_1 (1<<18)
|
||||
// Whether or not this atom is storing contents for a disassociated storage object
|
||||
/// Whether or not this atom is storing contents for a disassociated storage object
|
||||
#define HAS_DISASSOCIATED_STORAGE_1 (1<<19)
|
||||
/// If this atom has experienced a decal element "init finished" sourced appearance update
|
||||
/// We use this to ensure stacked decals don't double up appearance updates for no rasin
|
||||
/// Flag as an optimization, don't make this a trait without profiling
|
||||
/// Yes I know this is a stupid flag, no you can't take him from me
|
||||
#define DECAL_INIT_UPDATE_EXPERIENCED_1 (1<<20)
|
||||
|
||||
// Update flags for [/atom/proc/update_appearance]
|
||||
/// Update the atom's name
|
||||
|
||||
@@ -10,23 +10,29 @@
|
||||
STAT_ENTRY[STAT_ENTRY_TIME] += STAT_TIME;\
|
||||
STAT_ENTRY[STAT_ENTRY_COUNT] += 1;
|
||||
|
||||
// Cost tracking macros, to be used in one proc
|
||||
// The static lists are under the assumption that costs and counting are global lists, and will therefor
|
||||
// Break during world init
|
||||
// Cost tracking macros, to be used in one proc. If you're using this raw you'll want to use global lists
|
||||
// If you don't you'll need another way of reading it
|
||||
#define INIT_COST(costs, counting) \
|
||||
var/list/_costs = costs; \
|
||||
var/list/_counting = counting; \
|
||||
var/usage = TICK_USAGE;
|
||||
|
||||
// Cost tracking macro for global lists, prevents erroring if GLOB has not yet been initialized
|
||||
#define INIT_COST_GLOBAL(costs, counting) \
|
||||
// STATIC cost tracking macro. Uses static lists instead of the normal global ones
|
||||
// Good for debug stuff, and for running before globals init
|
||||
#define INIT_COST_STATIC(...) \
|
||||
var/static/list/hidden_static_list_for_fun1 = list(); \
|
||||
var/static/list/hidden_static_list_for_fun2 = list(); \
|
||||
INIT_COST(hidden_static_list_for_fun1, hidden_static_list_for_fun2)
|
||||
|
||||
// Cost tracking macro for global lists, prevents erroring if GLOB has not yet been initialized
|
||||
#define INIT_COST_GLOBAL(costs, counting) \
|
||||
INIT_COST_STATIC() \
|
||||
if(GLOB){\
|
||||
costs = hidden_static_list_for_fun1; \
|
||||
counting = hidden_static_list_for_fun2 ; \
|
||||
} \
|
||||
INIT_COST(hidden_static_list_for_fun1, hidden_static_list_for_fun2)
|
||||
usage = TICK_USAGE;
|
||||
|
||||
|
||||
#define SET_COST(category) \
|
||||
do { \
|
||||
@@ -38,7 +44,10 @@
|
||||
|
||||
#define SET_COST_LINE(...) SET_COST("[__LINE__]")
|
||||
|
||||
#define EXPORT_STATS_TO_FILE_LATER(filename, costs, counts) \
|
||||
#define EXPORT_STATS_TO_JSON_LATER(filename, costs, counts) EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, stat_tracking_export_to_json_later)
|
||||
#define EXPORT_STATS_TO_CSV_LATER(filename, costs, counts) EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, stat_tracking_export_to_csv_later)
|
||||
|
||||
#define EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, proc) \
|
||||
do { \
|
||||
var/static/last_export = 0; \
|
||||
if (world.time - last_export > 1.1 SECONDS) { \
|
||||
@@ -46,7 +55,7 @@
|
||||
/* spawn() is used here because this is often used to track init times, where timers act oddly. */ \
|
||||
/* I was making timers and even after init times were complete, the timers didn't run :shrug: */ \
|
||||
spawn (1 SECONDS) { \
|
||||
stat_tracking_export_to_file_later(filename, costs, counts); \
|
||||
##proc(filename, costs, counts); \
|
||||
} \
|
||||
} \
|
||||
} while (FALSE);
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
if(_our_turf){\
|
||||
thing.plane = GET_NEW_PLANE(_cached_plane, GET_Z_PLANE_OFFSET(_our_turf.z));\
|
||||
}\
|
||||
else {\
|
||||
thing.plane = new_value;\
|
||||
}\
|
||||
}\
|
||||
else {\
|
||||
thing.plane = new_value;\
|
||||
|
||||
@@ -127,6 +127,12 @@ DEFINE_BITFIELD(smoothing_junction, list(
|
||||
CRASH("smooth_icon called for [src] with smoothing_flags == [smoothing_flags]")
|
||||
SEND_SIGNAL(src, COMSIG_ATOM_SMOOTHED_ICON)
|
||||
|
||||
// As a rule, movables will most always care about smoothing changes
|
||||
// Turfs on the other hand, don't, so we don't do the update for THEM unless they explicitly request it
|
||||
/atom/movable/smooth_icon()
|
||||
. = ..()
|
||||
update_appearance(~UPDATE_SMOOTHING)
|
||||
|
||||
/atom/proc/corners_diagonal_smooth(adjacencies)
|
||||
switch(adjacencies)
|
||||
if(NORTH_JUNCTION|WEST_JUNCTION)
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR].
|
||||
/proc/emissive_appearance(icon, icon_state = "", atom/offset_spokesman, layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE, offset_const)
|
||||
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const)
|
||||
// Note: alpha doesn't "do" anything, since it's overriden by the color set shortly after
|
||||
// Consider removing it someday? (I wonder if we made emissives blend right we could make alpha actually matter. dreams man, dreams)
|
||||
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, 255, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const)
|
||||
appearance.color = GLOB.emissive_color
|
||||
return appearance
|
||||
|
||||
// This is a semi hot proc, so we micro it. saves maybe 150ms
|
||||
// sorry :)
|
||||
/proc/fast_emissive_blocker(atom/make_blocker)
|
||||
// Note: alpha doesn't "do" anything, since it's overriden by the color set shortly after
|
||||
// Consider removing it someday?
|
||||
var/mutable_appearance/blocker = new()
|
||||
blocker.icon = make_blocker.icon
|
||||
blocker.icon_state = make_blocker.icon_state
|
||||
blocker.layer = make_blocker.layer
|
||||
blocker.appearance_flags |= make_blocker.appearance_flags | EMISSIVE_APPEARANCE_FLAGS
|
||||
blocker.dir = make_blocker.dir
|
||||
blocker.color = GLOB.em_block_color
|
||||
|
||||
// Note, we are ok with null turfs, that's not an error condition we'll just default to 0, the error would be
|
||||
// Not passing ANYTHING in, key difference
|
||||
SET_PLANE_EXPLICIT(blocker, EMISSIVE_PLANE, make_blocker)
|
||||
return blocker
|
||||
|
||||
/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EM_BLOCK_COLOR].
|
||||
/proc/emissive_blocker(icon, icon_state = "", atom/offset_spokesman, layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE, offset_const)
|
||||
// Note: alpha doesn't "do" anything, since it's overriden by the color set shortly after
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// For use with the stopwatch defines
|
||||
/proc/render_stats(list/stats, user, sort = GLOBAL_PROC_REF(cmp_generic_stat_item_time))
|
||||
sortTim(stats, sort, TRUE)
|
||||
|
||||
@@ -12,7 +13,8 @@
|
||||
|
||||
. = lines.Join("\n")
|
||||
|
||||
/proc/stat_tracking_export_to_file_later(filename, costs, counts)
|
||||
// For use with the set_cost defines
|
||||
/proc/stat_tracking_export_to_json_later(filename, costs, counts)
|
||||
if (IsAdminAdvancedProcCall())
|
||||
return
|
||||
|
||||
@@ -25,3 +27,15 @@
|
||||
)
|
||||
|
||||
rustg_file_write(json_encode(output), "[GLOB.log_directory]/[filename]")
|
||||
|
||||
/proc/stat_tracking_export_to_csv_later(filename, costs, counts)
|
||||
if (IsAdminAdvancedProcCall())
|
||||
return
|
||||
|
||||
var/list/output = list()
|
||||
|
||||
output += "key, cost, count"
|
||||
for (var/key in costs)
|
||||
output += "[replacetext(key, ",", "")], [replacetext(costs[key], ",", "")], [replacetext(counts[key], ",", "")]"
|
||||
|
||||
rustg_file_write(output.Join("\n"), "[GLOB.log_directory]/[filename]")
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
#ifdef TESTING
|
||||
#define DATUMVAR_DEBUGGING_MODE
|
||||
|
||||
/// Enables update_appearance "relevence" tracking
|
||||
/// This allows us to check which update_appearance procs are actually doing anything. Good thing to look in on once a year or so
|
||||
/// You'll need to run a two regexes/search and replaces to make it work
|
||||
/// First, one to convert type refs (PROC_REF.*)(update_appearance\)) -> $1_$2
|
||||
/// Second, one to convert definitions /update_appearance\( -> /_update_appearance(
|
||||
/// We'll use another define to convert uses of the proc over. That'll be all
|
||||
// #define APPEARANCE_SUCCESS_TRACKING
|
||||
|
||||
///Used to find the sources of harddels, quite laggy, don't be surpised if it freezes your client for a good while
|
||||
//#define REFERENCE_TRACKING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
|
||||
@@ -128,11 +128,11 @@
|
||||
/datum/element/decal/proc/late_update_icon(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(source && istype(source))
|
||||
if(istype(source) && !(source.flags_1 & DECAL_INIT_UPDATE_EXPERIENCED_1))
|
||||
source.flags_1 |= DECAL_INIT_UPDATE_EXPERIENCED_1 // I am so sorry, but it saves like 80ms I gotta
|
||||
source.update_appearance(UPDATE_OVERLAYS)
|
||||
UnregisterSignal(source, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)
|
||||
|
||||
|
||||
/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
|
||||
@@ -92,8 +92,6 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
else if(istype(source, /turf)) //turfs
|
||||
on_applied_turf(source, amount, material_flags)
|
||||
|
||||
source.update_appearance()
|
||||
|
||||
source.mat_update_desc(src)
|
||||
|
||||
///This proc is called when a material updates an object's description
|
||||
|
||||
@@ -24,27 +24,25 @@
|
||||
* offset_const - A constant to offset our plane by, so it renders on the right "z layer"
|
||||
**/
|
||||
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, atom/offset_spokesman, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE, offset_const)
|
||||
var/mutable_appearance/appearance = new()
|
||||
appearance.icon = icon
|
||||
appearance.icon_state = icon_state
|
||||
appearance.layer = layer
|
||||
appearance.alpha = alpha
|
||||
appearance.appearance_flags |= appearance_flags
|
||||
if(plane != FLOAT_PLANE)
|
||||
// Essentially, we allow users that only want one static offset to pass one in
|
||||
if(!isnull(offset_const))
|
||||
plane = GET_NEW_PLANE(plane, offset_const)
|
||||
// That, or you need to pass in some non null object to reference
|
||||
else if(isatom(offset_spokesman))
|
||||
// You need to pass in some non null object to reference
|
||||
if(isatom(offset_spokesman))
|
||||
// Note, we are ok with null turfs, that's not an error condition we'll just default to 0, the error would be
|
||||
// Not passing ANYTHING in, key difference
|
||||
var/turf/our_turf = get_turf(offset_spokesman)
|
||||
plane = MUTATE_PLANE(plane, our_turf)
|
||||
SET_PLANE_EXPLICIT(appearance, plane, offset_spokesman)
|
||||
// That or I'll let you pass in a static offset. Don't be stupid now
|
||||
else if(!isnull(offset_const))
|
||||
SET_PLANE_W_SCALAR(appearance, plane, offset_const)
|
||||
// otherwise if you're setting plane you better have the guts to back it up
|
||||
else
|
||||
stack_trace("No plane offset passed in as context for a non floating mutable appearance, things are gonna go to hell on multiz maps")
|
||||
else if(!isnull(offset_spokesman) && !isatom(offset_spokesman))
|
||||
stack_trace("Why did you pass in offset_spokesman as [offset_spokesman]? We need an atom to properly offset planes")
|
||||
|
||||
var/mutable_appearance/MA = new()
|
||||
MA.icon = icon
|
||||
MA.icon_state = icon_state
|
||||
MA.layer = layer
|
||||
MA.plane = plane
|
||||
MA.alpha = alpha
|
||||
MA.appearance_flags |= appearance_flags
|
||||
return MA
|
||||
return appearance
|
||||
|
||||
@@ -740,6 +740,24 @@
|
||||
. = list()
|
||||
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE_MORE, user, .)
|
||||
|
||||
/// Wrapper for _update_appearance that is only called when APPEARANCE_SUCCESS_TRACKING is defined
|
||||
#ifdef APPEARANCE_SUCCESS_TRACKING
|
||||
/atom/proc/wrap_update_appearance(file, line, updates)
|
||||
INIT_COST_STATIC()
|
||||
EXPORT_STATS_TO_CSV_LATER("appearance_efficency.csv", _costs, _counting)
|
||||
var/old_appearance = appearance
|
||||
|
||||
_update_appearance(updates)
|
||||
// We're checking to see if update_appearance DID anything to our appearance
|
||||
// If it didn't, or it produced the same thing, we'll mark it as such so it can potentially be opitmized
|
||||
if(old_appearance == appearance)
|
||||
SET_COST("SAME [file] [line]")
|
||||
return FALSE
|
||||
else
|
||||
SET_COST("DIFFERENT [file] [line]")
|
||||
return TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Updates the appearence of the icon
|
||||
*
|
||||
|
||||
@@ -204,9 +204,7 @@
|
||||
if(!blocks_emissive)
|
||||
return
|
||||
else if (blocks_emissive == EMISSIVE_BLOCK_GENERIC)
|
||||
var/mutable_appearance/gen_emissive_blocker = emissive_blocker(icon, icon_state, src, alpha = src.alpha, appearance_flags = src.appearance_flags)
|
||||
gen_emissive_blocker.dir = dir
|
||||
return gen_emissive_blocker
|
||||
return fast_emissive_blocker(src)
|
||||
else if(blocks_emissive == EMISSIVE_BLOCK_UNIQUE)
|
||||
if(!em_block && !QDELETED(src))
|
||||
render_target = ref(src)
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
var/market_verb = "Customer"
|
||||
var/payment_department = ACCOUNT_ENG
|
||||
|
||||
// For storing and overriding ui id
|
||||
/// For storing and overriding ui id
|
||||
var/tgui_id // ID of TGUI interface
|
||||
///Is this machine currently in the atmos machinery queue?
|
||||
var/atmos_processing = FALSE
|
||||
@@ -148,6 +148,9 @@
|
||||
var/always_area_sensitive = FALSE
|
||||
///Multiplier for power consumption.
|
||||
var/machine_power_rectifier = 1
|
||||
/// What was our power state the last time we updated its appearance?
|
||||
/// TRUE for on, FALSE for off, -1 for never checked
|
||||
var/appearance_power_state = -1
|
||||
|
||||
/obj/machinery/Initialize(mapload)
|
||||
if(!armor)
|
||||
@@ -542,6 +545,21 @@
|
||||
/obj/machinery/proc/on_set_is_operational(old_value)
|
||||
return
|
||||
|
||||
///Called when we want to change the value of the `panel_open` variable. Boolean.
|
||||
/obj/machinery/proc/set_panel_open(new_value)
|
||||
if(panel_open == new_value)
|
||||
return
|
||||
var/old_value = panel_open
|
||||
panel_open = new_value
|
||||
on_set_panel_open(old_value)
|
||||
|
||||
///Called when the value of `panel_open` changes, so we can react to it.
|
||||
/obj/machinery/proc/on_set_panel_open(old_value)
|
||||
return
|
||||
|
||||
/// Toggles the panel_open var. Defined for convienience
|
||||
/obj/machinery/proc/toggle_panel_open()
|
||||
set_panel_open(!panel_open)
|
||||
|
||||
/obj/machinery/can_interact(mob/user)
|
||||
if((machine_stat & (NOPOWER|BROKEN)) && !(interaction_flags_machine & INTERACT_MACHINE_OFFLINE)) // Check if the machine is broken, and if we can still interact with it if so
|
||||
@@ -849,12 +867,11 @@
|
||||
return FALSE
|
||||
|
||||
screwdriver.play_tool_sound(src, 50)
|
||||
if(!panel_open)
|
||||
panel_open = TRUE
|
||||
toggle_panel_open()
|
||||
if(panel_open)
|
||||
icon_state = icon_state_open
|
||||
to_chat(user, span_notice("You open the maintenance hatch of [src]."))
|
||||
else
|
||||
panel_open = FALSE
|
||||
icon_state = icon_state_closed
|
||||
to_chat(user, span_notice("You close the maintenance hatch of [src]."))
|
||||
return TRUE
|
||||
|
||||
@@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(announcement_systems)
|
||||
|
||||
/obj/machinery/announcement_system/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
to_chat(user, span_notice("You [panel_open ? "open" : "close"] the maintenance hatch of [src]."))
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
. = ..()
|
||||
if(built)
|
||||
setDir(ndir)
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
update_appearance()
|
||||
|
||||
if(!built && !device && device_type)
|
||||
|
||||
@@ -216,7 +216,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
|
||||
/obj/machinery/camera/screwdriver_act(mob/living/user, obj/item/I)
|
||||
if(..())
|
||||
return TRUE
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
to_chat(user, span_notice("You screw the camera's panel [panel_open ? "open" : "closed"]."))
|
||||
I.play_tool_sound(src)
|
||||
update_appearance()
|
||||
|
||||
@@ -735,7 +735,7 @@
|
||||
if(panel_open && detonated)
|
||||
to_chat(user, span_warning("[src] has no maintenance panel!"))
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
to_chat(user, span_notice("You [panel_open ? "open":"close"] the maintenance panel of the airlock."))
|
||||
tool.play_tool_sound(src)
|
||||
update_appearance()
|
||||
@@ -1295,8 +1295,7 @@
|
||||
/obj/machinery/door/airlock/proc/on_break()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!panel_open)
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
wires.cut_all()
|
||||
|
||||
/obj/machinery/door/airlock/emp_act(severity)
|
||||
|
||||
@@ -503,8 +503,7 @@
|
||||
return (IS_CULTIST(user) && !isAllPowerCut())
|
||||
|
||||
/obj/machinery/door/airlock/cult/on_break()
|
||||
if(!panel_open)
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
|
||||
/obj/machinery/door/airlock/cult/isElectrified()
|
||||
return FALSE
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
return
|
||||
add_fingerprint(user)
|
||||
tool.play_tool_sound(src)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
to_chat(user, span_notice("You [panel_open ? "open" : "close"] the maintenance panel."))
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
. = ..()
|
||||
if(building)
|
||||
buildstage = 0
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
if(name == initial(name))
|
||||
name = "[get_area_name(src)] [initial(name)]"
|
||||
update_appearance()
|
||||
@@ -256,7 +256,7 @@
|
||||
|
||||
if(tool.tool_behaviour == TOOL_SCREWDRIVER && buildstage == 2)
|
||||
tool.play_tool_sound(src)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
to_chat(user, span_notice("The wires have been [panel_open ? "exposed" : "unexposed"]."))
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
@@ -438,6 +438,7 @@ Possible to do for anyone motivated enough:
|
||||
if(!LAZYLEN(holo_calls))
|
||||
set_can_hear_flags(CAN_HEAR_ACTIVE_HOLOCALLS, FALSE)
|
||||
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
@@ -487,7 +488,7 @@ Possible to do for anyone motivated enough:
|
||||
if(outgoing_call)
|
||||
outgoing_call.Check()
|
||||
|
||||
ringing = FALSE
|
||||
var/are_ringing = FALSE
|
||||
|
||||
for(var/datum/holocall/holocall as anything in holo_calls)
|
||||
if(holocall.connected_holopad == src)
|
||||
@@ -503,9 +504,11 @@ Possible to do for anyone motivated enough:
|
||||
holocall.Disconnect(src)//can't answer calls while calling
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
|
||||
ringing = TRUE
|
||||
are_ringing = TRUE
|
||||
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
if(ringing != are_ringing)
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
ringing = are_ringing
|
||||
|
||||
/obj/machinery/holopad/proc/activate_holo(mob/living/user)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
|
||||
/obj/machinery/shieldgen/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src, 100)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
if(panel_open)
|
||||
to_chat(user, span_notice("You open the panel and expose the wiring."))
|
||||
else
|
||||
|
||||
@@ -96,6 +96,10 @@
|
||||
if(panel_open && display_panel)
|
||||
. += "[base_icon_state]-open"
|
||||
|
||||
/obj/machinery/space_heater/on_set_panel_open()
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/space_heater/process_atmos()
|
||||
if(!on || !is_operational)
|
||||
if (on) // If it's broken, turn it off too
|
||||
@@ -275,8 +279,7 @@
|
||||
|
||||
/obj/machinery/space_heater/constructed/Initialize(mapload)
|
||||
. = ..()
|
||||
panel_open = TRUE
|
||||
update_appearance()
|
||||
set_panel_open(TRUE)
|
||||
|
||||
/obj/machinery/space_heater/proc/toggle_power(user)
|
||||
on = !on
|
||||
|
||||
@@ -97,13 +97,17 @@
|
||||
line1 = uppertext(line1)
|
||||
line2 = uppertext(line2)
|
||||
|
||||
var/message_changed = FALSE
|
||||
if(line1 != message1)
|
||||
message1 = line1
|
||||
message_changed = TRUE
|
||||
|
||||
if(line2 != message2)
|
||||
message2 = line2
|
||||
message_changed = TRUE
|
||||
|
||||
update_appearance()
|
||||
if(message_changed)
|
||||
update_appearance()
|
||||
|
||||
/**
|
||||
* Remove both message objs and null the fields.
|
||||
|
||||
@@ -141,8 +141,12 @@ GLOBAL_LIST_EMPTY(telecomms_list)
|
||||
icon_state = "[initial(icon_state)][panel_open ? "_o" : null][on ? null : "_off"]"
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/proc/update_power()
|
||||
/obj/machinery/telecomms/on_set_panel_open(old_value)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/proc/update_power()
|
||||
var/old_on = on
|
||||
if(toggled)
|
||||
if(machine_stat & (BROKEN|NOPOWER|EMPED)) // if powered, on. if not powered, off. if too damaged, off
|
||||
on = FALSE
|
||||
@@ -153,13 +157,12 @@ GLOBAL_LIST_EMPTY(telecomms_list)
|
||||
else
|
||||
on = FALSE
|
||||
soundloop.stop()
|
||||
if(old_on != on)
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/telecomms/process(delta_time)
|
||||
update_power()
|
||||
|
||||
// Update the icon
|
||||
update_appearance()
|
||||
|
||||
if(traffic > 0)
|
||||
traffic -= netspeed * delta_time
|
||||
|
||||
|
||||
@@ -76,10 +76,10 @@
|
||||
|
||||
/obj/structure/sign/barsign/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src)
|
||||
if(!panel_open)
|
||||
panel_open = !panel_open
|
||||
if(panel_open)
|
||||
to_chat(user, span_notice("You open the maintenance panel."))
|
||||
set_sign(new /datum/barsign/hiddensigns/signoff)
|
||||
panel_open = TRUE
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
to_chat(user, span_notice("You close the maintenance panel."))
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
set_sign(new /datum/barsign/hiddensigns/signoff)
|
||||
else
|
||||
set_sign(chosen_sign)
|
||||
panel_open = FALSE
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
/obj/structure/sign/barsign/attackby(obj/item/I, mob/user)
|
||||
|
||||
@@ -197,6 +197,7 @@
|
||||
QUEUE_SMOOTH_NEIGHBORS(src)
|
||||
QUEUE_SMOOTH(src)
|
||||
|
||||
// We don't react to smoothing changing here because this else exists only to "revert" intact changes
|
||||
/turf/closed/wall/r_wall/update_icon_state()
|
||||
if(d_state != INTACT)
|
||||
icon_state = "r_wall-[d_state]"
|
||||
|
||||
@@ -423,6 +423,10 @@
|
||||
desc = "A glow-in-the-dark floor used to test emissive turfs."
|
||||
floor_tile = /obj/item/stack/tile/emissive_test
|
||||
|
||||
/turf/open/floor/emissive_test/smooth_icon()
|
||||
. = ..()
|
||||
update_appearance(~UPDATE_SMOOTHING)
|
||||
|
||||
/turf/open/floor/emissive_test/update_overlays()
|
||||
. = ..()
|
||||
. += emissive_appearance(icon, icon_state, src, alpha = src.alpha)
|
||||
|
||||
@@ -131,7 +131,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm)
|
||||
|
||||
if(nbuild)
|
||||
buildstage = AIRALARM_BUILD_NO_CIRCUIT
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
|
||||
if(name == initial(name))
|
||||
name = "[get_area_name(src)] Air Alarm"
|
||||
@@ -723,7 +723,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm)
|
||||
if(buildstage != AIRALARM_BUILD_COMPLETE)
|
||||
return
|
||||
tool.play_tool_sound(src)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
to_chat(user, span_notice("The wires have been [panel_open ? "exposed" : "unexposed"]."))
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
@@ -57,7 +57,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/bluespace_vendor, 30)
|
||||
. = ..()
|
||||
|
||||
if(nbuild)
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
|
||||
update_appearance()
|
||||
|
||||
|
||||
@@ -147,15 +147,15 @@
|
||||
if(generator)
|
||||
disconnectFromGenerator()
|
||||
mode = !mode
|
||||
to_chat(user, span_notice("You set [src] to [mode?"cold":"hot"] mode."))
|
||||
to_chat(user, span_notice("You set [src] to [mode ? "cold" : "hot"] mode."))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/circulator/screwdriver_act(mob/user, obj/item/I)
|
||||
if(..())
|
||||
return TRUE
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
I.play_tool_sound(src)
|
||||
to_chat(user, span_notice("You [panel_open?"open":"close"] the panel on [src]."))
|
||||
to_chat(user, span_notice("You [panel_open ? "open" : "close"] the panel on [src]."))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/circulator/crowbar_act(mob/user, obj/item/I)
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
/obj/machinery/electrolyzer/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src, 50)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
user.visible_message(span_notice("\The [user] [panel_open ? "opens" : "closes"] the hatch on \the [src]."), span_notice("You [panel_open ? "open" : "close"] the hatch on \the [src]."))
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
@@ -579,19 +579,25 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister())
|
||||
valve_open = !valve_open
|
||||
timing = FALSE
|
||||
|
||||
var/visual_update = FALSE
|
||||
// Handle gas transfer.
|
||||
if(valve_open)
|
||||
var/turf/location = get_turf(src)
|
||||
var/datum/gas_mixture/target_air = holding?.return_air() || location.return_air()
|
||||
excited = TRUE
|
||||
|
||||
if(air_contents.release_gas_to(target_air, release_pressure) && !holding)
|
||||
air_update_turf(FALSE, FALSE)
|
||||
if(air_contents.release_gas_to(target_air, release_pressure))
|
||||
visual_update = TRUE
|
||||
if(!holding)
|
||||
air_update_turf(FALSE, FALSE)
|
||||
|
||||
// A bit different than other atmos devices. Wont stop if currently taking damage.
|
||||
if(take_atmos_damage())
|
||||
visual_update = TRUE
|
||||
excited = TRUE
|
||||
update_appearance()
|
||||
|
||||
if(visual_update)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_state(mob/user)
|
||||
|
||||
@@ -161,12 +161,12 @@
|
||||
if(16 to 23)
|
||||
airlock.welded = TRUE
|
||||
if(24 to 30)
|
||||
airlock.panel_open = TRUE
|
||||
airlock.set_panel_open(TRUE)
|
||||
if(airlock.cutAiWire)
|
||||
airlock.wires.cut(WIRE_AI)
|
||||
if(airlock.autoname)
|
||||
airlock.name = get_area_name(src, TRUE)
|
||||
update_appearance()
|
||||
airlock.update_appearance()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/proc/payload(obj/machinery/door/airlock/payload)
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
if(obj_flags & EMAGGED)
|
||||
balloon_alert(user, "the interface is broken!")
|
||||
return
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
balloon_alert(user, "wires are [panel_open ? "exposed" : "unexposed"]")
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
@@ -151,6 +151,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
|
||||
icon_state = "l[cable_layer]-noconnection"
|
||||
return ..()
|
||||
|
||||
// TODO: stop doing this shit in update_icon_state, this should be event based for the love of all that is holy
|
||||
var/list/dir_icon_list = list()
|
||||
for(var/check_dir in GLOB.cardinals)
|
||||
if(linked_dirs & check_dir)
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
/obj/machinery/power/generator/screwdriver_act(mob/user, obj/item/I)
|
||||
if(..())
|
||||
return TRUE
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
I.play_tool_sound(src)
|
||||
to_chat(user, span_notice("You [panel_open?"open":"close"] the panel on [src]."))
|
||||
return TRUE
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
return
|
||||
else if(O.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
O.play_tool_sound(src)
|
||||
if(panel_open)
|
||||
to_chat(user, span_notice("You open the access panel."))
|
||||
|
||||
@@ -188,7 +188,14 @@
|
||||
if(!(initial_stat & NOPOWER))
|
||||
SEND_SIGNAL(src, COMSIG_MACHINERY_POWER_LOST)
|
||||
. = TRUE
|
||||
update_appearance()
|
||||
|
||||
if(appearance_power_state != (machine_stat & NOPOWER))
|
||||
update_appearance()
|
||||
|
||||
// Saves like 300ms of init by not duping calls in the above proc
|
||||
/obj/machinery/update_appearance(updates)
|
||||
. = ..()
|
||||
appearance_power_state = machine_stat & NOPOWER
|
||||
|
||||
// connect the machine to a powernet if a node cable or a terminal is present on the turf
|
||||
/obj/machinery/power/proc/connect_to_network()
|
||||
@@ -426,6 +433,6 @@
|
||||
return null
|
||||
for(var/obj/structure/cable/C in src)
|
||||
if(C.machinery_layer & machinery_layer)
|
||||
C.update_appearance()
|
||||
C.update_appearance() // I hate this. it's here because update_icon_state SCANS nearby turfs for objects to connect to. Wastes cpu time
|
||||
return C
|
||||
return null
|
||||
|
||||
@@ -95,13 +95,12 @@
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
tool.play_tool_sound(src, 50)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
if(panel_open)
|
||||
disable_parts(user)
|
||||
else
|
||||
enable_parts(user)
|
||||
var/descriptor = panel_open ? "open" : "close"
|
||||
balloon_alert(user, "you [descriptor] the maintenance hatch of [src]")
|
||||
balloon_alert(user, "you [panel_open ? "open" : "close"] the maintenance hatch of [src]")
|
||||
update_appearance()
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
add_fingerprint(user)
|
||||
if(!pressure_charging && !full_pressure && !flush)
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
panel_open = !panel_open
|
||||
toggle_panel_open()
|
||||
I.play_tool_sound(src)
|
||||
to_chat(user, span_notice("You [panel_open ? "remove":"attach"] the screws around the power connection."))
|
||||
return
|
||||
|
||||
@@ -1438,7 +1438,7 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
/obj/machinery/vending/custom/greed/Initialize(mapload)
|
||||
. = ..()
|
||||
//starts in a state where you can move it
|
||||
panel_open = TRUE
|
||||
set_panel_open(TRUE)
|
||||
set_anchored(FALSE)
|
||||
add_overlay(panel_type)
|
||||
//and references the deity
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "code\__DEFINES\alerts.dm"
|
||||
#include "code\__DEFINES\antagonists.dm"
|
||||
#include "code\__DEFINES\apc_defines.dm"
|
||||
#include "code\__DEFINES\appearance.dm"
|
||||
#include "code\__DEFINES\aquarium.dm"
|
||||
#include "code\__DEFINES\art.dm"
|
||||
#include "code\__DEFINES\assemblies.dm"
|
||||
|
||||
Reference in New Issue
Block a user