Airlock variable door delay fixes (#91828)

## About The Pull Request

- Fixes airlock's run_animation from having a duplicate open in the
switch case instead of an open/closed.
- Completes the implementation of [Variable Door
Delay](https://github.com/tgstation/tgstation/pull/84631) on airlocks.
(The procs were made but never called in the airlock code.
- Implements a set_airlock_state that sets the airlock state as well as
managing operating status and animations instead of calling it
individually.

## Why It's Good For The Game

Fixes, less code duplication, airlocks use the new animation procs.

## Changelog

🆑 LT3
fix: Fixed incorrect opening case in variable door delay
code: Airlocks can have variable animation delay same as doors
/🆑
This commit is contained in:
LT3
2025-06-27 21:31:26 -06:00
committed by GitHub
parent 32bc3b9d04
commit c4877abb6f
4 changed files with 107 additions and 73 deletions
+5 -6
View File
@@ -6,9 +6,8 @@
#define AIRLOCK_LIGHT_OPENING "opening"
// Airlock physical states
#define AIRLOCK_CLOSED 1
#define AIRLOCK_CLOSING 2
#define AIRLOCK_OPEN 3
#define AIRLOCK_OPENING 4
#define AIRLOCK_DENY 5
#define AIRLOCK_EMAG 6
#define AIRLOCK_CLOSED "closed"
#define AIRLOCK_CLOSING "closing"
#define AIRLOCK_OPEN "open"
#define AIRLOCK_OPENING "opening"
#define AIRLOCK_DENY "deny"
+53 -42
View File
@@ -76,6 +76,7 @@
name = "Airlock"
icon = 'icons/obj/doors/airlocks/station/public.dmi'
icon_state = "closed"
base_icon_state = null
max_integrity = 300
var/normal_integrity = AIRLOCK_INTEGRITY_N
integrity_failure = 0.25
@@ -502,30 +503,44 @@
/obj/machinery/door/airlock/proc/is_secure()
return (security_level > 0)
/obj/machinery/door/airlock/update_icon(updates=ALL, state=0, override=FALSE)
if(operating && !override)
/**
* Set the airlock state to a new value, change the icon state
* and run the associated animation if required.
*/
/obj/machinery/door/airlock/proc/set_airlock_state(new_state, animated = FALSE)
if(!new_state)
new_state = density ? AIRLOCK_CLOSED : AIRLOCK_OPEN
airlock_state = new_state
if(animated)
operating = TRUE
run_animation(airlock_state)
return
operating = FALSE
set_animation()
if(!state)
state = density ? AIRLOCK_CLOSED : AIRLOCK_OPEN
airlock_state = state
/obj/machinery/door/airlock/update_icon(updates = ALL)
if(!airlock_state)
airlock_state = icon_state
. = ..()
return ..()
/obj/machinery/door/airlock/update_icon_state()
. = ..()
switch(airlock_state)
if(AIRLOCK_OPEN, AIRLOCK_CLOSED)
icon_state = ""
if(AIRLOCK_DENY, AIRLOCK_OPENING, AIRLOCK_CLOSING, AIRLOCK_EMAG)
icon_state = "nonexistenticonstate" //MADNESS
if(animation)
icon_state = "[base_icon_state][animation]"
else if(airlock_state == AIRLOCK_OPEN)
icon_state = "[base_icon_state]open"
else
icon_state = "[base_icon_state]closed"
/obj/machinery/door/airlock/update_overlays()
. = ..()
var/frame_state
var/light_state
switch(airlock_state)
if(machine_stat & MAINT) // in the process of being emagged
frame_state = AIRLOCK_FRAME_CLOSED
else switch(airlock_state)
if(AIRLOCK_CLOSED)
frame_state = AIRLOCK_FRAME_CLOSED
if(locked)
@@ -535,8 +550,6 @@
if(AIRLOCK_DENY)
frame_state = AIRLOCK_FRAME_CLOSED
light_state = AIRLOCK_LIGHT_DENIED
if(AIRLOCK_EMAG)
frame_state = AIRLOCK_FRAME_CLOSED
if(AIRLOCK_CLOSING)
frame_state = AIRLOCK_FRAME_CLOSING
light_state = AIRLOCK_LIGHT_CLOSING
@@ -557,10 +570,11 @@
if(panel_open)
. += get_airlock_overlay("panel_[frame_state][security_level ? "_protected" : null]", overlays_file, src, em_block = TRUE)
if(frame_state == AIRLOCK_FRAME_CLOSED && welded)
. += get_airlock_overlay("welded", overlays_file, src, em_block = TRUE)
if(airlock_state == AIRLOCK_EMAG)
if(machine_stat & MAINT) // in the process of being emagged
. += get_airlock_overlay("sparks", overlays_file, src, em_block = FALSE)
if(hasPower())
@@ -600,20 +614,21 @@
. += floorlight
/obj/machinery/door/airlock/run_animation(animation)
switch(animation)
if(DOOR_OPENING_ANIMATION)
update_icon(ALL, AIRLOCK_OPENING)
if(DOOR_OPENING_ANIMATION)
update_icon(ALL, AIRLOCK_CLOSING)
if(DOOR_DENY_ANIMATION)
if(!machine_stat)
update_icon(ALL, AIRLOCK_DENY)
playsound(src,doorDeni,50,FALSE,3)
addtimer(CALLBACK(src, PROC_REF(handle_deny_end)), AIRLOCK_DENY_ANIMATION_TIME)
if(animation == DOOR_DENY_ANIMATION)
if(machine_stat)
return
set_airlock_state(AIRLOCK_DENY, animated = FALSE)
return ..()
/obj/machinery/door/airlock/animation_effects(animation)
if(animation == DOOR_DENY_ANIMATION)
playsound(src, soundin = doorDeni, vol = 50, vary = FALSE, extrarange = 3)
addtimer(CALLBACK(src, PROC_REF(handle_deny_end)), AIRLOCK_DENY_ANIMATION_TIME)
/obj/machinery/door/airlock/proc/handle_deny_end()
if(airlock_state == AIRLOCK_DENY)
update_icon(ALL, AIRLOCK_CLOSED)
set_airlock_state(AIRLOCK_CLOSED, animated = FALSE)
/obj/machinery/door/airlock/animation_length(animation)
switch(animation)
@@ -1279,8 +1294,7 @@
addtimer(CALLBACK(cyclelinkedairlock, PROC_REF(close)), BYPASS_DOOR_CHECKS)
SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, forced)
operating = TRUE
update_icon(ALL, AIRLOCK_OPENING, TRUE)
set_airlock_state(AIRLOCK_OPENING, animated = TRUE)
var/transparent_delay = animation_segment_delay(AIRLOCK_OPENING_TRANSPARENT)
sleep(transparent_delay)
set_opacity(0)
@@ -1297,8 +1311,7 @@
var/open_delay = animation_segment_delay(AIRLOCK_OPENING_FINISHED) - transparent_delay - passable_delay
sleep(open_delay)
layer = OPEN_DOOR_LAYER
update_icon(ALL, AIRLOCK_OPEN, TRUE)
operating = FALSE
set_airlock_state(AIRLOCK_OPEN, animated = FALSE)
if(delayed_close_requested)
delayed_close_requested = FALSE
addtimer(CALLBACK(src, PROC_REF(close)), FORCING_DOOR_CHECKS)
@@ -1355,8 +1368,7 @@
if(killthis)
SSexplosions.med_mov_atom += killthis
SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE, forced)
operating = TRUE
update_icon(ALL, AIRLOCK_CLOSING, 1)
set_airlock_state(AIRLOCK_CLOSING, animated = TRUE)
layer = CLOSED_DOOR_LAYER
if(air_tight)
set_density(TRUE)
@@ -1383,8 +1395,7 @@
update_freelook_sight()
var/close_delay = animation_segment_delay(AIRLOCK_CLOSING_FINISHED) - unpassable_delay - opaque_delay
sleep(close_delay)
update_icon(ALL, AIRLOCK_CLOSED, 1)
operating = FALSE
set_airlock_state(AIRLOCK_CLOSED, animated = FALSE)
delayed_close_requested = FALSE
if(!dangerous_close)
CheckForMobs()
@@ -1457,8 +1468,9 @@
if(istype(emag_card, /obj/item/card/emag/doorjack))
var/obj/item/card/emag/doorjack/doorjack_card = emag_card
doorjack_card.use_charge(user)
set_machine_stat(machine_stat | MAINT) // flash the airlock lights and display some sparks
set_airlock_state(AIRLOCK_CLOSED)
operating = TRUE
update_icon(ALL, AIRLOCK_EMAG, 1)
addtimer(CALLBACK(src, PROC_REF(finish_emag_act)), 0.6 SECONDS)
return TRUE
return FALSE
@@ -1467,9 +1479,10 @@
/obj/machinery/door/airlock/proc/finish_emag_act()
if(QDELETED(src))
return FALSE
set_machine_stat(machine_stat & ~MAINT)
operating = FALSE
if(!open())
update_icon(ALL, AIRLOCK_CLOSED, 1)
set_airlock_state(AIRLOCK_CLOSED)
obj_flags |= EMAGGED
lights = FALSE
locked = TRUE
@@ -2529,19 +2542,17 @@
// set_density on both open and close procs has a check and return builtin.
/obj/machinery/door/airlock/instant/open(forced = DEFAULT_DOOR_CHECKS)
operating = TRUE
SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, forced)
operating = TRUE
set_density(FALSE)
operating = FALSE
update_appearance()
set_airlock_state(AIRLOCK_OPEN, animated = FALSE)
return TRUE
/obj/machinery/door/airlock/instant/close(forced = DEFAULT_DOOR_CHECKS, force_crush = FALSE)
operating = TRUE
SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE, forced)
operating = TRUE
set_density(TRUE)
operating = FALSE
update_appearance()
set_airlock_state(AIRLOCK_CLOSED, animated = FALSE)
return TRUE
/obj/machinery/door/airlock/instant/glass
+5 -5
View File
@@ -436,17 +436,17 @@
switch(animation)
if(DOOR_OPENING_ANIMATION)
if(panel_open)
icon_state = "o_door_opening"
icon_state = "o_[base_icon_state]_opening"
else
icon_state = "door_opening"
icon_state = "[base_icon_state]_opening"
if(DOOR_CLOSING_ANIMATION)
if(panel_open)
icon_state = "o_door_closing"
icon_state = "o_[base_icon_state]_closing"
else
icon_state = "door_closing"
icon_state = "[base_icon_state]_closing"
if(DOOR_DENY_ANIMATION)
if(!machine_stat)
icon_state = "door_deny"
icon_state = "[base_icon_state]_deny"
else
icon_state = "[base_icon_state]_[density ? "closed" : "open"]"
+44 -20
View File
@@ -30,36 +30,37 @@
id_tag = assign_random_name()
/obj/machinery/door/airlock/tram/open(forced = DEFAULT_DOOR_CHECKS)
if(operating || welded || locked || seal)
if(welded || locked || seal)
return FALSE
if(!density)
return TRUE
if(forced == DEFAULT_DOOR_CHECKS && (!hasPower() || wires.is_cut(WIRE_OPEN)))
if(forced == DEFAULT_DOOR_CHECKS && (operating || !hasPower() || wires.is_cut(WIRE_OPEN)))
return FALSE
SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, FALSE)
operating = TRUE
update_icon(ALL, AIRLOCK_OPENING, TRUE)
set_airlock_state(AIRLOCK_OPENING, animated = TRUE)
var/passable_delay
if(forced >= BYPASS_DOOR_CHECKS)
playsound(src, 'sound/machines/airlock/airlockforced.ogg', vol = 40, vary = FALSE)
sleep(TRAM_DOOR_CYCLE_TIME)
passable_delay = 0
else
playsound(src, doorOpen, vol = 40, vary = FALSE)
sleep(TRAM_DOOR_WARNING_TIME)
passable_delay = animation_segment_delay(AIRLOCK_OPENING_PASSABLE)
sleep(passable_delay)
set_density(FALSE)
if(!isnull(filler))
filler.set_density(FALSE)
update_freelook_sight()
flags_1 &= ~PREVENT_CLICK_UNDER_1
air_update_turf(TRUE, FALSE)
sleep(TRAM_DOOR_WARNING_TIME)
var/open_delay = animation_segment_delay(AIRLOCK_OPENING_FINISHED) - passable_delay
sleep(open_delay)
layer = OPEN_DOOR_LAYER
update_icon(ALL, AIRLOCK_OPEN, TRUE)
operating = FALSE
set_airlock_state(AIRLOCK_OPEN, animated = FALSE)
return TRUE
@@ -93,10 +94,10 @@
playsound(src, SFX_SPARKS, vol = 75, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
use_energy(50 JOULES)
playsound(src, doorClose, vol = 40, vary = FALSE)
operating = TRUE
layer = CLOSED_DOOR_LAYER
update_icon(ALL, AIRLOCK_CLOSING, 1)
sleep(TRAM_DOOR_WARNING_TIME)
set_airlock_state(AIRLOCK_CLOSING, animated = TRUE)
var/unpassable_delay = animation_segment_delay(AIRLOCK_CLOSING_UNPASSABLE)
sleep(unpassable_delay)
if(!hungry_door)
for(var/turf/checked_turf in locs)
for(var/atom/movable/blocker in checked_turf)
@@ -104,11 +105,11 @@
say("Please stand clear of the doors!")
playsound(src, 'sound/machines/buzz/buzz-sigh.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
layer = OPEN_DOOR_LAYER
update_icon(ALL, AIRLOCK_OPEN, 1)
operating = FALSE
set_airlock_state(AIRLOCK_OPEN, animated = FALSE)
return FALSE
SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE)
sleep(TRAM_DOOR_CRUSH_TIME)
var/opaque_delay = animation_segment_delay(AIRLOCK_CLOSING_OPAQUE) - unpassable_delay
sleep(opaque_delay)
set_density(TRUE)
if(!isnull(filler))
filler.set_density(TRUE)
@@ -117,12 +118,34 @@
air_update_turf(TRUE, TRUE)
crush()
crushing_in_progress = FALSE
sleep(TRAM_DOOR_WARNING_TIME)
update_icon(ALL, AIRLOCK_CLOSED, 1)
operating = FALSE
var/close_delay = animation_segment_delay(AIRLOCK_CLOSING_FINISHED) - unpassable_delay - opaque_delay
sleep(close_delay)
set_airlock_state(AIRLOCK_CLOSED, animated = FALSE)
retry_counter = 0
return TRUE
/obj/machinery/door/airlock/tram/animation_length(animation)
switch(animation)
if(DOOR_OPENING_ANIMATION)
return 1.8 SECONDS
if(DOOR_CLOSING_ANIMATION)
return 2.5 SECONDS
/obj/machinery/door/airlock/tram/animation_segment_delay(animation)
switch(animation)
if(AIRLOCK_OPENING_TRANSPARENT)
return 0.9 SECONDS
if(AIRLOCK_OPENING_PASSABLE)
return 0.9 SECONDS
if(AIRLOCK_OPENING_FINISHED)
return 1.8 SECONDS
if(AIRLOCK_CLOSING_UNPASSABLE)
return 0.9 SECONDS
if(AIRLOCK_CLOSING_OPAQUE)
return 1.6 SECONDS
if(AIRLOCK_CLOSING_FINISHED)
return 2.5 SECONDS
/**
* Crush the jerk holding up the tram from moving
*
@@ -235,8 +258,9 @@
return
if((tram_part.travel_remaining < DEFAULT_TRAM_LENGTH || tram_part.travel_remaining > tram_part.travel_trip_length - DEFAULT_TRAM_LENGTH) && tram_part.controller_active)
return // we're already animating, don't reset that
open(forced = BYPASS_DOOR_CHECKS)
return
set_airlock_state(AIRLOCK_OPENING, animated = TRUE)
if(do_after(user, delay = 0.6 SECONDS, timed_action_flags = IGNORE_USER_LOC_CHANGE | IGNORE_SLOWDOWNS))
open(forced = BYPASS_DOOR_CHECKS)
#undef TRAM_DOOR_WARNING_TIME
#undef TRAM_DOOR_CYCLE_TIME