[MIRROR] Moves atmos checking from Fire Alarms to Fire Locks, Fire Locks now close on their own rather than area-based, a bunch of related stuff. [MDB IGNORE] (#10893)

* Moves atmos checking from Fire Alarms to Fire Locks, Fire Locks now close on their own rather than area-based, a bunch of related stuff.

* Weeeee

Co-authored-by: zxaber <37497534+zxaber@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-01-27 02:21:18 +00:00
committed by GitHub
co-authored by zxaber Gandalf
parent 30da2adecb
commit 4fc5079cdc
18 changed files with 458 additions and 585 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
//A set of defines to be used by the alarm datums
///Sent by air alarms, indecates something wrong with thier attached atmosphere
#define ALARM_ATMOS "Atmosphere"
///Sent by fire alarms when they are toggled
///Sent by firelocks when they detect fire, and by fire alarms when a user pulls them
#define ALARM_FIRE "Fire"
///Sent by apcs when their power starts to fail
#define ALARM_POWER "Power"
+13
View File
@@ -0,0 +1,13 @@
//A set of defines to be sent by fire alarms. The signals are sent to the alarm's area, but are read and used by the firelocks of the area, and are used for mass changes in fire detection.
///Sent when a fire alarm is emagged
#define FIRE_DETECT_EMAG "fire_detect_emag"
///Sent when the fire detection of an area is disabled
#define FIRE_DETECT_STOP "fire_detect_stop"
///Sent when the fire detection of an area is enabled
#define FIRE_DETECT_START "fire_detect_start"
///Designates a fire lock should be closed due to HEAT
#define FIRELOCK_ALARM_TYPE_HOT "firelock_alarm_type_hot"
///Designates a fire lock should be closed due to COLD
#define FIRELOCK_ALARM_TYPE_COLD "firelock_alarm_type_cold"
///Designates a fire lock should be closed due unknown reasons (IE fire alarm was pulled)
#define FIRELOCK_ALARM_TYPE_GENERIC "firelock_alarm_type_generic"
@@ -59,15 +59,6 @@
///from base of /obj/effect/abstract/liquid_turf/Initialize() (/obj/effect/abstract/liquid_turf/liquids)
#define COMSIG_TURF_LIQUIDS_CREATION "turf_liquids_creation"
// Firealarm signals
/// /obj/machinery/firealarm/proc/trigger_effects(manual = FALSE)
#define COMSIG_FIREALARM_TRIGGERED_ON "firealarm_triggered_on"
#define COMSIG_FIREALARM_TRIGGER_DOORS "firealarm_trigger_doors"
/// /obj/machinery/firealarm/proc/untrigger_effects()
#define COMSIG_FIREALARM_TRIGGERED_OFF "firealarm_triggered_off"
/// /obj/machinery/door/firedoor/proc/trigger_hot()
#define COMSIG_FIREDOOR_CLOSED_FIRE "firedoor_closed_fire"
//when someone casts their fishing rod
#define COMSIG_START_FISHING "start_fishing"
//when someone pulls back their fishing rod
@@ -64,6 +64,8 @@
mid_length = 18
volume = 50
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/oven
start_sound = 'sound/machines/oven/oven_loop_start.ogg' //my immersions
start_length = 12
@@ -98,6 +100,7 @@
volume = 85
vary = TRUE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/server
mid_sounds = list('sound/machines/tcomms/tcomms_mid1.ogg'=1,'sound/machines/tcomms/tcomms_mid2.ogg'=1,'sound/machines/tcomms/tcomms_mid3.ogg'=1,'sound/machines/tcomms/tcomms_mid4.ogg'=1,\
@@ -108,6 +111,8 @@
falloff_exponent = 5
volume = 50
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/computer
start_sound = 'sound/machines/computer/computer_start.ogg'
start_length = 7.2 SECONDS
@@ -121,6 +126,8 @@
extra_range = -12
falloff_distance = 1 //Instant falloff after initial tile
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/gravgen
mid_sounds = list('sound/machines/gravgen/gravgen_mid1.ogg'=1,'sound/machines/gravgen/gravgen_mid2.ogg'=1,'sound/machines/gravgen/gravgen_mid3.ogg'=1,'sound/machines/gravgen/gravgen_mid4.ogg'=1,)
mid_length = 1.8 SECONDS
@@ -129,6 +136,15 @@
falloff_distance = 5
falloff_exponent = 20
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/firealarm
mid_sounds = list('sound/machines/FireAlarm.ogg'=1)
mid_length = 9.7 SECONDS
volume = 75
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/gravgen/kinesis
volume = 20
falloff_distance = 2
+16 -95
View File
@@ -17,11 +17,17 @@
///Do we have an active fire alarm?
var/fire = FALSE
///How many fire alarm sources do we have?
var/triggered_firealarms = 0
///A var for whether the area allows for detecting fires/etc. Disabled or enabled at a fire alarm, checked by fire locks.
var/fire_detect = TRUE
///A list of all fire locks in this area. Used by fire alarm panels when resetting fire locks or activating all in an area
var/list/firedoors
///A list of firelocks currently active. Used by fire alarms when setting their icons.
var/list/active_firelocks
///A list of all fire alarms in this area. Used by fire locks and burglar alarms to tell the fire alarm to change its icon.
var/list/firealarms
///Alarm type to count of sources. Not usable for ^ because we handle fires differently
var/list/active_alarms = list()
///We use this just for fire alarms, because they're area based right now so one alarm going poof shouldn't prevent you from clearing your alarms listing
///We use this just for fire alarms, because they're area based right now so one alarm going poof shouldn't prevent you from clearing your alarms listing. Fire alarms and fire locks will set and clear alarms.
var/datum/alarm_handler/alarm_manager
var/lightswitch = TRUE
@@ -65,10 +71,7 @@
var/list/ambientsounds
flags_1 = CAN_BE_DIRTY_1
var/list/firedoors
var/list/cameras
//var/list/firealarms SKYRAT EDIT REMOVAL
var/firedoors_last_closed_on = 0
///Typepath to limit the areas (subtypes included) that atoms in this area can smooth with. Used for shuttles.
var/area/area_limited_icon_smoothing
@@ -240,84 +243,6 @@ GLOBAL_LIST_EMPTY(teleportlocs)
STOP_PROCESSING(SSobj, src)
QDEL_NULL(alarm_manager)
return ..()
/* SKYRAT EDIT REMOVAL
/**
* 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
if (D.being_held_open)
continue
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 ? FIREDOOR_OPEN : FIREDOOR_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
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*
* Also starts the area processing on SSobj
*/
/area/proc/firealert(obj/source)
if (!fire)
set_fire_alarm_effect()
ModifyFiredoors(FALSE)
for(var/item in firealarms)
var/obj/machinery/firealarm/F = item
F.update_appearance()
alarm_manager.send_alarm(ALARM_FIRE, source)
START_PROCESSING(SSobj, src)
/**
* Reset the firealarm alert for this area
*
* resets the alert sent to all ai players, alert consoles, drones and alarm monitor programs
* in the world
*
* Also cycles the icons of all firealarms and deregisters the area from processing on SSOBJ
*/
/area/proc/firereset(obj/source)
var/should_reset_alarms = fire
if(source)
if(istype(source, /obj/machinery/firealarm))
var/obj/machinery/firealarm/alarm = source
if(alarm.triggered)
alarm.triggered = FALSE
triggered_firealarms -= 1
if(triggered_firealarms > 0)
should_reset_alarms = FALSE
should_reset_alarms = should_reset_alarms & power_environ //No resetting if there's no power
if (should_reset_alarms) // if there's a source, make sure there's no fire alarms left
unset_fire_alarm_effects()
ModifyFiredoors(TRUE)
for(var/item in firealarms)
var/obj/machinery/firealarm/F = item
F.update_appearance()
alarm_manager.clear_alarm(ALARM_FIRE, source)
STOP_PROCESSING(SSobj, src)
/**
* If 100 ticks has elapsed, toggle all the firedoors closed again
*/
/area/process()
if(!triggered_firealarms)
firereset() //If there are no breaches or fires, and this alert was caused by a breach or fire, die
if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
ModifyFiredoors(FALSE)
/**
* Close and lock a door passed into this proc
@@ -352,15 +277,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
* Updates the fire light on fire alarms in the area and sets all lights to emergency mode
*/
/area/proc/set_fire_alarm_effect()
if(fire)
return
fire = TRUE
if(!triggered_firealarms) //If there aren't any fires/breaches
triggered_firealarms = INFINITY //You're not allowed to naturally die
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
for(var/obj/machinery/light/L in src)
L.update()
for(var/obj/machinery/firealarm/firepanel in firealarms)
firepanel.set_status()
/**
* unset the fire alarm visual affects in an area
@@ -369,15 +293,12 @@ GLOBAL_LIST_EMPTY(teleportlocs)
*/
/area/proc/unset_fire_alarm_effects()
fire = FALSE
triggered_firealarms = 0
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
F.triggered = FALSE
for(var/obj/machinery/light/L in src)
L.update()
*/
for(var/obj/machinery/firealarm/firepanel in firealarms)
firepanel.set_status()
/**
* Update the icon state of the area
*
+307 -77
View File
@@ -1,11 +1,12 @@
#define CONSTRUCTION_PANEL_OPEN 1 //Maintenance panel is open, still functioning
#define CONSTRUCTION_NO_CIRCUIT 2 //Circuit board removed, can safely weld apart
#define DEFAULT_STEP_TIME 20 /// default time for each step
#define DETECT_COOLDOWN_STEP_TIME 5 SECONDS ///Wait time before we can detect an issue again, after a recent clear.
/obj/machinery/door/firedoor
name = "firelock"
desc = "Apply crowbar."
icon = 'icons/obj/doors/Doorfireglass.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
icon = 'icons/obj/doors/Doorfireglass.dmi'
icon_state = "door_open"
opacity = FALSE
density = FALSE
@@ -21,16 +22,76 @@
assemblytype = /obj/structure/firelock_frame
armor = list(MELEE = 10, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 100, FIRE = 95, ACID = 70)
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
var/nextstate = null
COOLDOWN_DECLARE(detect_cooldown)
///Trick to get the glowing overlay visible from a distance
luminosity = 1
///X offset for the overlay lights, so that they line up with the thin border firelocks
var/light_xoffset = 0
///Y offset for the overlay lights, so that they line up with the thin border firelocks
var/light_yoffset = 0
var/boltslocked = TRUE
///List of areas we handle. See CalculateAffectingAreas()
var/list/affecting_areas
///For the few times we affect only the area we're actually in. Set during Init. If we get moved, we don't update, but this is consistant with fire alarms and also kinda funny so call it intentional.
var/area/my_area
///Tracks if the firelock is being held open by a crowbar. If so, we don't close until they walk away
var/being_held_open = FALSE
///Type of alarm when active. See code/defines/firealarm.dm for the list. This var being null means there is no alarm.
var/alarm_type = null
///The merger_id and merger_typecache variables are used to make rows of firelocks activate at the same time.
var/merger_id = "firelocks"
var/static/list/merger_typecache
///Overlay object for the warning lights. This and some plane settings allows the lights to glow in the dark.
var/mutable_appearance/warn_lights
///looping sound datum for our fire alarm siren.
var/datum/looping_sound/firealarm/soundloop
///Keeps track of if we're playing the alarm sound loop (as only one firelock per group should be). Used during power changes.
var/is_playing_alarm = FALSE
var/knock_sound = 'sound/effects/glassknock.ogg'
var/bash_sound = 'sound/effects/glassbash.ogg'
/obj/machinery/door/firedoor/Initialize(mapload)
. = ..()
COOLDOWN_START(src, detect_cooldown, DETECT_COOLDOWN_STEP_TIME)
soundloop = new(src, FALSE)
AddElement(/datum/element/atmos_sensitive, mapload)
CalculateAffectingAreas()
my_area = get_area(src)
var/static/list/loc_connections = list(
COMSIG_TURF_EXPOSE = .proc/check_atmos,
)
AddElement(/datum/element/connect_loc, loc_connections)
if(!merger_typecache)
merger_typecache = typecacheof(/obj/machinery/door/firedoor)
check_atmos()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/door/firedoor/LateInitialize()
. = ..()
GetMergeGroup(merger_id, allowed_types = merger_typecache)
/**
* Sets the offset for the warning lights.
*
* Used for special firelocks with light overlays that don't line up to their sprite.
*/
/obj/machinery/door/firedoor/proc/adjust_lights_starting_offset()
return
/obj/machinery/door/firedoor/Destroy()
remove_from_areas()
QDEL_NULL(soundloop)
return ..()
/obj/machinery/door/firedoor/examine(mob/user)
. = ..()
@@ -39,39 +100,152 @@
else if(!welded)
. += span_notice("It is closed, but could be <b>pried</b> open.")
. += span_notice("Hold the firelock temporarily open by prying it with <i>left-click</i> and standing next to it.")
//. += span_notice("Prying by <i>right-clicking</i> the firelock will open it permanently.") SKYRAT EDIT REMOVAL
. += span_notice("Prying by <i>right-clicking</i> the firelock will open it permanently.")
. += span_notice("Deconstruction would require it to be <b>welded</b> shut.")
else if(boltslocked)
. += span_notice("It is <i>welded</i> shut. The floor bolts have been locked by <b>screws</b>.")
else
. += span_notice("The bolt locks have been <i>unscrewed</i>, but the bolts themselves are still <b>wrenched</b> to the floor.")
/* //SKYRAT EDIT REMOVAL BEGIN
/**
* Calculates what areas we should worry about.
*
* This proc builds a list of areas we are in and areas we border
* and writes it to affecting_areas.
*/
/obj/machinery/door/firedoor/proc/CalculateAffectingAreas()
var/list/new_affecting_areas = get_adjacent_open_areas(src) | get_area(src)
if(compare_list(new_affecting_areas, affecting_areas))
return //No changes needed
remove_from_areas()
affecting_areas = get_adjacent_open_areas(src) | get_area(src)
for(var/I in affecting_areas)
var/area/A = I
LAZYADD(A.firedoors, src)
*/ //SKYRAT EDIT END
affecting_areas = new_affecting_areas
for(var/area/place in affecting_areas)
LAZYADD(place.firedoors, src)
if(alarm_type)
if(place == get_area(src))
LAZYADD(place.active_firelocks, src) //We only add ourselves to our own area's active firelocks...
for(var/obj/machinery/firealarm/fire_panel in place.firealarms)
fire_panel.set_status() //...but all adjacent fire alarms are notified
/obj/machinery/door/firedoor/closed
icon_state = "door_closed"
density = TRUE
/* //SKYRAT EDIT REMOVAL BEGIN
//see also turf/AfterChange for adjacency shennanigans
/**
* Removes us from any lists of areas in the affecting_areas list, then clears affecting_areas
*
* Undoes everything done in the CalculateAffectingAreas() proc, to clean up prior to deletion.
* Calls reset() first, in case any alarms need to be cleared first.
*/
/obj/machinery/door/firedoor/proc/remove_from_areas()
if(affecting_areas)
for(var/I in affecting_areas)
var/area/A = I
LAZYREMOVE(A.firedoors, src)
if(!affecting_areas)
return
for(var/area/place in affecting_areas)
LAZYREMOVE(place.firedoors, src)
LAZYREMOVE(place.active_firelocks, src)
if(LAZYLEN(place.active_firelocks)) //if we were the last firelock still active in this particular area
continue
for(var/obj/machinery/firealarm/fire_panel in place.firealarms)
fire_panel.set_status()
/obj/machinery/door/firedoor/Destroy()
remove_from_areas()
affecting_areas.Cut()
return ..()
*/ //SKYRAT EDIT REMOVAL END
/obj/machinery/door/firedoor/proc/check_atmos(datum/source)
if(!COOLDOWN_FINISHED(src, detect_cooldown))
return
if(alarm_type)
return
for(var/area/place in affecting_areas)
if(!place.fire_detect) //if any area is set to disable detection
return
var/turf/my_turf = source
if(!my_turf)
my_turf = get_turf(src)
var/datum/gas_mixture/environment = my_turf.return_air()
var/result
if(environment?.temperature >= BODYTEMP_HEAT_DAMAGE_LIMIT || environment?.volume > WARNING_HIGH_PRESSURE) //SKYRAT EDIT CHANGE - BETTER LOCKS
result = FIRELOCK_ALARM_TYPE_HOT
if(environment?.temperature <= BODYTEMP_COLD_DAMAGE_LIMIT || environment?.volume < WARNING_LOW_PRESSURE) //SKYRAT EDIT CHANGE - BETTER LOCKS
result = FIRELOCK_ALARM_TYPE_COLD
if(!result)
return
start_activation_process(result)
/**
* Begins activation process of us and our neighbors.
*
* This proc will call activate() on every fire lock (including us) listed
* in the merge group datum. Returns without doing anything if our alarm_type
* was already set, as that means that we're already active.
*
* Arguments:
* code should be one of three defined alarm types, or can be not supplied. Will dictate the color of the fire alarm lights, and defults to "firelock_alarm_type_generic"
*/
/obj/machinery/door/firedoor/proc/start_activation_process(code = FIRELOCK_ALARM_TYPE_GENERIC)
if(alarm_type)
return //We're already active
soundloop.start()
is_playing_alarm = TRUE
var/datum/merger/merge_group = GetMergeGroup(merger_id, merger_typecache)
for(var/obj/machinery/door/firedoor/buddylock as anything in merge_group.members)
buddylock.activate(code)
/**
* Proc that handles activation of the firelock and all this details
*
* Sets the alarm_type variable based on the single arg, which is in turn
* used by several procs to understand the intended state of the fire lock.
* Also calls set_status() on all fire alarms in all affected areas, tells
* the area the firelock sits in to report the event (AI, alarm consoles, etc)
* and finally calls correct_state(), which will handle opening or closing
* this fire lock.
*/
/obj/machinery/door/firedoor/proc/activate(code = FIRELOCK_ALARM_TYPE_GENERIC)
SIGNAL_HANDLER
if(alarm_type)
return //Already active
alarm_type = code
for(var/area/place in affecting_areas)
LAZYADD(place.active_firelocks, src)
if(LAZYLEN(place.active_firelocks) == 1) //if we're the first to activate in this particular area
for(var/obj/machinery/firealarm/fire_panel in place.firealarms)
fire_panel.set_status()
if(alarm_type != FIRELOCK_ALARM_TYPE_GENERIC) //Generic alarms tend to activate all firelocks in an area, which otherwise makes the red lighting spread like a virus. Anyway, fire alarms already do this for manual pulls.
place.set_fire_alarm_effect() //bathe in red
if(place == my_area)
place.alarm_manager.send_alarm(ALARM_FIRE, place) //We'll limit our reporting to just the area we're on. If the issue affects bordering areas, they can report it themselves
update_icon() //Sets the door lights even if the door doesn't move.
correct_state()
/**
* Proc that handles reset steps
*
* Clears the alarm state and attempts to open the firelock.
*/
/obj/machinery/door/firedoor/proc/reset()
SIGNAL_HANDLER
alarm_type = null
for(var/area/place in affecting_areas)
LAZYREMOVE(place.active_firelocks, src)
if(!LAZYLEN(place.active_firelocks)) //if we were the last firelock still active in this particular area
for(var/obj/machinery/firealarm/fire_panel in place.firealarms)
fire_panel.set_status()
place.unset_fire_alarm_effects()
COOLDOWN_START(src, detect_cooldown, DETECT_COOLDOWN_STEP_TIME)
soundloop.stop()
is_playing_alarm = FALSE
update_icon() //Sets the door lights even if the door doesn't move.
correct_state()
/obj/machinery/door/firedoor/emag_act(mob/user, obj/item/card/emag/doorjack/digital_crowbar)
if(obj_flags & EMAGGED)
return
if(!isAI(user)) //Skip doorjack-specific code
if(!user || digital_crowbar.charges < 1)
return
digital_crowbar.use_charge(user)
obj_flags |= EMAGGED
INVOKE_ASYNC(src, .proc/open)
/obj/machinery/door/firedoor/Bumped(atom/movable/AM)
if(panel_open || operating)
@@ -85,7 +259,13 @@
/obj/machinery/door/firedoor/power_change()
. = ..()
INVOKE_ASYNC(src, .proc/latetoggle)
update_icon()
correct_state()
if(machine_stat & NOPOWER)
soundloop.stop()
else if(is_playing_alarm)
soundloop.start()
/obj/machinery/door/firedoor/attack_hand(mob/living/user, list/modifiers)
. = ..()
@@ -143,6 +323,7 @@
user.visible_message(span_danger("[user] [welded?"welds":"unwelds"] [src]."), span_notice("You [welded ? "weld" : "unweld"] [src]."))
log_game("[key_name(user)] [welded ? "welded":"unwelded"] firedoor [src] with [W] at [AREACOORD(src)]")
update_appearance()
correct_state()
/// We check for adjacency when using the primary attack.
/obj/machinery/door/firedoor/try_to_crowbar(obj/item/acting_object, mob/user)
@@ -170,6 +351,8 @@
if(density)
open()
if(alarm_type)
addtimer(CALLBACK(src, .proc/correct_state), 2 SECONDS, TIMER_UNIQUE)
else
close()
@@ -180,7 +363,7 @@
if(!QDELETED(user) && Adjacent(user) && isliving(user) && (living_user.body_position == STANDING_UP))
return
being_held_open = FALSE
INVOKE_ASYNC(src, .proc/close)
correct_state()
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
UnregisterSignal(user, COMSIG_LIVING_SET_BODY_POSITION)
UnregisterSignal(user, COMSIG_PARENT_QDELETING)
@@ -193,6 +376,8 @@
return TRUE
if(density)
open()
if(alarm_type)
addtimer(CALLBACK(src, .proc/correct_state), 2 SECONDS, TIMER_UNIQUE)
else
close()
return TRUE
@@ -206,6 +391,8 @@
to_chat(user, span_warning("[src] refuses to budge!"))
return
open()
if(alarm_type)
addtimer(CALLBACK(src, .proc/correct_state), 2 SECONDS, TIMER_UNIQUE)
/obj/machinery/door/firedoor/do_animate(animation)
switch(animation)
@@ -214,54 +401,77 @@
if("closing")
flick("door_closing", src)
/*SKYRAT EDIT REMOVAL
/obj/machinery/door/firedoor/update_icon_state()
. = ..()
icon_state = "[base_icon_state]_[density ? "closed" : "open"]"
*/
/obj/machinery/door/firedoor/update_overlays()
. = ..()
if(!welded)
if(welded)
. += density ? "welded" : "welded_open"
if(alarm_type && powered())
var/mutable_appearance/hazards
hazards = mutable_appearance(icon, "[(obj_flags & EMAGGED) ? "firelock_alarm_type_emag" : alarm_type]")
hazards.pixel_x = light_xoffset
hazards.pixel_y = light_yoffset
. += hazards
hazards = emissive_appearance(icon, "[(obj_flags & EMAGGED) ? "firelock_alarm_type_emag" : alarm_type]", alpha = src.alpha)
hazards.pixel_x = light_xoffset
hazards.pixel_y = light_yoffset
. += hazards
/**
* Corrects the current state of the door, based on if alarm_type is set.
*
* This proc is called after weld and power restore events. Gives the
* illusion that the door is constantly attempting to move without actually
* having to process it. Timers also call this, so that if alarm_type
* changes during the timer, the door doesn't close or open incorrectly.
*/
/obj/machinery/door/firedoor/proc/correct_state()
if(obj_flags & EMAGGED || being_held_open)
return //Unmotivated, indifferent, we have no real care what state we're in anymore.
if(alarm_type && !density) //We should be closed but we're not
INVOKE_ASYNC(src, .proc/close)
return
if(!alarm_type && density) //We should be open but we're not
INVOKE_ASYNC(src, .proc/open)
return
. += density ? "welded" : "welded_open"
/obj/machinery/door/firedoor/open()
if(welded)
return
var/alarm = alarm_type
. = ..()
latetoggle()
if(alarm != alarm_type) //Something changed while we were sleeping
correct_state() //So we should re-evaluate our state
/obj/machinery/door/firedoor/close()
if(HAS_TRAIT(loc, TRAIT_FIREDOOR_STOP))
return
var/alarm = alarm_type
. = ..()
latetoggle()
if(alarm != alarm_type) //Something changed while we were sleeping
correct_state() //So we should re-evaluate our state
/obj/machinery/door/firedoor/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
var/turf/T = get_turf(src)
var/turf/targetloc = get_turf(src)
if(disassembled || prob(40))
var/obj/structure/firelock_frame/F = new assemblytype(T)
var/obj/structure/firelock_frame/unbuilt_lock = new assemblytype(targetloc)
if(disassembled)
F.constructionStep = CONSTRUCTION_PANEL_OPEN
unbuilt_lock.constructionStep = CONSTRUCTION_PANEL_OPEN
else
F.constructionStep = CONSTRUCTION_NO_CIRCUIT
F.update_integrity(F.max_integrity * 0.5)
F.update_appearance()
unbuilt_lock.constructionStep = CONSTRUCTION_NO_CIRCUIT
unbuilt_lock.update_integrity(unbuilt_lock.max_integrity * 0.5)
unbuilt_lock.update_appearance()
else
new /obj/item/electronics/firelock (T)
new /obj/item/electronics/firelock (targetloc)
qdel(src)
/obj/machinery/door/firedoor/proc/latetoggle()
if(operating || machine_stat & NOPOWER || !nextstate)
return
switch(nextstate)
if(FIREDOOR_OPEN)
nextstate = null
open()
if(FIREDOOR_CLOSED)
nextstate = null
close()
/obj/machinery/door/firedoor/closed
icon_state = "door_closed"
density = TRUE
/obj/machinery/door/firedoor/border_only
icon = 'icons/obj/doors/edge_Doorfire.dmi'
@@ -281,6 +491,25 @@
)
AddElement(/datum/element/connect_loc, loc_connections)
adjust_lights_starting_offset()
/obj/machinery/door/firedoor/border_only/adjust_lights_starting_offset()
light_xoffset = 0
light_yoffset = 0
switch(dir)
if(NORTH)
light_yoffset = 2
if(SOUTH)
light_yoffset = -2
if(EAST)
light_xoffset = 2
if(WEST)
light_xoffset = -2
update_icon()
/obj/machinery/door/firedoor/border_only/Moved()
. = ..()
adjust_lights_starting_offset()
/obj/machinery/door/firedoor/border_only/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
@@ -306,7 +535,7 @@
/obj/machinery/door/firedoor/heavy
name = "heavy firelock"
icon = 'icons/obj/doors/Doorfire.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
icon = 'icons/obj/doors/Doorfire.dmi' //SKYRAT EDIT - ICON OVERRIDEN IN AESTHETICS MODULE
glass = FALSE
explosion_block = 2
assemblytype = /obj/structure/firelock_frame/heavy
@@ -321,7 +550,7 @@
/obj/structure/firelock_frame
name = "firelock frame"
desc = "A partially completed firelock."
icon = 'icons/obj/doors/Doorfire.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
icon = 'icons/obj/doors/Doorfire.dmi' //SKYRAT EDIT - ICON OVERRIDEN IN AESTHETICS MODULE
icon_state = "frame1"
base_icon_state = "frame"
anchored = FALSE
@@ -343,14 +572,14 @@
icon_state = "[base_icon_state][constructionStep]"
return ..()
/obj/structure/firelock_frame/attackby(obj/item/C, mob/user)
/obj/structure/firelock_frame/attackby(obj/item/attacking_object, mob/user)
switch(constructionStep)
if(CONSTRUCTION_PANEL_OPEN)
if(C.tool_behaviour == TOOL_CROWBAR)
C.play_tool_sound(src)
if(attacking_object.tool_behaviour == TOOL_CROWBAR)
attacking_object.play_tool_sound(src)
user.visible_message(span_notice("[user] begins removing the circuit board from [src]..."), \
span_notice("You begin prying out the circuit board from [src]..."))
if(!C.use_tool(src, user, DEFAULT_STEP_TIME))
if(!attacking_object.use_tool(src, user, DEFAULT_STEP_TIME))
return
if(constructionStep != CONSTRUCTION_PANEL_OPEN)
return
@@ -361,14 +590,14 @@
constructionStep = CONSTRUCTION_NO_CIRCUIT
update_appearance()
return
if(C.tool_behaviour == TOOL_WRENCH)
if(attacking_object.tool_behaviour == TOOL_WRENCH)
if(locate(/obj/machinery/door/firedoor) in get_turf(src))
to_chat(user, span_warning("There's already a firelock there."))
return
C.play_tool_sound(src)
attacking_object.play_tool_sound(src)
user.visible_message(span_notice("[user] starts bolting down [src]..."), \
span_notice("You begin bolting [src]..."))
if(!C.use_tool(src, user, DEFAULT_STEP_TIME))
if(!attacking_object.use_tool(src, user, DEFAULT_STEP_TIME))
return
if(locate(/obj/machinery/door/firedoor) in get_turf(src))
return
@@ -381,61 +610,61 @@
new /obj/machinery/door/firedoor(get_turf(src))
qdel(src)
return
if(istype(C, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/P = C
if(istype(attacking_object, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/plasteel_sheet = attacking_object
if(reinforced)
to_chat(user, span_warning("[src] is already reinforced."))
return
if(P.get_amount() < 2)
if(plasteel_sheet.get_amount() < 2)
to_chat(user, span_warning("You need more plasteel to reinforce [src]."))
return
user.visible_message(span_notice("[user] begins reinforcing [src]..."), \
span_notice("You begin reinforcing [src]..."))
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, TRUE)
if(do_after(user, DEFAULT_STEP_TIME, target = src))
if(constructionStep != CONSTRUCTION_PANEL_OPEN || reinforced || P.get_amount() < 2 || !P)
if(constructionStep != CONSTRUCTION_PANEL_OPEN || reinforced || plasteel_sheet.get_amount() < 2 || !plasteel_sheet)
return
user.visible_message(span_notice("[user] reinforces [src]."), \
span_notice("You reinforce [src]."))
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, TRUE)
P.use(2)
plasteel_sheet.use(2)
reinforced = 1
return
if(CONSTRUCTION_NO_CIRCUIT)
if(istype(C, /obj/item/electronics/firelock))
user.visible_message(span_notice("[user] starts adding [C] to [src]..."), \
if(istype(attacking_object, /obj/item/electronics/firelock))
user.visible_message(span_notice("[user] starts adding [attacking_object] to [src]..."), \
span_notice("You begin adding a circuit board to [src]..."))
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, TRUE)
if(!do_after(user, DEFAULT_STEP_TIME, target = src))
return
if(constructionStep != CONSTRUCTION_NO_CIRCUIT)
return
qdel(C)
qdel(attacking_object)
user.visible_message(span_notice("[user] adds a circuit to [src]."), \
span_notice("You insert and secure [C]."))
span_notice("You insert and secure [attacking_object]."))
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, TRUE)
constructionStep = CONSTRUCTION_PANEL_OPEN
return
if(C.tool_behaviour == TOOL_WELDER)
if(!C.tool_start_check(user, amount=1))
if(attacking_object.tool_behaviour == TOOL_WELDER)
if(!attacking_object.tool_start_check(user, amount=1))
return
user.visible_message(span_notice("[user] begins cutting apart [src]'s frame..."), \
span_notice("You begin slicing [src] apart..."))
if(C.use_tool(src, user, DEFAULT_STEP_TIME, volume=50, amount=1))
if(attacking_object.use_tool(src, user, DEFAULT_STEP_TIME, volume=50, amount=1))
if(constructionStep != CONSTRUCTION_NO_CIRCUIT)
return
user.visible_message(span_notice("[user] cuts apart [src]!"), \
span_notice("You cut [src] into metal."))
var/turf/T = get_turf(src)
new /obj/item/stack/sheet/iron(T, 3)
var/turf/tagetloc = get_turf(src)
new /obj/item/stack/sheet/iron(tagetloc, 3)
if(reinforced)
new /obj/item/stack/sheet/plasteel(T, 2)
new /obj/item/stack/sheet/plasteel(tagetloc, 2)
qdel(src)
return
if(istype(C, /obj/item/electroadaptive_pseudocircuit))
var/obj/item/electroadaptive_pseudocircuit/P = C
if(!P.adapt_circuit(user, DEFAULT_STEP_TIME * 0.5))
if(istype(attacking_object, /obj/item/electroadaptive_pseudocircuit))
var/obj/item/electroadaptive_pseudocircuit/raspberrypi = attacking_object
if(!raspberrypi.adapt_circuit(user, DEFAULT_STEP_TIME * 0.5))
return
user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \
span_notice("You adapt a firelock circuit and slot it into the assembly."))
@@ -471,3 +700,4 @@
#undef CONSTRUCTION_PANEL_OPEN
#undef CONSTRUCTION_NO_CIRCUIT
#undef DETECT_COOLDOWN_STEP_TIME
+93 -92
View File
@@ -1,5 +1,3 @@
#define FIREALARM_COOLDOWN 80 //SKYRAT EDIT CHANGE - ORIGINAL: 96 - AESTHETIC // This define is based on the current FireAlarm.ogg, and is placed to match the running time at 9 seconds 600 milliseconds (9.6 seconds)
/obj/item/electronics/firealarm
name = "fire alarm electronics"
desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
@@ -7,7 +5,7 @@
/obj/item/wallframe/firealarm
name = "fire alarm frame"
desc = "Used for building fire alarms."
icon = 'icons/obj/monitors.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
icon = 'icons/obj/monitors.dmi'
icon_state = "fire_bitem"
result_path = /obj/machinery/firealarm
pixel_shift = 26
@@ -15,7 +13,7 @@
/obj/machinery/firealarm
name = "fire alarm"
desc = "<i>\"Pull this in case of emergency\"</i>. Thus, keep pulling it forever."
icon = 'icons/obj/monitors.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
icon = 'icons/obj/monitors.dmi'
icon_state = "fire0"
max_integrity = 250
integrity_failure = 0.4
@@ -32,15 +30,13 @@
//Trick to get the glowing overlay visible from a distance
luminosity = 1
///Buildstate for contruction steps. 2 = complete, 1 = no wires, 0 = circuit gone
var/buildstage = 2
///Our home area, set in Init. Due to loading step order, this seems to be null very early in the server setup process, which is why some procs use `my_area?` for var or list checks.
var/area/my_area = null
///looping sound datum for our fire alarm siren.
var/datum/looping_sound/firealarm/soundloop
var/detecting = 1
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
COOLDOWN_DECLARE(last_alarm)
var/area/myarea = null
//Has this firealarm been triggered by its enviroment?
var/triggered = FALSE
/* SKYRAT EDIT REMOVAL
/obj/machinery/firealarm/Initialize(mapload, dir, building)
. = ..()
if(building)
@@ -49,18 +45,34 @@
if(name == initial(name))
name = "[get_area_name(src)] [initial(name)]"
update_appearance()
myarea = get_area(src)
LAZYADD(myarea.firealarms, src)
my_area = get_area(src)
LAZYADD(my_area.firealarms, src)
AddElement(/datum/element/atmos_sensitive, mapload)
RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, .proc/check_security_level)
soundloop = new(src, FALSE)
/obj/machinery/firealarm/Destroy()
myarea.firereset(src)
LAZYREMOVE(myarea.firealarms, src)
if(my_area)
LAZYREMOVE(my_area.firealarms, src)
my_area = null
QDEL_NULL(soundloop)
return ..()
*/
/**
* Sets the sound state, and then calls update_icon()
*
* This proc exists to be called by areas and firelocks
* so that it may update its icon and start or stop playing
* the alarm sound based on the state of an area variable.
*/
/obj/machinery/firealarm/proc/set_status()
if( (my_area.fire || LAZYLEN(my_area.active_firelocks)) && !(obj_flags & EMAGGED) )
set_light(l_power = 0.8)
else
soundloop.stop()
set_light(l_power = 0)
update_icon()
/obj/machinery/firealarm/update_icon_state()
if(panel_open)
@@ -87,12 +99,11 @@
. += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]")
. += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]", alpha = src.alpha)
var/area/area = get_area(src)
if(!detecting || !area.fire)
. += "fire_off"
. += mutable_appearance(icon, "fire_off")
. += emissive_appearance(icon, "fire_off", alpha = src.alpha)
if(!(my_area?.fire || LAZYLEN(my_area?.active_firelocks)))
if(my_area?.fire_detect) //If this is false, leave the green light missing. A good hint to anyone paying attention.
. += "fire_off"
. += mutable_appearance(icon, "fire_off")
. += emissive_appearance(icon, "fire_off", alpha = src.alpha)
else if(obj_flags & EMAGGED)
. += "fire_emagged"
. += mutable_appearance(icon, "fire_emagged")
@@ -102,7 +113,7 @@
. += mutable_appearance(icon, "fire_on")
. += emissive_appearance(icon, "fire_on", alpha = src.alpha)
if(!panel_open && detecting && triggered) //It just looks horrible with the panel open
if(!panel_open && my_area?.fire_detect && my_area?.fire) //It just looks horrible with the panel open
. += "fire_detected"
. += mutable_appearance(icon, "fire_detected")
. += emissive_appearance(icon, "fire_detected", alpha = src.alpha) //Pain
@@ -123,30 +134,9 @@
update_appearance()
if(user)
user.visible_message(span_warning("Sparks fly out of [src]!"),
span_notice("You emag [src], disabling its thermal sensors."))
span_notice("You override [src], disabling the speaker."))
playsound(src, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
/* SKYRAT EDIT REMOVAL
/obj/machinery/firealarm/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return (exposed_temperature > T0C + 200 || exposed_temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && !(obj_flags & EMAGGED) && !machine_stat
/obj/machinery/firealarm/atmos_expose(datum/gas_mixture/air, exposed_temperature)
if(!detecting)
return
if(!triggered)
triggered = TRUE
myarea.triggered_firealarms += 1
update_appearance()
alarm()
/obj/machinery/firealarm/atmos_end()
if(!detecting)
return
if(triggered)
triggered = FALSE
myarea.triggered_firealarms -= 1
update_appearance()
*/
set_status()
/**
* Signal handler for checking if we should update fire alarm appearance accordingly to a newly set security level
@@ -161,45 +151,69 @@
if(is_station_level(z))
update_appearance()
/*SKYRAT EDIT REMOVAL
/**
* Sounds the fire alarm and closes all firelocks in the area. Also tells the area to color the lights red.
*
* Arguments:
* * mob/user is the user that pulled the alarm.
*/
/obj/machinery/firealarm/proc/alarm(mob/user)
if(!is_operational || !COOLDOWN_FINISHED(src, last_alarm))
if(!is_operational)
return
COOLDOWN_START(src, last_alarm, FIREALARM_COOLDOWN)
var/area/area = get_area(src)
area.firealert(src)
//playsound(loc, 'sound/machines/FireAlarm.ogg', 96) ORIGINAL
playsound(loc, alarm_sound, 75) //SKYRAT EDIT CHANGE - AESTHETICS
if(my_area.fire)
return //area alarm already active
my_area.alarm_manager.send_alarm(ALARM_FIRE, my_area)
my_area.set_fire_alarm_effect()
for(var/obj/machinery/door/firedoor/firelock in my_area.firedoors)
firelock.activate(FIRELOCK_ALARM_TYPE_GENERIC)
if(user)
log_game("[user] triggered a fire alarm at [COORD(src)]")
soundloop.start() //Manually pulled fire alarms will make the sound, rather than the doors.
/**
* Resets all firelocks in the area. Also tells the area to disable alarm lighting, if it was enabled.
*
* Arguments:
* * mob/user is the user that reset the alarm.
*/
/obj/machinery/firealarm/proc/reset(mob/user)
if(!is_operational)
return
var/area/area = get_area(src)
area.firereset()
my_area.unset_fire_alarm_effects()
for(var/obj/machinery/door/firedoor/firelock in my_area.firedoors)
firelock.reset()
my_area.alarm_manager.clear_alarm(ALARM_FIRE, my_area)
if(user)
log_game("[user] reset a fire alarm at [COORD(src)]")
soundloop.stop()
/obj/machinery/firealarm/attack_hand(mob/user, list/modifiers)
if(buildstage != 2)
return
. = ..()
add_fingerprint(user)
var/area/area = get_area(src)
if(area.fire)
reset(user)
else
alarm(user)
*/
alarm(user)
/obj/machinery/firealarm/attack_hand_secondary(mob/user, list/modifiers)
if(buildstage != 2)
return ..()
add_fingerprint(user)
reset(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/machinery/firealarm/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/firealarm/attack_ai_secondary(mob/user)
return attack_hand_secondary(user)
/obj/machinery/firealarm/attack_robot(mob/user)
return attack_hand(user)
/*SKYRAT EDIT REMOVAL
/obj/machinery/firealarm/attack_robot_secondary(mob/user)
return attack_hand_secondary(user)
/obj/machinery/firealarm/attackby(obj/item/tool, mob/living/user, params)
add_fingerprint(user)
@@ -227,15 +241,7 @@
switch(buildstage)
if(2)
if(tool.tool_behaviour == TOOL_MULTITOOL)
detecting = !detecting
if (src.detecting)
user.visible_message(span_notice("[user] reconnects [src]'s detecting unit!"), span_notice("You reconnect [src]'s detecting unit."))
else
user.visible_message(span_notice("[user] disconnects [src]'s detecting unit!"), span_notice("You disconnect [src]'s detecting unit."))
return
else if(tool.tool_behaviour == TOOL_WIRECUTTER)
if(tool.tool_behaviour == TOOL_WIRECUTTER)
buildstage = 1
tool.play_tool_sound(src)
new /obj/item/stack/cable_coil(user.loc, 5)
@@ -302,9 +308,7 @@
tool.play_tool_sound(src)
qdel(src)
return
return ..()
*/
/obj/machinery/firealarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
if((buildstage == 0) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
@@ -331,16 +335,12 @@
/obj/machinery/firealarm/singularity_pull(S, current_size)
if (current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects, the fire alarm experiences integrity failure
deconstruct()
..()
return ..()
/* SKYRAT EDIT REMOVAL
/obj/machinery/firealarm/atom_break(damage_flag)
if(buildstage == 0) //can't break the electronics if there isn't any inside.
return
. = ..()
if(.)
LAZYREMOVE(myarea.firealarms, src)
*/
return ..()
/obj/machinery/firealarm/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
@@ -352,18 +352,16 @@
new /obj/item/stack/cable_coil(loc, 3)
qdel(src)
/obj/machinery/firealarm/proc/update_fire_light(fire)
if(fire == !!light_power)
return // do nothing if we're already active
if(fire)
set_light(l_power = 0.8)
else
set_light(l_power = 0)
// Allows users to examine the state of the thermal sensor
/obj/machinery/firealarm/examine(mob/user)
. = ..()
. += "A light on the side indicates the thermal sensor is [detecting ? "enabled" : "disabled"]."
if((my_area?.fire || LAZYLEN(my_area?.active_firelocks)))
. += "The local area hazard light is flashing."
. += "<b>Left-Click</b> to activate all firelocks in this area."
. += "<b>Right-Click</b> or <b>Alt-Click</b> to reset firelocks in this area."
else
. += "The local area thermal detection light is [my_area.fire_detect ? "lit" : "unlit"]."
. += "<b>Left-Click</b> to activate all firelocks in this area."
// Allows Silicons to disable thermal sensor
/obj/machinery/firealarm/BorgCtrlClick(mob/living/silicon/robot/user)
@@ -376,8 +374,11 @@
if(obj_flags & EMAGGED)
to_chat(user, span_warning("The control circuitry of [src] appears to be malfunctioning."))
return
detecting = !detecting
to_chat(user, span_notice("You [ detecting ? "enable" : "disable" ] [src]'s detecting unit!"))
my_area.fire_detect = !my_area.fire_detect
for(var/obj/machinery/firealarm/fire_panel in my_area.firealarms)
fire_panel.update_icon()
to_chat(user, span_notice("You [ my_area.fire_detect ? "enable" : "disable" ] the local firelock thermal sensors!"))
log_game("[user] has [ my_area.fire_detect ? "enabled" : "disabled" ] firelock sensors using [src] at [COORD(src)]")
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
@@ -91,7 +91,7 @@ again.
/obj/effect/spawner/structure/window/reinforced
name = "reinforced window spawner"
icon_state = "rwindow_spawner"
spawn_list = list(/obj/machinery/door/firedoor/onetile, /obj/structure/grille, /obj/structure/window/reinforced/fulltile) //SKYRAT EDIT CHANGE
spawn_list = list(/obj/machinery/door/firedoor, /obj/structure/grille, /obj/structure/window/reinforced/fulltile) //SKYRAT EDIT CHANGE
/obj/effect/spawner/structure/window/hollow/reinforced
name = "hollow reinforced window spawner"
+2 -2
View File
@@ -61,7 +61,7 @@
/obj/item/card/emag/Initialize(mapload)
. = ..()
type_blacklist = list(typesof(/obj/machinery/door/airlock), typesof(/obj/machinery/door/window/)) //list of all typepaths that require a specialized emag to hack.
type_blacklist = list(typesof(/obj/machinery/door/airlock), typesof(/obj/machinery/door/window/), typesof(/obj/machinery/door/firedoor)) //list of all typepaths that require a specialized emag to hack.
/obj/item/card/emag/attack()
return
@@ -101,7 +101,7 @@
/obj/item/card/emag/doorjack/Initialize(mapload)
. = ..()
type_whitelist = list(typesof(/obj/machinery/door/airlock), typesof(/obj/machinery/door/window/)) //list of all acceptable typepaths that this device can affect
type_whitelist = list(typesof(/obj/machinery/door/airlock), typesof(/obj/machinery/door/window/), typesof(/obj/machinery/door/firedoor)) //list of all acceptable typepaths that this device can affect
/obj/item/card/emag/doorjack/proc/use_charge(mob/user)
charges --
@@ -697,11 +697,15 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
uses = 1
/datum/action/innate/ai/break_fire_alarms/Activate()
for(var/obj/machinery/firealarm/F in GLOB.machines)
if(!is_station_level(F.z))
for(var/obj/machinery/firealarm/bellman in GLOB.machines)
if(!is_station_level(bellman.z))
continue
F.obj_flags |= EMAGGED
F.update_appearance()
bellman.obj_flags |= EMAGGED
bellman.update_appearance()
for(var/obj/machinery/door/firedoor/firelock in GLOB.machines)
if(!is_station_level(firelock.z))
continue
firelock.emag_act(owner_AI, src)
to_chat(owner, span_notice("All thermal sensors on the station have been disabled. Fire alerts will no longer be recognized."))
owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 20 KiB

@@ -1,199 +1,2 @@
/obj/machinery/firealarm
icon = 'modular_skyrat/modules/aesthetics/firealarm/icons/firealarm.dmi'
var/alarm_sound = 'modular_skyrat/modules/aesthetics/firealarm/sound/alarm_fire.ogg'
/obj/machinery/firealarm/Initialize(mapload, dir, building)
. = ..()
if(dir)
src.setDir(dir)
if(building)
buildstage = 0
panel_open = TRUE
pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
if(name == initial(name))
name = "[get_area_name(src)] [initial(name)]"
RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, .proc/check_security_level)
gather_objects()
update_appearance()
/obj/machinery/firealarm/proc/gather_objects()
var/area/my_area = get_area(src)
for(var/obj/machinery/light/iterating_light in my_area)
iterating_light.RegisterSignal(src, COMSIG_FIREALARM_TRIGGERED_ON, /obj/machinery/light.proc/firealarm_on)
iterating_light.RegisterSignal(src, COMSIG_FIREALARM_TRIGGERED_OFF, /obj/machinery/light.proc/firealarm_off)
for(var/obj/machinery/door/firedoor/iterating_firedoor in my_area)
iterating_firedoor.RegisterSignal(src, COMSIG_FIREALARM_TRIGGER_DOORS, /obj/machinery/door/firedoor.proc/firealarm_on)
iterating_firedoor.RegisterSignal(src, COMSIG_FIREALARM_TRIGGERED_OFF, /obj/machinery/door/firedoor.proc/firealarm_off)
for(var/obj/machinery/firealarm/iterating_firealarm in my_area)
if(iterating_firealarm == src) //Bad infinite loops.
continue
iterating_firealarm.RegisterSignal(src, COMSIG_FIREALARM_TRIGGERED_ON, .proc/area_alarm_on)
iterating_firealarm.RegisterSignal(src, COMSIG_FIREALARM_TRIGGERED_OFF, .proc/area_alarm_off)
/obj/machinery/firealarm/proc/area_alarm_on()
SIGNAL_HANDLER
triggered = TRUE
update_fire_light(TRUE)
update_appearance()
/obj/machinery/firealarm/proc/area_alarm_off()
SIGNAL_HANDLER
triggered = FALSE
update_fire_light(FALSE)
update_appearance()
/obj/machinery/firealarm/proc/alarm(mob/user)
if(triggered)
return
triggered = TRUE
if(!is_operational || !COOLDOWN_FINISHED(src, last_alarm))
return
COOLDOWN_START(src, last_alarm, FIREALARM_COOLDOWN)
playsound(loc, alarm_sound, 75)
if(user)
log_game("[user] triggered a fire alarm at [COORD(src)]")
trigger_effects()
trigger_doors()
update_appearance()
/obj/machinery/firealarm/proc/trigger_doors()
SEND_SIGNAL(src, COMSIG_FIREALARM_TRIGGER_DOORS)
/obj/machinery/firealarm/proc/trigger_effects()
SIGNAL_HANDLER
SEND_SIGNAL(src, COMSIG_FIREALARM_TRIGGERED_ON)
/obj/machinery/firealarm/proc/untrigger_effects()
SEND_SIGNAL(src, COMSIG_FIREALARM_TRIGGERED_OFF)
/obj/machinery/firealarm/proc/reset(mob/user)
if(!is_operational)
return
if(user)
log_game("[user] reset a fire alarm at [COORD(src)]")
triggered = FALSE
untrigger_effects()
update_appearance()
/obj/machinery/firealarm/attack_hand(mob/user, list/modifiers)
if(buildstage != 2)
return ..()
add_fingerprint(user)
if(triggered)
reset(user)
else
alarm(user, TRUE)
/obj/machinery/firealarm/attackby(obj/item/tool, mob/living/user, params)
add_fingerprint(user)
if(tool.tool_behaviour == TOOL_SCREWDRIVER && buildstage == 2)
tool.play_tool_sound(src)
panel_open = !panel_open
to_chat(user, span_notice("The wires have been [panel_open ? "exposed" : "unexposed"]."))
update_appearance()
return
if(panel_open)
if(tool.tool_behaviour == TOOL_WELDER && !user.combat_mode)
if(atom_integrity < max_integrity)
if(!tool.tool_start_check(user, amount=0))
return
to_chat(user, span_notice("You begin repairing [src]..."))
if(tool.use_tool(src, user, 40, volume=50))
atom_integrity = max_integrity
to_chat(user, span_notice("You repair [src]."))
else
to_chat(user, span_warning("[src] is already in good condition!"))
return
switch(buildstage)
if(2)
if(tool.tool_behaviour == TOOL_MULTITOOL)
detecting = !detecting
if (src.detecting)
user.visible_message(span_notice("[user] reconnects [src]'s detecting unit!"), span_notice("You reconnect [src]'s detecting unit."))
else
user.visible_message(span_notice("[user] disconnects [src]'s detecting unit!"), span_notice("You disconnect [src]'s detecting unit."))
return
else if(tool.tool_behaviour == TOOL_WIRECUTTER)
buildstage = 1
tool.play_tool_sound(src)
new /obj/item/stack/cable_coil(user.loc, 5)
to_chat(user, span_notice("You cut the wires from \the [src]."))
update_appearance()
return
else if(tool.force) //hit and turn it on
..()
if(!triggered)
alarm()
return
if(1)
if(istype(tool, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/coil = tool
if(coil.get_amount() < 5)
to_chat(user, span_warning("You need more cable for this!"))
else
coil.use(5)
buildstage = 2
to_chat(user, span_notice("You wire \the [src]."))
update_appearance()
return
else if(tool.tool_behaviour == TOOL_CROWBAR)
user.visible_message(span_notice("[user.name] removes the electronics from [src.name]."), \
span_notice("You start prying out the circuit..."))
if(tool.use_tool(src, user, 20, volume=50))
if(buildstage == 1)
if(machine_stat & BROKEN)
to_chat(user, span_notice("You remove the destroyed circuit."))
set_machine_stat(machine_stat & ~BROKEN)
else
to_chat(user, span_notice("You pry out the circuit."))
new /obj/item/electronics/firealarm(user.loc)
buildstage = 0
update_appearance()
return
if(0)
if(istype(tool, /obj/item/electronics/firealarm))
to_chat(user, span_notice("You insert the circuit."))
qdel(tool)
buildstage = 1
update_appearance()
return
else if(istype(tool, /obj/item/electroadaptive_pseudocircuit))
var/obj/item/electroadaptive_pseudocircuit/pseudoc = tool
if(!pseudoc.adapt_circuit(user, 15))
return
user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \
span_notice("You adapt a fire alarm circuit and slot it into the assembly."))
buildstage = 1
update_appearance()
return
else if(tool.tool_behaviour == TOOL_WRENCH)
user.visible_message(span_notice("[user] removes the fire alarm assembly from the wall."), \
span_notice("You remove the fire alarm assembly from the wall."))
var/obj/item/wallframe/firealarm/frame = new /obj/item/wallframe/firealarm()
frame.forceMove(user.drop_location())
tool.play_tool_sound(src)
qdel(src)
return
return ..()
@@ -1,116 +1,9 @@
#define FIREDOOR_CLOSE_OVERRIDE_RESET_TIME 3 MINUTES
/obj/machinery/door/firedoor
name = "emergency shutter"
desc = "Emergency air-tight shutter, capable of sealing off breached areas. This one has a glass panel. It has a mechanism to open it with just your hands."
icon = 'modular_skyrat/modules/aesthetics/firedoor/icons/firedoor_glass.dmi'
req_access = list(ACCESS_ATMOSPHERICS)
var/door_open_sound = 'modular_skyrat/modules/aesthetics/firedoor/sound/firedoor_open.ogg'
var/door_close_sound = 'modular_skyrat/modules/aesthetics/firedoor/sound/firedoor_open.ogg'
var/hot_or_cold = FALSE //True for hot, false for cold
var/stay_open = FALSE // Do we stay open? Triggered via atmos techs using their ID on it.
var/has_hotcold_sprite = TRUE //does it actually have the sprites needed
/obj/machinery/door/firedoor/heavy
name = "heavy emergency shutter"
desc = "Emergency air-tight shutter, capable of sealing off breached areas. It has a mechanism to open it with just your hands."
icon = 'modular_skyrat/modules/aesthetics/firedoor/icons/firedoor.dmi'
/obj/structure/firelock_frame
icon = 'modular_skyrat/modules/aesthetics/firedoor/icons/firedoor.dmi'
/obj/machinery/door/firedoor/border_only
has_hotcold_sprite = FALSE
/obj/machinery/door/firedoor/open()
playsound(loc, door_open_sound, 90, TRUE)
. = ..()
/obj/machinery/door/firedoor/close()
if(stay_open)
return
playsound(loc, door_close_sound, 90, TRUE)
return ..()
/obj/machinery/door/firedoor/proc/atmos_changed(datum/source, datum/gas_mixture/air, exposed_temperature)
if(density)
return
var/pressure = air.return_pressure()
if(exposed_temperature < BODYTEMP_COLD_DAMAGE_LIMIT || pressure < WARNING_LOW_PRESSURE)
hot_or_cold = FALSE
close()
else if(exposed_temperature > BODYTEMP_HEAT_DAMAGE_LIMIT || pressure > WARNING_HIGH_PRESSURE)
hot_or_cold = TRUE
trigger_hot()
close()
/obj/machinery/door/firedoor/proc/firealarm_on()
SIGNAL_HANDLER
INVOKE_ASYNC(src, .proc/close)
/obj/machinery/door/firedoor/proc/firealarm_off()
SIGNAL_HANDLER
INVOKE_ASYNC(src, .proc/open)
/obj/machinery/door/firedoor/proc/trigger_hot()
SEND_SIGNAL(src, COMSIG_FIREDOOR_CLOSED_FIRE)
/obj/machinery/door/firedoor/proc/CalculateAffectingAreas()
for(var/turf/adjacent_turf in range(1, src))
RegisterSignal(adjacent_turf, COMSIG_TURF_EXPOSE, .proc/atmos_changed, override = TRUE)
var/my_area = get_area(src)
for(var/obj/machinery/firealarm/iterating_alarm in my_area)
iterating_alarm.RegisterSignal(src, COMSIG_FIREDOOR_CLOSED_FIRE, /obj/machinery/firealarm.proc/trigger_effects, override = TRUE) //We trigger the alarms automatically.
/obj/machinery/door/firedoor/update_icon_state()
. = ..()
if(density)
icon_state = "[base_icon_state]_closed[has_hotcold_sprite ? (hot_or_cold ? "_hot" : "_cold") : ""]"
else
icon_state = "[base_icon_state]_open"
/obj/machinery/door/firedoor/onetile/CalculateAffectingAreas()
RegisterSignal(loc, COMSIG_TURF_EXPOSE, .proc/atmos_changed, override = TRUE)
var/my_area = get_area(src)
for(var/obj/machinery/firealarm/iterating_alarm in my_area)
iterating_alarm.RegisterSignal(src, COMSIG_FIREDOOR_CLOSED_FIRE, /obj/machinery/firealarm.proc/trigger_effects, override = TRUE) //We trigger the alarms automatically.
/obj/machinery/door/firedoor/attackby(obj/item/C, mob/user, params)
if(C.GetID())
if(allowed(user))
toggle_close_override(user)
return ..()
/obj/machinery/door/firedoor/CtrlClick(mob/user)
if(!user.canUseTopic(src, !issilicon(user)))
return
toggle_close_override(user)
/obj/machinery/door/firedoor/proc/toggle_close_override(mob/user)
stay_open = !stay_open
balloon_alert(user, "close override [stay_open ? "engaged" : "disengaged"]")
addtimer(CALLBACK(src, .proc/close_override_reset), FIREDOOR_CLOSE_OVERRIDE_RESET_TIME)
/obj/machinery/door/firedoor/proc/close_override_reset()
stay_open = FALSE
/obj/machinery/door/firedoor/examine(mob/user)
. = ..()
if(issilicon(user))
. += span_notice("You can override the closing mechanism by Ctrl+Clicking on the firelock.")
else
. += span_notice("You can override the closing mechanism by swiping your ID on it, providing it has Atmospherics Access.")
. += span_notice("It's close override mechanism is [stay_open ? "engaged" : "disengaged"].")
/obj/effect/spawner/structure/window/reinforced/no_firelock
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/fulltile)
#undef FIREDOOR_CLOSE_OVERRIDE_RESET_TIME
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

+1
View File
@@ -71,6 +71,7 @@
#include "code\__DEFINES\explosions.dm"
#include "code\__DEFINES\exports.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
#include "code\__DEFINES\firealarm.dm"
#include "code\__DEFINES\flags.dm"
#include "code\__DEFINES\food.dm"
#include "code\__DEFINES\footsteps.dm"