Files
CHOMPStation2/code/game/machinery/doors/blast_door.dm
CHOMPStation2StaffMirrorBot 2738c2c020 [MIRROR] Modernizing doors (#11728)
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com>
Co-authored-by: C.L. <killer65311@gmail.com>
2025-09-23 17:24:13 -04:00

495 lines
16 KiB
Plaintext

// BLAST DOORS
//
// Refactored 27.12.2014 by Atlantis
//
// Blast doors are suposed to be reinforced versions of regular doors. Instead of being manually
// controlled they use buttons or other means of remote control. This is why they cannot be emagged
// as they lack any ID scanning system, they just handle remote control signals. Subtypes have
// different icons, which are defined by set of variables. Subtypes are on bottom of this file.
// UPDATE 06.04.2018
// The emag thing wasn't working as intended, manually overwrote it.
#define BLAST_DOOR_CRUSH_DAMAGE 40
#define SHUTTER_CRUSH_DAMAGE 5 // YW Edit - Shutter damage 5.
/obj/machinery/door/blast
name = "Blast Door"
desc = "That looks like it doesn't open easily."
icon = 'icons/obj/doors/rapid_pdoor.dmi'
icon_state = null
min_force = 20 //minimum amount of force needed to damage the door with a melee weapon
var/datum/material/implicit_material
// Icon states for different shutter types. Simply change this instead of rewriting the update_icon proc.
var/icon_state_open = null
var/icon_state_opening = null
var/icon_state_closed = null
var/icon_state_closing = null
var/open_sound = 'sound/machines/door/blastdooropen.ogg'
var/close_sound = 'sound/machines/door/blastdoorclose.ogg'
var/damage = BLAST_DOOR_CRUSH_DAMAGE
var/multiplier = 1 // The multiplier for how powerful our YEET is.
var/istransparent = 0
closed_layer = ON_WINDOW_LAYER // Above airlocks when closed
var/id = 1.0
dir = 1
explosion_resistance = 25
//Most blast doors are infrequently toggled and sometimes used with regular doors anyways,
//turning this off prevents awkward zone geometry in places like medbay lobby, for example.
block_air_zones = 0
/obj/machinery/door/blast/Initialize(mapload)
. = ..()
implicit_material = get_material_by_name(MAT_PLASTEEL)
/obj/machinery/door/blast/get_material()
return implicit_material
// Proc: Bumped()
// Parameters: 1 (AM - Atom that tried to walk through this object)
// Description: If we are open returns zero, otherwise returns result of parent function.
/obj/machinery/door/blast/Bumped(atom/AM)
if(!density)
return ..()
else
return 0
// Proc: update_icon()
// Parameters: None
// Description: Updates icon of this object. Uses icon state variables.
/obj/machinery/door/blast/update_icon()
if(density)
icon_state = icon_state_closed
else
icon_state = icon_state_open
SSradiation.resistance_cache.Remove(get_turf(src))
return
// Proc: emag_act()
// Description: Emag action to allow blast doors to double their yeet distance and speed.
/obj/machinery/door/blast/emag_act()
if(!emagged)
emagged = 1
multiplier = 2 // Haha emag go yeet
return 1
// Blast doors are triggered remotely, so nobody is allowed to physically influence it.
/obj/machinery/door/blast/allowed(mob/M)
return FALSE
// Proc: force_open()
// Parameters: None
// Description: Opens the door. No checks are done inside this proc.
/obj/machinery/door/blast/proc/force_open()
operating = TRUE
playsound(src, open_sound, 100, 1)
flick(icon_state_opening, src)
density = FALSE
update_nearby_tiles()
update_icon()
set_opacity(0)
addtimer(CALLBACK(src, PROC_REF(complete_force_open)), 1.5 SECONDS, TIMER_DELETE_ME|TIMER_UNIQUE)
/obj/machinery/door/blast/proc/complete_force_open()
PRIVATE_PROC(TRUE)
layer = open_layer
operating = FALSE
// Proc: force_close()
// Parameters: None
// Description: Closes the door. No checks are done inside this proc.
/obj/machinery/door/blast/proc/force_close()
// Blast door turf checks. We do this before the door closes to prevent it from failing after the door is closed, because obv a closed door will block any adjacency checks.
var/turf/T = get_turf(src)
var/list/yeet_turfs = T.CardinalTurfs(TRUE)
operating = TRUE
playsound(src, close_sound, 100, 1)
layer = closed_layer
flick(icon_state_closing, src)
density = TRUE
update_nearby_tiles()
update_icon()
if(istransparent)
set_opacity(0)
else
set_opacity(1)
addtimer(CALLBACK(src, PROC_REF(complete_force_close), yeet_turfs), 1.5 SECONDS, TIMER_DELETE_ME|TIMER_UNIQUE)
/obj/machinery/door/blast/proc/complete_force_close(list/yeet_turfs)
PRIVATE_PROC(TRUE)
operating = FALSE
// Blast door crushing.
for(var/turf/turf in locs)
for(var/atom/movable/AM in turf)
if(AM.airlock_crush(damage))
if(LAZYLEN(yeet_turfs))
AM.throw_at(get_edge_target_turf(src, get_dir(src, pick(yeet_turfs))), (rand(1,3) * multiplier), (rand(2,4) * multiplier)) // YEET.
take_damage(damage*0.2)
// Proc: force_toggle()
// Parameters: None
// Description: Opens or closes the door, depending on current state. No checks are done inside this proc.
/obj/machinery/door/blast/proc/force_toggle(var/forced = 0, mob/user as mob)
if (forced)
playsound(src, 'sound/machines/door/airlock_creaking.ogg', 100, 1)
if(src.density)
src.force_open()
else
src.force_close()
//Proc: attack_hand
//Description: Attacked with empty hand. Only to allow special attack_bys.
/obj/machinery/door/blast/attack_hand(mob/user as mob)
if(ishuman(user))
var/mob/living/carbon/human/X = user
if(istype(X.species, /datum/species/xenos))
src.attack_alien(user)
return
..()
// Proc: attackby()
// Parameters: 2 (C - Item this object was clicked with, user - Mob which clicked this object)
// Description: If we are clicked with crowbar, wielded fire axe, or armblade, try to manually open the door.
// This only works on broken doors or doors without power. Also allows repair with Plasteel.
/obj/machinery/door/blast/attackby(obj/item/C as obj, mob/user as mob)
src.add_fingerprint(user)
if(istype(C, /obj/item)) // For reasons unknown, sometimes C is actually not what it is advertised as, like a mob.
if(C.pry == 1 && (user.a_intent != I_HURT || (stat & BROKEN))) // Can we pry it open with something, like a crowbar/fireaxe/lingblade?
if(istype(C,/obj/item/material/twohanded/fireaxe)) // Fireaxes need to be in both hands to pry.
var/obj/item/material/twohanded/fireaxe/F = C
if(!F.wielded)
to_chat(user, span_warning("You need to be wielding \the [F] to do that."))
return
// If we're at this point, it's a fireaxe in both hands or something else that doesn't care for twohanding.
if(((stat & NOPOWER) || (stat & BROKEN)) && !( src.operating ))
force_toggle(1, user)
else
to_chat(user, span_notice("[src]'s motors resist your effort."))
return
else if(src.density && (user.a_intent == I_HURT)) //If we can't pry it open and it's a weapon, let's hit it.
var/obj/item/W = C
user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
if(W.force < min_force)
user.visible_message(span_danger("\The [user] hits \the [src] with \the [W] with no visible effect."))
else
user.visible_message(span_danger("\The [user] forcefully strikes \the [src] with \the [W]!"))
playsound(src, hitsound, 100, 1)
take_damage(W.force*0.35) //it's a blast door, it should take a while. -Luke
return
else if(istype(C, /obj/item/stack/material) && C.get_material_name() == MAT_PLASTEEL) // Repairing.
var/amt = CEILING((maxhealth - health)/150, 1)
if(!amt)
to_chat(user, span_notice("\The [src] is already fully repaired."))
return
var/obj/item/stack/P = C
if(P.get_amount() < amt)
to_chat(user, span_warning("You don't have enough sheets to repair this! You need at least [amt] sheets."))
return
to_chat(user, span_notice("You begin repairing [src]..."))
if(do_after(user, 3 SECONDS, target = src))
if(P.use(amt))
to_chat(user, span_notice("You have repaired \The [src]"))
src.repair()
else
to_chat(user, span_warning("You don't have enough sheets to repair this! You need at least [amt] sheets."))
else if(src.density && (user.a_intent == I_HURT)) //If we can't pry it open and it's not a weapon.... Eh, let's attack it anyway.
var/obj/item/W = C
user.setClickCooldown(user.get_attack_speed(W))
if(istype(W) && (W.damtype == BRUTE || W.damtype == BURN))
user.do_attack_animation(src)
if(W.force < min_force) //No actual non-weapon item shouls have a force greater than the min_force, but let's include this just in case.
user.visible_message(span_danger("\The [user] hits \the [src] with \the [W] with no visible effect."))
else
user.visible_message(span_danger("\The [user] forcefully strikes \the [src] with \the [W]!"))
playsound(src, hitsound, 100, 1)
take_damage(W.force*0.15) //If the item isn't a weapon, let's make this take longer than usual to break it down.
return
// Proc: attack_alien()
// Parameters: Attacking Xeno mob.
// Description: Forces open the door after a delay.
/obj/machinery/door/blast/attack_alien(var/mob/user) //Familiar, right? Doors.
if(ishuman(user))
var/mob/living/carbon/human/X = user
if(istype(X.species, /datum/species/xenos))
if(src.density)
visible_message(span_alium("\The [user] begins forcing \the [src] open!"))
if(do_after(user, 15 SECONDS, target = src))
playsound(src, 'sound/machines/door/airlock_creaking.ogg', 100, 1)
visible_message(span_danger("\The [user] forces \the [src] open!"))
force_open(1)
else
visible_message(span_alium("\The [user] begins forcing \the [src] closed!"))
if(do_after(user, 5 SECONDS, target = src))
playsound(src, 'sound/machines/door/airlock_creaking.ogg', 100, 1)
visible_message(span_danger("\The [user] forces \the [src] closed!"))
force_close(1)
else
visible_message(span_notice("\The [user] strains fruitlessly to force \the [src] [density ? "open" : "closed"]."))
return
..()
// Proc: attack_generic()
// Parameters: Attacking simple mob, incoming damage.
// Description: Checks the power or integrity of the blast door, if either have failed, chekcs the damage to determine if the creature would be able to open the door by force. Otherwise, super.
/obj/machinery/door/blast/attack_generic(mob/living/user, damage)
if(stat & (BROKEN|NOPOWER))
if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
user.set_AI_busy(TRUE) // If the mob doesn't have an AI attached, this won't do anything.
if(src.density)
visible_message(span_danger("\The [user] starts forcing \the [src] open!"))
if(do_after(user, 5 SECONDS, target = src))
visible_message(span_danger("\The [user] forces \the [src] open!"))
force_open(1)
else
visible_message(span_danger("\The [user] starts forcing \the [src] closed!"))
if(do_after(user, 2 SECONDS, target = src))
visible_message(span_danger("\The [user] forces \the [src] closed!"))
force_close(1)
user.set_AI_busy(FALSE)
else
visible_message(span_notice("\The [user] strains fruitlessly to force \the [src] [density ? "open" : "closed"]."))
return
..()
// Proc: open()
// Parameters: None
// Description: Opens the door. Does necessary checks. Automatically closes if autoclose is true
/obj/machinery/door/blast/open(var/forced = 0)
if(forced)
force_open()
return 1
else
if (src.operating || (stat & BROKEN || stat & NOPOWER))
return 1
force_open()
if(autoclose && src.operating && !(stat & BROKEN || stat & NOPOWER))
addtimer(CALLBACK(src, PROC_REF(close)), 15 SECONDS)
return 1
// Proc: close()
// Parameters: None
// Description: Closes the door. Does necessary checks.
/obj/machinery/door/blast/close()
if (src.operating || (stat & BROKEN || stat & NOPOWER))
return
force_close()
return 1
// Proc: repair()
// Parameters: None
// Description: Fully repairs the blast door.
/obj/machinery/door/blast/proc/repair()
health = maxhealth
if(stat & BROKEN)
stat &= ~BROKEN
/*
// This replicates the old functionality coded into CanPass() for this object, however it appeared to have made blast doors not airtight.
// If for some reason this is actually needed for something important, uncomment this.
/obj/machinery/door/blast/CanZASPass(turf/T, is_zone)
if(is_zone)
return TRUE
return ..()
*/
// SUBTYPE: Regular
// Your classical blast door, found almost everywhere.
/obj/machinery/door/blast/regular
icon_state_open = "pdoor0"
icon_state_opening = "pdoorc0"
icon_state_closed = "pdoor1"
icon_state_closing = "pdoorc1"
icon_state = "pdoor1"
maxhealth = 600
heat_proof = 1 //just so repairing them doesn't try to fireproof something that never takes fire damage
/obj/machinery/door/blast/regular/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return // blast doors are immune to fire completely.
/obj/machinery/door/blast/regular/open
icon_state = "pdoor0"
density = FALSE
opacity = 0
/obj/machinery/door/blast/regular/bookcase //CHOMP Add code block
name = "bookcase"
desc = "On closer inspection, the array of books is decorative and built into the frame."
icon_state = "bookcase1"
icon_state_open = "bookcase0"
icon_state_opening = "bookcasec0"
icon_state_closed = "bookcase1"
icon_state_closing = "bookcasec1"
// SUBTYPE: Shuttle
// Slightly weaker, intergrated shutters - open state is hidden from view. Found on fancy_shuttles
/obj/machinery/door/blast/shuttle
name = "shuttle blast doors"
icon_state_open = "spdoor0"
icon_state_opening = "spdoorc0"
icon_state_closed = "spdoor1"
icon_state_closing = "spdoorc1"
icon_state = "spdoor1"
maxhealth = 400
/obj/machinery/door/blast/shuttle/open
icon_state = "spdoor0"
density = FALSE
opacity = 0
// SUBTYPE: Shutters
// Nicer looking, and also weaker, shutters. Found in kitchen and similar areas.
/obj/machinery/door/blast/shutters
icon_state_open = "shutter0"
icon_state_opening = "shutterc0"
icon_state_closed = "shutter1"
icon_state_closing = "shutterc1"
icon_state = "shutter1"
damage = SHUTTER_CRUSH_DAMAGE
// SUBTYPE: Transparent
// Not technically a blast door but operates like one. Allows air and light.
/obj/machinery/door/blast/gate
name = "thick gate"
icon_state_open = "tshutter0"
icon_state_opening = "tshutterc0"
icon_state_closed = "tshutter1"
icon_state_closing = "tshutterc1"
icon_state = "tshutter1"
damage = SHUTTER_CRUSH_DAMAGE
maxhealth = 400
block_air_zones = 0
opacity = 0
istransparent = 1
/obj/machinery/door/blast/gate/open
icon_state = "tshutter0"
density = FALSE
/obj/machinery/door/blast/gate/thin
name = "thin gate"
icon_state_open = "shutter2_0"
icon_state_opening = "shutter2_c0"
icon_state_closed = "shutter2_1"
icon_state_closing = "shutter2_c1"
icon_state = "shutter2_1"
maxhealth = 200
opacity = 0
/obj/machinery/door/blast/gate/thin/open
icon_state = "shutter2_1"
density = FALSE
/obj/machinery/door/blast/gate/bars
name = "prison bars"
icon_state_open = "bars_0"
icon_state_opening = "bars_c0"
icon_state_closed = "bars_1"
icon_state_closing = "bars_c1"
icon_state = "bars_1"
maxhealth = 600
opacity = 0
/obj/machinery/door/blast/gate/bars/open
icon_state = "bars_1"
density = FALSE
// SUBTYPE: Multi-tile
// Pod doors ported from Paradise
// Whoever wrote the old code for multi-tile spesspod doors needs to burn in hell. - Unknown
// Wise words. - Bxil
/obj/machinery/door/blast/multi_tile
name = "large blast door"
/obj/machinery/door/blast/multi_tile/Initialize(mapload)
. = ..()
apply_opacity_to_my_turfs(opacity)
/obj/machinery/door/blast/multi_tile/set_opacity()
. = ..()
apply_opacity_to_my_turfs(opacity)
/obj/machinery/door/blast/multi_tile/proc/apply_opacity_to_my_turfs(new_opacity)
for(var/turf/T in locs)
T.set_opacity(new_opacity)
update_nearby_tiles()
/obj/machinery/door/blast/multi_tile
icon_state_open = "open"
icon_state_opening = "opening"
icon_state_closed = "closed"
icon_state_closing = "closing"
icon_state = "closed"
/obj/machinery/door/blast/multi_tile/four_tile_ver_sec
icon = 'icons/obj/doors/1x4blast_vert_sec.dmi'
bound_height = 128
width = 4
dir = NORTH
autoclose = TRUE
/obj/machinery/door/blast/multi_tile/four_tile_ver
icon = 'icons/obj/doors/1x4blast_vert.dmi'
bound_height = 128
width = 4
dir = NORTH
/obj/machinery/door/blast/multi_tile/three_tile_ver
icon = 'icons/obj/doors/1x3blast_vert.dmi'
bound_height = 96
width = 3
dir = NORTH
/obj/machinery/door/blast/multi_tile/two_tile_ver
icon = 'icons/obj/doors/1x2blast_vert.dmi'
bound_height = 64
width = 2
dir = NORTH
/obj/machinery/door/blast/multi_tile/four_tile_hor_sec
icon = 'icons/obj/doors/1x4blast_hor_sec.dmi'
bound_width = 128
width = 4
dir = EAST
autoclose = TRUE
/obj/machinery/door/blast/multi_tile/four_tile_hor
icon = 'icons/obj/doors/1x4blast_hor.dmi'
bound_width = 128
width = 4
dir = EAST
/obj/machinery/door/blast/multi_tile/three_tile_hor
icon = 'icons/obj/doors/1x3blast_hor.dmi'
bound_width = 96
width = 3
dir = EAST
/obj/machinery/door/blast/multi_tile/two_tile_hor
icon = 'icons/obj/doors/1x2blast_hor.dmi'
bound_width = 64
width = 2
dir = EAST
#undef BLAST_DOOR_CRUSH_DAMAGE
#undef SHUTTER_CRUSH_DAMAGE