diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index 1cc97f39763..fb0a6e00ada 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -43,6 +43,14 @@ #define SHOCK (1<<3) #define SAFE (1<<4) +//defines to be used with the door's open()/close() procs in order to discriminate what type of open is being done. The door will never open if it's been physically disabled (i.e. welded, sealed, etc.). +/// We should go through the door's normal opening procedure, no overrides. +#define DEFAULT_DOOR_CHECKS 0 +/// We're not going through the door's normal opening procedure, we're forcing it open. Can still fail if it's emagged or something. Costs power. +#define FORCING_DOOR_CHECKS 1 +/// We are getting this door open if it has not been physically held shut somehow. Play a special sound to signify this level of opening. +#define BYPASS_DOOR_CHECKS 2 + //used in design to specify which machine can build it #define IMPRINTER (1<<0) //For circuits. Uses glass/chemicals. #define PROTOLATHE (1<<1) //New stuff. Uses various minerals diff --git a/code/datums/components/pry_open_door.dm b/code/datums/components/pry_open_door.dm index 11abf36d190..17e445d25ca 100644 --- a/code/datums/components/pry_open_door.dm +++ b/code/datums/components/pry_open_door.dm @@ -44,9 +44,9 @@ if(airlock_target.locked) return attacker.visible_message(span_warning("We force the [airlock_target] to open.")) - airlock_target.open(2) + airlock_target.open(BYPASS_DOOR_CHECKS) else if(!airlock_target.hasPower()) attacker.visible_message(span_warning("We force the [airlock_target] to open.")) - airlock_target.open(1) + airlock_target.open(FORCING_DOOR_CHECKS) else - airlock_target.open(0) + airlock_target.open(DEFAULT_DOOR_CHECKS) diff --git a/code/game/machinery/airlock_control.dm b/code/game/machinery/airlock_control.dm index d2aef08ecf3..004eb1cde39 100644 --- a/code/game/machinery/airlock_control.dm +++ b/code/game/machinery/airlock_control.dm @@ -18,7 +18,7 @@ update_appearance() stoplag(0.2 SECONDS) - open(forced = TRUE) + open(FORCING_DOOR_CHECKS) locked = TRUE update_appearance() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 476056ae292..40879ab6150 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1090,9 +1090,9 @@ if(check_electrified && shock(user,100)) prying_so_hard = FALSE return - open(2) + open(BYPASS_DOOR_CHECKS) take_damage(25, BRUTE, 0, 0) // Enough to sometimes spark - if(density && !open(2)) + if(density && !open(BYPASS_DOOR_CHECKS)) to_chat(user, span_warning("Despite your attempts, [src] refuses to open.")) prying_so_hard = FALSE return @@ -1103,31 +1103,24 @@ if(istype(I, /obj/item/fireaxe) && !HAS_TRAIT(I, TRAIT_WIELDED)) //being fireaxe'd to_chat(user, span_warning("You need to be wielding [I] to do that!")) return - INVOKE_ASYNC(src, density ? PROC_REF(open) : PROC_REF(close), 2) + INVOKE_ASYNC(src, density ? PROC_REF(open) : PROC_REF(close), BYPASS_DOOR_CHECKS) -/obj/machinery/door/airlock/open(forced=0) +/obj/machinery/door/airlock/open(forced = DEFAULT_DOOR_CHECKS) if( operating || welded || locked || seal ) return FALSE - if(!forced) - if(!hasPower() || wires.is_cut(WIRE_OPEN)) - return FALSE - if(forced < 2) - if(obj_flags & EMAGGED) - return FALSE - use_power(50) - playsound(src, doorOpen, 30, TRUE) - else - //playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE) - ORIGINAL - playsound(src, forcedOpen, 30, TRUE) //SKYRAT EDIT CHANGE - AESTHETICS - - if(autoclose) - autoclose_in(normalspeed ? 8 SECONDS : 1.5 SECONDS) if(!density) return TRUE + // Since we aren't physically held shut, do extra checks to see if we should open. + if(!try_to_force_door_open(forced)) + return FALSE + + if(autoclose) + autoclose_in(normalspeed ? 8 SECONDS : 1.5 SECONDS) + if(closeOther != null && istype(closeOther, /obj/machinery/door/airlock)) - addtimer(CALLBACK(closeOther, PROC_REF(close)), 2) + addtimer(CALLBACK(closeOther, PROC_REF(close)), BYPASS_DOOR_CHECKS) if(close_others) for(var/obj/machinery/door/airlock/otherlock as anything in close_others) @@ -1135,14 +1128,14 @@ if(otherlock.operating) otherlock.delayed_close_requested = TRUE else - addtimer(CALLBACK(otherlock, PROC_REF(close)), 2) + addtimer(CALLBACK(otherlock, PROC_REF(close)), BYPASS_DOOR_CHECKS) if(cyclelinkedairlock) if(!shuttledocked && !emergency && !cyclelinkedairlock.shuttledocked && !cyclelinkedairlock.emergency) if(cyclelinkedairlock.operating) cyclelinkedairlock.delayed_close_requested = TRUE else - addtimer(CALLBACK(cyclelinkedairlock, PROC_REF(close)), 2) + addtimer(CALLBACK(cyclelinkedairlock, PROC_REF(close)), BYPASS_DOOR_CHECKS) SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, forced) operating = TRUE @@ -1168,34 +1161,55 @@ operating = FALSE if(delayed_close_requested) delayed_close_requested = FALSE - addtimer(CALLBACK(src, PROC_REF(close)), 1) + addtimer(CALLBACK(src, PROC_REF(close)), FORCING_DOOR_CHECKS) return TRUE +/// Additional checks depending on what we want to happen to door (should we try and open it normally, or do we want this open at all costs?) +/obj/machinery/door/airlock/try_to_force_door_open(force_type = DEFAULT_DOOR_CHECKS) + switch(force_type) + if(DEFAULT_DOOR_CHECKS) // Regular behavior. + if(!hasPower() || wires.is_cut(WIRE_OPEN) || (obj_flags & EMAGGED)) + return FALSE + use_power(50) + playsound(src, doorOpen, 30, TRUE) + return TRUE -/obj/machinery/door/airlock/close(forced = FALSE, force_crush = FALSE) + if(FORCING_DOOR_CHECKS) // Only one check. + if(obj_flags & EMAGGED) + return FALSE + use_power(50) + playsound(src, doorOpen, 30, TRUE) + return TRUE + + if(BYPASS_DOOR_CHECKS) // No power usage, special sound, get it open. + //playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE) - ORIGINAL + playsound(src, forcedOpen, 30, TRUE) //SKYRAT EDIT CHANGE - AESTHETICS + return TRUE + + else + stack_trace("Invalid forced argument '[force_type]' passed to open() on this airlock.") + + // If we got here, shit's fucked, hope parent can help us out here + return ..() + +/obj/machinery/door/airlock/close(forced = DEFAULT_DOOR_CHECKS, force_crush = FALSE) if(operating || welded || locked || seal) - return + return FALSE if(density) return TRUE - if(!forced) + if(forced == DEFAULT_DOOR_CHECKS) // Do this up here and outside of try_to_force_door_shut because if we don't have power, we shouldn't be doing any dangerous_close stuff. if(!hasPower() || wires.is_cut(WIRE_BOLTS)) - return + return FALSE var/dangerous_close = !safe || force_crush if(!dangerous_close) for(var/atom/movable/M in get_turf(src)) if(M.density && M != src) //something is blocking the door autoclose_in(DOOR_CLOSE_WAIT) - return - if(forced < 2) - if(obj_flags & EMAGGED) - return - use_power(50) - playsound(src, doorClose, 30, TRUE) + return FALSE - else - //playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE) //ORIGINAL - playsound(src, forcedClosed, 30, TRUE) //SKYRAT EDIT ADDITION - AESTHETICS + if(!try_to_force_door_shut(forced)) + return FALSE var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) if(killthis) @@ -1236,6 +1250,25 @@ CheckForMobs() return TRUE +/obj/machinery/door/airlock/try_to_force_door_shut(force_type = DEFAULT_DOOR_CHECKS) + switch(force_type) + if(DEFAULT_DOOR_CHECKS to FORCING_DOOR_CHECKS) + if(obj_flags & EMAGGED) + return FALSE + use_power(50) + playsound(src, doorClose, 30, TRUE) + return TRUE + + if(BYPASS_DOOR_CHECKS) + playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE) + return TRUE + + else + stack_trace("Invalid forced argument '[force_type]' passed to close() on this airlock.") + + // shit's fucked, let's hope parent has something to handle it. + return ..() + /obj/machinery/door/airlock/proc/prison_open() if(obj_flags & EMAGGED) return @@ -1313,7 +1346,7 @@ if(do_after(user, time_to_open, src)) - if(density && !open(2)) //The airlock is still closed, but something prevented it opening. (Another player noticed and bolted/welded the airlock in time!) + if(density && !open(BYPASS_DOOR_CHECKS)) //The airlock is still closed, but something prevented it opening. (Another player noticed and bolted/welded the airlock in time!) to_chat(user, span_warning("Despite your efforts, [src] managed to resist your attempts to open it!")) /obj/machinery/door/airlock/hostile_lockdown(mob/origin) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 9c31e3c3f2d..c9d37a32315 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -648,14 +648,14 @@ // set_density on both open and close procs has a check and return builtin. -/obj/machinery/door/airlock/instant/open(forced = FALSE) +/obj/machinery/door/airlock/instant/open(forced = DEFAULT_DOOR_CHECKS) operating = TRUE SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, forced) set_density(FALSE) operating = FALSE return TRUE -/obj/machinery/door/airlock/instant/close(forced = FALSE, force_crush = FALSE) +/obj/machinery/door/airlock/instant/close(forced = DEFAULT_DOOR_CHECKS, force_crush = FALSE) operating = TRUE SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE, forced) set_density(TRUE) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 0b30b3023d4..0b233788485 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -357,12 +357,13 @@ if(!machine_stat) flick("door_deny", src) - -/obj/machinery/door/proc/open() +/// Public proc that simply handles opening the door. Returns TRUE if the door was opened, FALSE otherwise. +/// Use argument "forced" in conjunction with try_to_force_door_open if you want/need additional checks depending on how sorely you need the door opened. +/obj/machinery/door/proc/open(forced = DEFAULT_DOOR_CHECKS) if(!density) - return 1 + return TRUE if(operating) - return + return FALSE operating = TRUE use_power(active_power_usage) do_animate("opening") @@ -379,19 +380,26 @@ update_freelook_sight() if(autoclose) autoclose_in(DOOR_CLOSE_WAIT) - return 1 + return TRUE -/obj/machinery/door/proc/close() +/// Private proc that runs a series of checks to see if we should forcibly open the door. Returns TRUE if we should open the door, FALSE otherwise. Implemented in child types. +/// In case a specific behavior isn't covered, we should default to TRUE just to be safe (simply put, this proc should have an explicit reason to return FALSE). +/obj/machinery/door/proc/try_to_force_door_open(force_type = DEFAULT_DOOR_CHECKS) + return TRUE // the base "door" can always be forced open since there's no power or anything like emagging it to prevent an open, not even invoked on the base type anyways. + +/// Public proc that simply handles closing the door. Returns TRUE if the door was closed, FALSE otherwise. +/// Use argument "forced" in conjuction with try_to_force_door_shut if you want/need additional checks depending on how sorely you need the door closed. +/obj/machinery/door/proc/close(forced = DEFAULT_DOOR_CHECKS) if(density) return TRUE if(operating || welded) - return + return FALSE if(safe) for(var/atom/movable/M in get_turf(src)) if(M.density && M != src) //something is blocking the door if(autoclose) autoclose_in(DOOR_CLOSE_WAIT) - return + return FALSE operating = TRUE @@ -417,6 +425,11 @@ crush() return TRUE +/// Private proc that runs a series of checks to see if we should forcibly shut the door. Returns TRUE if we should shut the door, FALSE otherwise. Implemented in child types. +/// In case a specific behavior isn't covered, we should default to TRUE just to be safe (simply put, this proc should have an explicit reason to return FALSE). +/obj/machinery/door/proc/try_to_force_door_shut(force_type = DEFAULT_DOOR_CHECKS) + return TRUE // the base "door" can always be forced shut + /obj/machinery/door/proc/CheckForMobs() if(locate(/mob/living) in get_turf(src)) sleep(0.1 SECONDS) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 8869d601bbb..53d928869ef 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -194,17 +194,16 @@ leaving.Bump(src) return COMPONENT_ATOM_BLOCK_EXIT -/obj/machinery/door/window/open(forced=FALSE) +/obj/machinery/door/window/open(forced = DEFAULT_DOOR_CHECKS) if (operating) //doors can still open when emag-disabled - return 0 - if(!forced) - if(!hasPower()) - return 0 - if(forced < 2) - if(obj_flags & EMAGGED) - return 0 + return FALSE + + if(!try_to_force_door_open(forced)) + return FALSE + if(!operating) //in case of emag operating = TRUE + do_animate("opening") playsound(src, 'sound/machines/windowdoor.ogg', 100, TRUE) icon_state ="[base_state]open" @@ -215,17 +214,35 @@ if(operating == 1) //emag again operating = FALSE - return 1 -/obj/machinery/door/window/close(forced=FALSE) - if (operating) - return 0 - if(!forced) - if(!hasPower()) - return 0 - if(forced < 2) - if(obj_flags & EMAGGED) - return 0 + return TRUE + +/// Additional checks depending on what we want to happen to this windoor +/obj/machinery/door/window/try_to_force_door_open(force_type = DEFAULT_DOOR_CHECKS) + switch(force_type) + if(DEFAULT_DOOR_CHECKS) + if(!hasPower() || (obj_flags & EMAGGED)) + return FALSE + return TRUE + + if(FORCING_DOOR_CHECKS) + if(obj_flags & EMAGGED) + return FALSE + return TRUE + + if(BYPASS_DOOR_CHECKS) // Get it open! + return TRUE + + else + stack_trace("Invalid forced argument '[force_type]' passed to open() on this airlock.") + + // Shit's fucked, let's just check parent real fast. + return ..() + +/obj/machinery/door/window/close(forced = DEFAULT_DOOR_CHECKS) + if(operating || !try_to_force_door_shut(forced)) + return FALSE + operating = TRUE do_animate("closing") playsound(src, 'sound/machines/windowdoor.ogg', 100, TRUE) @@ -237,7 +254,28 @@ sleep(1 SECONDS) operating = FALSE - return 1 + return TRUE + +/obj/machinery/door/window/try_to_force_door_shut(force_type = DEFAULT_DOOR_CHECKS) + switch(force_type) + if(DEFAULT_DOOR_CHECKS) + if(!hasPower() || (obj_flags & EMAGGED)) + return FALSE + return TRUE + + if(FORCING_DOOR_CHECKS) + if(obj_flags & EMAGGED) + return FALSE + return TRUE + + if(BYPASS_DOOR_CHECKS) // Get it shut! + return TRUE + + else + stack_trace("Invalid forced argument '[force_type]' passed to close() on this airlock.") + + // If we got here, shit's fucked, but let's presume parent can bail us out somehow. + return ..() /obj/machinery/door/window/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) switch(damage_type) @@ -279,7 +317,7 @@ playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) sleep(0.6 SECONDS) operating = FALSE - open(2) + open(BYPASS_DOOR_CHECKS) /obj/machinery/door/window/examine(mob/user) . = ..() @@ -364,9 +402,9 @@ /obj/machinery/door/window/try_to_crowbar(obj/item/I, mob/user, forced = FALSE) if(!hasPower() || forced) if(density) - open(2) + open(BYPASS_DOOR_CHECKS) else - close(2) + close(BYPASS_DOOR_CHECKS) else to_chat(user, span_warning("The door's motors resist your efforts to force it!")) diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index c34aa018b78..02ad54eaa0f 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -239,7 +239,7 @@ //user.say("Heeeeeeeeeerrre's Johnny!") user.visible_message(span_warning("[user] forces the airlock to open with [user.p_their()] [src]!"), span_warning("We force the [opening] to open."), \ span_hear("You hear a metal screeching sound.")) - opening.open(2) + opening.open(BYPASS_DOOR_CHECKS) /obj/item/melee/arm_blade/dropped(mob/user) ..() diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm index 0045d3f6399..735371f6621 100644 --- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm +++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm @@ -190,7 +190,7 @@ playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, vary = TRUE) if(do_after(src, time_to_open, prying_door)) opening_airlock = FALSE - if(prying_door.density && !prying_door.open(2)) + if(prying_door.density && !prying_door.open(BYPASS_DOOR_CHECKS)) to_chat(src, span_warning("Despite your efforts, the airlock managed to resist your attempts to open it!")) return FALSE prying_door.open()