Ports TG emergency lights, adds special code Epsilon and Delta effects. (#16333)

Co-authored-by: SabreML <57483089+SabreML@users.noreply.github.com>
This commit is contained in:
S34N
2021-12-01 21:20:53 +00:00
committed by GitHub
parent 31b336da64
commit e72fda67b2
6 changed files with 180 additions and 46 deletions
+8 -5
View File
@@ -1,5 +1,6 @@
/area
var/fire = null
var/area_emergency_mode = FALSE // When true, fire alarms cannot unset emergency lighting. Not to be confused with emergency_mode var on light objects.
var/atmosalm = ATMOS_ALARM_NONE
var/poweralm = TRUE
var/report_alerts = TRUE // Should atmos alerts notify the AI/computers
@@ -345,21 +346,23 @@
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
if(area_emergency_mode) //Fires are not legally allowed if the power is off
return
for(var/obj/machinery/light/L in src)
L.fire_mode = TRUE
L.update(TRUE, TRUE, FALSE)
/**
* unset the fire alarm visual affects in an area
*
* Updates the fire light on fire alarms in the area and sets all lights to emergency mode
*/
///unset the fire alarm visual affects in an area
/area/proc/unset_fire_alarm_effects()
fire = FALSE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
if(area_emergency_mode) //The lights stay red until the crisis is resolved
return
for(var/obj/machinery/light/L in src)
L.fire_mode = FALSE
L.update(TRUE, TRUE, FALSE)
/area/proc/updateicon()
+25
View File
@@ -116,6 +116,11 @@
var/nightshift_lights = FALSE
var/last_nightshift_switch = 0
///Used to determine if emergency lights should be on or off
var/emergency_power = TRUE
var/emergency_power_timer
var/emergency_lights = FALSE
/obj/machinery/power/apc/worn_out
name = "\improper Worn out APC"
keep_preset_name = 1
@@ -124,6 +129,7 @@
equipment = 0
lighting = 0
operating = 0
emergency_power = FALSE
/obj/machinery/power/apc/noalarm
report_power_alarm = FALSE
@@ -810,6 +816,7 @@
data["siliconLock"] = locked
data["malfStatus"] = get_malf_status(user)
data["nightshiftLights"] = nightshift_lights
data["emergencyLights"] = !emergency_lights
var/powerChannels[0]
powerChannels[++powerChannels.len] = list(
@@ -855,6 +862,13 @@
area.power_light = (lighting > 1)
area.power_equip = (equipment > 1)
area.power_environ = (environ > 1)
if(lighting)
emergency_power = TRUE
if(emergency_power_timer)
deltimer(emergency_power_timer)
emergency_power_timer = null
else
emergency_power_timer = addtimer(CALLBACK(src, .proc/turn_emergency_power_off), 10 MINUTES, TIMER_UNIQUE|TIMER_STOPPABLE)
// if(area.name == "AI Chamber")
// spawn(10)
// to_chat(world, " [area.name] [area.power_equip]")
@@ -862,10 +876,16 @@
area.power_light = 0
area.power_equip = 0
area.power_environ = 0
emergency_power_timer = addtimer(CALLBACK(src, .proc/turn_emergency_power_off), 10 MINUTES, TIMER_UNIQUE|TIMER_STOPPABLE)
// if(area.name == "AI Chamber")
// to_chat(world, "[area.power_equip]")
area.power_change()
/obj/machinery/power/apc/proc/turn_emergency_power_off()
emergency_power = FALSE
for(var/obj/machinery/light/L in area)
INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE)
/obj/machinery/power/apc/proc/can_use(mob/user, loud = 0) //used by attack_hand() and Topic()
if(user.can_admin_interact())
return 1
@@ -971,6 +991,11 @@
if("deoccupy")
if(get_malf_status(usr))
malfvacate()
if("emergency_lighting")
emergency_lights = !emergency_lights
for(var/obj/machinery/light/L in area)
INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE)
CHECK_TICK
/obj/machinery/power/apc/proc/toggle_breaker()
operating = !operating
+71 -27
View File
@@ -11,6 +11,9 @@
#define LIGHT_ON_DELAY_LOWER 1 SECONDS
#define LIGHT_ON_DELAY_UPPER 3 SECONDS
#define MAXIMUM_SAFE_BACKUP_CHARGE 600
#define EMERGENCY_LIGHT_POWER_USE 0.5
/**
* # Light fixture frame
*
@@ -36,8 +39,8 @@
/// Holder for the completed fixture
var/obj/machinery/light/newlight = null
/obj/machinery/light_construct/New()
..()
/obj/machinery/light_construct/Initialize(mapload, ndir, building)
. = ..()
if(fixture_type == "bulb")
icon_state = "bulb-construct-stage1"
@@ -102,14 +105,12 @@
newlight = new /obj/machinery/light/built(loc)
if("bulb")
newlight = new /obj/machinery/light/small/built(loc)
newlight.setDir(dir)
transfer_fingerprints_to(newlight)
qdel(src)
/obj/machinery/light_construct/attackby(obj/item/W, mob/living/user, params)
add_fingerprint(user)
if(istype(W, /obj/item/stack/cable_coil))
if(stage != 1)
return
@@ -217,6 +218,9 @@
/// The colour of the light while it's in emergency mode
var/bulb_emergency_colour = "#FF3232"
var/emergency_mode = FALSE // if true, the light is in emergency mode
var/fire_mode = FALSE // if true, the light swaps over to emergency colour
var/no_emergency = FALSE // if true, this light cannot ever have an emergency mode
/**
* # Small light fixture
@@ -278,8 +282,7 @@
switch(status) // set icon_states
if(LIGHT_OK)
var/area/A = get_area(src)
if(A && A.fire)
if(emergency_mode)
icon_state = "[base_state]_emergency"
else
icon_state = "[base_state][on]"
@@ -303,20 +306,26 @@
* * play_sound - Will the lightbulb play a sound when it's turned on.
*/
/obj/machinery/light/proc/update(trigger = TRUE, instant = FALSE, play_sound = TRUE)
var/area/current_area = get_area(src)
UnregisterSignal(current_area, COMSIG_AREA_POWER_CHANGE)
switch(status)
if(LIGHT_BROKEN, LIGHT_BURNED, LIGHT_EMPTY)
on = FALSE
emergency_mode = FALSE
if(fire_mode)
set_emergency_lights()
if(on) // Turning on
if(instant)
_turn_on(trigger, play_sound)
else if(!turning_on)
turning_on = TRUE
addtimer(CALLBACK(src, .proc/_turn_on, trigger, play_sound), rand(LIGHT_ON_DELAY_LOWER, LIGHT_ON_DELAY_UPPER))
else if(!turned_off())
set_emergency_lights()
else // Turning off
use_power = IDLE_POWER_USE
set_light(0)
update_icon()
update_icon()
active_power_usage = (brightness_range * 10)
if(on != power_state) // Light was turned on/off, so update the power usage
power_state = on
@@ -326,6 +335,7 @@
else
removeStaticPower(static_power_used, STATIC_LIGHT)
/**
* The actual proc to turn on the lightbulb.
*
@@ -346,8 +356,7 @@
var/CO = brightness_color
if(color)
CO = color
var/area/A = get_area(src)
if(A?.fire)
if(emergency_mode)
CO = bulb_emergency_colour
else if(nightshift_enabled)
BR = nightshift_light_range
@@ -406,8 +415,6 @@
if(LIGHT_BROKEN)
. += "The [fitting] has been smashed."
// attack with item - insert light (if right type), otherwise try to break the light
/obj/machinery/light/attackby(obj/item/W, mob/living/user, params)
@@ -416,9 +423,10 @@
if(istype(W, /obj/item/lightreplacer))
var/obj/item/lightreplacer/LR = W
LR.ReplaceLight(src, user)
return
// attempt to insert light
else if(istype(W, /obj/item/light))
if(istype(W, /obj/item/light))
if(status != LIGHT_EMPTY)
to_chat(user, "<span class='warning'>There is a [fitting] already inserted.</span>")
else
@@ -447,13 +455,12 @@
explode()
else
to_chat(user, "<span class='warning'>This type of light requires a [fitting].</span>")
return
return
// attempt to break the light
//If xenos decide they want to smash a light bulb with a toolbox, who am I to stop them? /N
else if(status != LIGHT_BROKEN && status != LIGHT_EMPTY)
if(status != LIGHT_BROKEN && status != LIGHT_EMPTY)
user.do_attack_animation(src)
if(prob(1 + W.force * 5))
@@ -463,14 +470,14 @@
if(prob(12))
electrocute_mob(user, get_area(src), src, 0.3, TRUE)
break_light_tube()
else
user.visible_message("<span class='danger'>[user] hits the light.</span>", "<span class='danger'>You hit the light.</span>", \
"<span class='danger'>You hear someone hitting a light.</span>")
playsound(loc, 'sound/effects/glasshit.ogg', 75, 1)
return
// attempt to stick weapon into light socket
else if(status == LIGHT_EMPTY)
if(status == LIGHT_EMPTY)
if(istype(W, /obj/item/screwdriver)) //If it's a screwdriver open it.
playsound(loc, W.usesound, W.tool_volume, 1)
user.visible_message("<span class='notice'>[user] opens [src]'s casing.</span>", \
@@ -485,8 +492,9 @@
to_chat(user, "<span class='userdanger'>You are electrocuted by [src]!</span>")
else // If not electrocuted
to_chat(user, "<span class='danger'>You stick [W] into the light socket!</span>")
else
return ..()
return
return ..()
/obj/machinery/light/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
@@ -540,17 +548,45 @@
if(BURN)
playsound(loc, 'sound/items/welder.ogg', 100, TRUE)
// returns if the light has power /but/ is manually turned off
// if a light is turned off, it won't activate emergency power
/obj/machinery/light/proc/turned_off()
var/area/A = get_area(src)
return !A.lightswitch && A.power_light
// returns whether this light has power
// true if area has power and lightswitch is on
/obj/machinery/light/proc/has_power()
var/area/A = get_area(src)
return A.lightswitch && A.power_light
// attempts to set emergency lights
/obj/machinery/light/proc/set_emergency_lights()
var/area/current_area = get_area(src)
var/obj/machinery/power/apc/current_apc = current_area.get_apc()
if(status != LIGHT_OK || !current_apc || flickering || no_emergency)
emergency_lights_off(current_area, current_apc)
return
if(current_apc.emergency_lights || !current_apc.emergency_power)
emergency_lights_off(current_area, current_apc)
return
if(fire_mode)
set_light(nightshift_light_range, nightshift_light_power, bulb_emergency_colour)
return
emergency_mode = TRUE
set_light(3, 1.7, bulb_emergency_colour)
RegisterSignal(current_area, COMSIG_AREA_POWER_CHANGE, .proc/update, override = TRUE)
/obj/machinery/light/proc/emergency_lights_off(area/current_area, obj/machinery/power/apc/current_apc)
set_light(0, 0, 0) //you, sir, are off!
if(current_apc)
RegisterSignal(current_area, COMSIG_AREA_POWER_CHANGE, .proc/update, override = TRUE)
/obj/machinery/light/flicker(amount = rand(20, 30))
if(flickering)
return FALSE
if(!on || status != LIGHT_OK)
if(!on || status != LIGHT_OK || emergency_mode)
return FALSE
flickering = TRUE
@@ -578,9 +614,11 @@
flickering = FALSE
// ai attack - make lights flicker, because why not
// ai attack - toggle emergency lighting
/obj/machinery/light/attack_ai(mob/user)
flicker(1)
no_emergency = !no_emergency
to_chat(user, "<span class='notice'>Emergency lights for this fixture have been [no_emergency ? "disabled" : "enabled"].</span>")
update(FALSE)
// attack with hand - remove tube/bulb
// if hands aren't protected and the light is on, burn the player
@@ -589,10 +627,6 @@
user.changeNext_move(CLICK_CD_MELEE)
add_fingerprint(user)
if(status == LIGHT_EMPTY)
to_chat(user, "<span class='warning'>There is no [fitting] in this light.</span>")
return
// make it burn hands if not wearing fire-insulated gloves
if(on)
var/prot = 0
@@ -884,9 +918,19 @@
/obj/machinery/light/extinguish_light()
on = FALSE
emergency_mode = FALSE
no_emergency = TRUE
addtimer(CALLBACK(src, .proc/enable_emergency_lighting), 5 MINUTES, TIMER_UNIQUE|TIMER_OVERRIDE)
visible_message("<span class='danger'>[src] flickers and falls dark.</span>")
update(FALSE)
/obj/machinery/light/proc/enable_emergency_lighting()
visible_message("<span class='notice'>[src]'s emergency lighting flickers back to life.</span>")
no_emergency = FALSE
update(FALSE)
#undef MAXIMUM_SAFE_BACKUP_CHARGE
#undef EMERGENCY_LIGHT_POWER_USE
#undef LIGHT_OK
#undef LIGHT_EMPTY
#undef LIGHT_BROKEN
+65 -13
View File
@@ -35,9 +35,8 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
if(SEC_LEVEL_GREEN)
GLOB.security_announcement_down.Announce("All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced.","Attention! Security level lowered to green.", 'sound/AI/green.ogg')
GLOB.security_level = SEC_LEVEL_GREEN
unset_stationwide_emergency_lighting()
post_status("alert", "outline")
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_contact(FA.z))
FA.overlays.Cut()
@@ -51,7 +50,7 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
GLOB.security_level = SEC_LEVEL_BLUE
post_status("alert", "outline")
unset_stationwide_emergency_lighting()
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_contact(FA.z))
FA.overlays.Cut()
@@ -62,6 +61,7 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
GLOB.security_announcement_up.Announce("There is an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.","Attention! Code Red!", 'sound/AI/red.ogg')
else
GLOB.security_announcement_down.Announce("The station's self-destruct mechanism has been deactivated, but there is still an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.","Attention! Code Red!", 'sound/AI/red.ogg')
unset_stationwide_emergency_lighting()
GLOB.security_level = SEC_LEVEL_RED
var/obj/machinery/door/airlock/highsecurity/red/R = locate(/obj/machinery/door/airlock/highsecurity/red) in GLOB.airlocks
@@ -70,7 +70,6 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
R.update_icon()
post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_contact(FA.z))
FA.overlays.Cut()
@@ -95,15 +94,15 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
FA.update_icon()
if(SEC_LEVEL_EPSILON)
GLOB.security_announcement_up.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.","Attention! Epsilon security level activated!", 'sound/effects/purge_siren.ogg', new_sound2 = 'sound/AI/epsilon.ogg')
GLOB.security_level = SEC_LEVEL_EPSILON
post_status("alert", "epsilonalert")
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_contact(FA.z))
FA.overlays.Cut()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_epsilon")
for(var/mob/M in GLOB.player_list)
var/turf/T = get_turf(M)
if(!M.client || !is_station_level(T.z))
continue
SEND_SOUND(M, sound('sound/effects/powerloss.ogg'))
set_stationwide_emergency_lighting()
addtimer(CALLBACK(GLOBAL_PROC, .proc/epsilon_process), 15 SECONDS)
SSblackbox.record_feedback("tally", "security_level_changes", 1, level)
return
if(SEC_LEVEL_DELTA)
GLOB.security_announcement_up.Announce("The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.","Attention! Delta security level reached!", 'sound/effects/deltaalarm.ogg', new_sound2 = 'sound/AI/delta.ogg')
@@ -115,6 +114,9 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
if(is_station_contact(FA.z))
FA.overlays.Cut()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_delta")
set_stationwide_emergency_lighting()
SSblackbox.record_feedback("tally", "security_level_changes", 1, level)
return
SSnightshift.check_nightshift(TRUE)
SSblackbox.record_feedback("tally", "security_level_changes", 1, level)
@@ -181,3 +183,53 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
return "<font color='blueviolet'>Epsilon</font>"
if(SEC_LEVEL_DELTA)
return "<font color='orangered'>Delta</font>"
/proc/set_stationwide_emergency_lighting()
for(var/obj/machinery/power/apc/A in GLOB.apcs)
var/area/AR = get_area(A)
if(!is_station_level(A.z))
continue
A.emergency_lights = FALSE
AR.area_emergency_mode = TRUE
for(var/obj/machinery/light/L in A.area)
if(L.status)
continue
if(GLOB.security_level == SEC_LEVEL_DELTA)
L.fire_mode = TRUE
L.on = FALSE
L.emergency_mode = TRUE
INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE)
/proc/unset_stationwide_emergency_lighting()
for(var/area/A as anything in GLOB.all_areas)
if(!is_station_level(A.z))
continue
if(!A.area_emergency_mode)
continue
A.area_emergency_mode = FALSE
for(var/obj/machinery/light/L in A)
if(A.fire)
continue
if(L.status)
continue
L.fire_mode = FALSE
L.emergency_mode = FALSE
L.on = TRUE
INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE)
/proc/epsilon_process()
GLOB.security_announcement_up.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.", "Attention! Epsilon security level activated!", 'sound/effects/purge_siren.ogg')
GLOB.security_level = SEC_LEVEL_EPSILON
post_status("alert", "epsilonalert")
for(var/area/A as anything in GLOB.all_areas)
if(!is_station_level(A.z))
continue
for(var/obj/machinery/light/L in A)
if(L.status)
continue
L.fire_mode = TRUE
L.update()
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_contact(FA.z))
FA.overlays.Cut()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_epsilon")
+10
View File
@@ -188,6 +188,16 @@ const ApcContent = (props, context) => {
selected={data.nightshiftLights}
onClick={() => act('toggle_nightshift')} />
)} />
<LabeledList.Item
label="Emergency Light Fallback"
buttons={(
<Button
icon={data.coverLocked ? 'lock' : 'unlock'}
content={data.emergencyLights ? 'Engaged' : 'Disengaged'}
selected={data.emergencyLights}
disabled={locked}
onClick={() => act('emergency_lighting')} />
)} />
</LabeledList>
</Section>
</Fragment>
File diff suppressed because one or more lines are too long