From ff75cf9d926f1f31bf816b8b172e3542d89532f2 Mon Sep 17 00:00:00 2001 From: Vi3trice <80771500+Vi3trice@users.noreply.github.com> Date: Sun, 25 Sep 2022 12:03:12 -0400 Subject: [PATCH] Rework firelocks, and update alarm light sprites (#19036) * when the fix to firelocks is in areas * Maybe * Clearer defines * Removing emissives. I'll explore that again later. * Revert "Removing emissives. I'll explore that again later." This reverts commit a5635f5230f5fb03c1cfd45db3e1648ffa2fe297. * Brilliance flashed before my eyes (Order of applied overlays matter) * Figured I'd update the documentation. --- code/__DEFINES/machines.dm | 5 ++ code/__HELPERS/lighting.dm | 2 +- code/game/area/areas.dm | 92 ++++++++++++++---------- code/game/machinery/doors/airlock.dm | 16 ++--- code/game/machinery/doors/door.dm | 12 ++-- code/game/machinery/doors/firedoor.dm | 46 ++++++++---- code/game/machinery/doors/windowdoor.dm | 16 ++--- icons/obj/doors/doorfire.dmi | Bin 8998 -> 9620 bytes 8 files changed, 113 insertions(+), 76 deletions(-) diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index 3a8662dedee..6e4d49aad9f 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -126,3 +126,8 @@ #define AI_DISPLAY_MODE_BLANK 0 #define AI_DISPLAY_MODE_EMOTE 1 #define AI_DISPLAY_MODE_BSOD 2 + +// Door operations +#define DOOR_OPENING 1 +#define DOOR_CLOSING 2 +#define DOOR_MALF 3 diff --git a/code/__HELPERS/lighting.dm b/code/__HELPERS/lighting.dm index fcba21227ab..55a0e2e53ec 100644 --- a/code/__HELPERS/lighting.dm +++ b/code/__HELPERS/lighting.dm @@ -1,4 +1,4 @@ -/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR]. +/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR]. Order of application matters: Default generated blockers are overlays, and will block its own emissive underlays. If you want an object to be both a blocker, and have their own emissive, it has to be an overlay instead. Grayscale lightmasks are visible in the BYOND right-click and Examine pane, unless they're covered up by another overlay. /proc/emissive_appearance(icon, icon_state = "", layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE) var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS) appearance.color = EMISSIVE_COLOR diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 2519224062e..94e81f2d785 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -146,29 +146,34 @@ return cameras /area/proc/air_doors_close() - if(!air_doors_activated) - air_doors_activated = TRUE - for(var/obj/machinery/door/firedoor/D in src) - if(!D.welded) - D.activate_alarm() - if(D.operating) - D.nextstate = FD_CLOSED - else if(!D.density) - spawn(0) - D.close() + if(air_doors_activated) + return + air_doors_activated = TRUE + for(var/obj/machinery/door/firedoor/D in src) + if(!D.is_operational()) + continue + D.activate_alarm() + if(D.welded) + continue + if(D.operating && D.operating != DOOR_CLOSING) + D.nextstate = FD_CLOSED + else if(!D.density) + INVOKE_ASYNC(D, /obj/machinery/door/firedoor.proc/close) /area/proc/air_doors_open() - if(air_doors_activated) - air_doors_activated = FALSE - for(var/obj/machinery/door/firedoor/D in src) - if(!D.welded) - D.deactivate_alarm() - if(D.operating) - D.nextstate = OPEN - else if(D.density) - spawn(0) - D.open() - + if(!air_doors_activated) + return + air_doors_activated = FALSE + for(var/obj/machinery/door/firedoor/D in src) + if(!D.is_operational()) + continue + D.deactivate_alarm() + if(D.welded) + continue + if(D.operating && D.operating != DOOR_OPENING) + D.nextstate = FD_OPEN + else if(D.density) + INVOKE_ASYNC(D, /obj/machinery/door/firedoor.proc/open) /area/Destroy() STOP_PROCESSING(SSobj, src) @@ -229,23 +234,34 @@ * Try to close all the firedoors in the area */ /area/proc/ModifyFiredoors(opening) - if(firedoors) - firedoors_last_closed_on = world.time - for(var/FD in firedoors) - var/obj/machinery/door/firedoor/D = FD - var/cont = !D.welded - if(cont && opening) //don't open if adjacent area is on fire - for(var/I in D.affecting_areas) - var/area/A = I - if(A.fire) - cont = FALSE - break - if(cont && D.is_operational()) - if(D.operating) - D.nextstate = opening ? FD_OPEN : FD_CLOSED - else if(!(D.density ^ opening)) - INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/open : /obj/machinery/door/firedoor.proc/close)) - INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/deactivate_alarm : /obj/machinery/door/firedoor.proc/activate_alarm)) + if(!firedoors) + return + firedoors_last_closed_on = world.time + for(var/obj/machinery/door/firedoor/D in firedoors) + if(!D.is_operational()) + continue + var/valid = TRUE + if(opening) //don't open if adjacent area is on fire + for(var/I in D.affecting_areas) + var/area/A = I + if(A.fire) + valid = FALSE + break + if(!valid) + continue + + // At this point, the area is safe and the door is technically functional. + + INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/deactivate_alarm : /obj/machinery/door/firedoor.proc/activate_alarm)) + if(D.welded) + continue // Alarm is toggled, but door stuck + if(D.operating) + if((D.operating == DOOR_OPENING && opening) || (D.operating == DOOR_CLOSING && !opening)) + continue + else + D.nextstate = opening ? FD_OPEN : FD_CLOSED + else if(D.density == opening) + INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/open : /obj/machinery/door/firedoor.proc/close)) /** * Generate a firealarm alert for this area diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 644c6c9ae3b..137e19562c7 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1233,7 +1233,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) if(!density) return TRUE SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN) - operating = TRUE + operating = DOOR_OPENING update_icon(AIRLOCK_OPENING, 1) sleep(1) set_opacity(0) @@ -1244,7 +1244,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) sleep(1) layer = OPEN_DOOR_LAYER update_icon(AIRLOCK_OPEN, 1) - operating = FALSE + operating = NONE return TRUE /obj/machinery/door/airlock/close(forced=0, override = 0) @@ -1274,7 +1274,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) killthis.ex_act(EXPLODE_HEAVY)//Smashin windows SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE) - operating = TRUE + operating = DOOR_CLOSING update_icon(AIRLOCK_CLOSING, 1) layer = CLOSED_DOOR_LAYER if(!override) @@ -1290,7 +1290,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) update_freelook_sight() sleep(1) update_icon(AIRLOCK_CLOSED, 1) - operating = FALSE + operating = NONE if(safe) CheckForMobs() return TRUE @@ -1326,13 +1326,13 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) /obj/machinery/door/airlock/emag_act(mob/user) if(!operating && density && arePowerSystemsOn() && !emagged) - operating = TRUE + operating = DOOR_MALF update_icon(AIRLOCK_EMAG, 1) sleep(6) if(QDELETED(src)) return electronics = new /obj/item/airlock_electronics/destroyed() - operating = FALSE + operating = NONE if(!open()) update_icon(AIRLOCK_CLOSED, 1) emagged = TRUE @@ -1341,12 +1341,12 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) /obj/machinery/door/airlock/cmag_act(mob/user) if(operating || HAS_TRAIT(src, TRAIT_CMAGGED) || !density || !arePowerSystemsOn()) return - operating = TRUE + operating = DOOR_MALF update_icon(AIRLOCK_EMAG, 1) sleep(6) if(QDELETED(src)) return - operating = FALSE + operating = NONE update_icon(AIRLOCK_CLOSED, 1) ADD_TRAIT(src, TRAIT_CMAGGED, "clown_emag") return TRUE diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index c6f82284212..0c442fd217e 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -14,8 +14,8 @@ damage_deflection = 10 var/closingLayer = CLOSED_DOOR_LAYER var/visible = TRUE - /// Is it currently in the process of opening or closing. - var/operating = FALSE + /// Is it currently in the process of opening, closing or being tampered + var/operating = NONE var/autoclose = FALSE /// Whether the door detects things and mobs in its way and reopen or crushes them. var/safe = TRUE @@ -383,7 +383,7 @@ if(operating) return SEND_SIGNAL(src, COMSIG_DOOR_OPEN) - operating = TRUE + operating = DOOR_OPENING do_animate("opening") set_opacity(0) sleep(5) @@ -392,7 +392,7 @@ layer = initial(layer) update_icon() set_opacity(0) - operating = FALSE + operating = NONE air_update_turf(1) update_freelook_sight() if(autoclose) @@ -413,7 +413,7 @@ return SEND_SIGNAL(src, COMSIG_DOOR_CLOSE) - operating = TRUE + operating = DOOR_CLOSING do_animate("closing") layer = closingLayer @@ -423,7 +423,7 @@ update_icon() if(!glass || polarized_on) set_opacity(TRUE) - operating = FALSE + operating = NONE air_update_turf(1) update_freelook_sight() if(safe) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index fc7a37b3b8c..a5ce9b0b5b8 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -85,8 +85,22 @@ latetoggle() else stat |= NOPOWER + adjust_light() update_icon() +/obj/machinery/door/firedoor/proc/adjust_light() + if(stat & (NOPOWER|BROKEN)) + set_light(0) + return + if(active_alarm) + set_light(1, 0.5, COLOR_RED_LIGHT) + else + set_light(1, LIGHTING_MINIMUM_POWER) + +/obj/machinery/door/firedoor/extinguish_light() + set_light(0) + update_icon(UPDATE_OVERLAYS) + /obj/machinery/door/firedoor/attack_hand(mob/user) if(operating || !density) return @@ -168,7 +182,7 @@ else WELDER_WELD_SUCCESS_MESSAGE welded = !welded - update_icon() + update_icon(UPDATE_OVERLAYS) /obj/machinery/door/firedoor/try_to_crowbar(obj/item/I, mob/user) if(welded || operating) @@ -209,20 +223,23 @@ /obj/machinery/door/firedoor/update_overlays() . = ..() - if(active_alarm && hasPower()) - . += image('icons/obj/doors/doorfire.dmi', "alarmlights") - if(density && welded) - . += "welded" - return if(welded) - . += "welded_open" + . += "welded[density ? "" : "_open"]" + if(active_alarm && hasPower()) + if(light) + . += emissive_appearance('icons/obj/doors/doorfire.dmi', "alarmlights_lightmask") + . += image('icons/obj/doors/doorfire.dmi', "alarmlights") /obj/machinery/door/firedoor/proc/activate_alarm() active_alarm = TRUE + adjust_light() update_icon() /obj/machinery/door/firedoor/proc/deactivate_alarm() active_alarm = FALSE + if(!density) + layer = initial(layer) + adjust_light() update_icon() /obj/machinery/door/firedoor/open(auto_close = TRUE) @@ -230,7 +247,8 @@ return . = ..() latetoggle(auto_close) - + if(active_alarm) + layer = closingLayer // Active firedoors take precedence and remain visible over closed airlocks. if(auto_close) autoclose = TRUE @@ -245,13 +263,11 @@ /obj/machinery/door/firedoor/proc/latetoggle(auto_close = TRUE) if(operating || !hasPower() || !nextstate) return - switch(nextstate) - if(FD_OPEN) - nextstate = null - open(auto_close) - if(FD_CLOSED) - nextstate = null - close() + if(nextstate == FD_OPEN) + INVOKE_ASYNC(src, .proc/open, auto_close) + if(nextstate == FD_CLOSED) + INVOKE_ASYNC(src, .proc/close) + nextstate = null /obj/machinery/door/firedoor/proc/forcetoggle(magic = FALSE, auto_close = TRUE) if(!magic && (operating || !hasPower())) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 2c0e51f0c22..dc00f7ca1cb 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -178,7 +178,7 @@ if(emagged) return 0 if(!operating) //in case of emag - operating = TRUE + operating = DOOR_OPENING do_animate("opening") set_opacity(FALSE) playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) @@ -191,7 +191,7 @@ update_freelook_sight() if(operating) //emag again - operating = FALSE + operating = NONE return 1 /obj/machinery/door/window/close(forced=0) @@ -203,7 +203,7 @@ if(forced < 2) if(emagged) return 0 - operating = TRUE + operating = DOOR_CLOSING do_animate("closing") playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) icon_state = base_state @@ -215,7 +215,7 @@ update_freelook_sight() sleep(10) - operating = FALSE + operating = NONE return 1 /obj/machinery/door/window/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) @@ -261,12 +261,12 @@ /obj/machinery/door/window/emag_act(mob/user, obj/weapon) if(!operating && density && !emagged) emagged = TRUE - operating = TRUE + operating = DOOR_MALF electronics = new /obj/item/airlock_electronics/destroyed() flick("[base_state]spark", src) playsound(src, "sparks", 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) sleep(6) - operating = FALSE + operating = NONE open(2) return 1 @@ -274,11 +274,11 @@ if(operating || !density || HAS_TRAIT(src, TRAIT_CMAGGED)) return ADD_TRAIT(src, TRAIT_CMAGGED, "clown_emag") - operating = TRUE + operating = DOOR_MALF flick("[base_state]spark", src) playsound(src, "sparks", 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) sleep(6) - operating = FALSE + operating = NONE return TRUE /obj/machinery/door/window/attackby(obj/item/I, mob/living/user, params) diff --git a/icons/obj/doors/doorfire.dmi b/icons/obj/doors/doorfire.dmi index d154a8436a00d1580184cd1675675a29c8ed3430..a20b20a1d90a6ad1fc3e75bfbdf59cd166a1193a 100644 GIT binary patch literal 9620 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 B=@tM0