mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
528 lines
16 KiB
Plaintext
528 lines
16 KiB
Plaintext
// Areas.dm
|
|
|
|
/area
|
|
var/fire = null
|
|
var/atmos = 1
|
|
var/atmosalm = 0
|
|
var/poweralm = 1
|
|
var/party = null
|
|
level = null
|
|
name = "Unknown"
|
|
icon = 'icons/turf/areas.dmi'
|
|
icon_state = "unknown"
|
|
plane = PLANE_LIGHTING_ABOVE //In case we color them
|
|
luminosity = 0
|
|
mouse_opacity = 0
|
|
var/lightswitch = 1
|
|
|
|
var/eject = null
|
|
|
|
var/debug = 0
|
|
var/requires_power = 1
|
|
var/always_unpowered = 0 //this gets overriden to 1 for space in area/New()
|
|
|
|
// Power channel status - Is it currently energized?
|
|
var/power_equip = TRUE
|
|
var/power_light = TRUE
|
|
var/power_environ = TRUE
|
|
|
|
// Oneoff power usage - Used once and cleared each power cycle
|
|
var/oneoff_equip = 0
|
|
var/oneoff_light = 0
|
|
var/oneoff_environ = 0
|
|
|
|
// Continuous "static" power usage - Do not update these directly!
|
|
var/static_equip = 0
|
|
var/static_light = 0
|
|
var/static_environ = 0
|
|
|
|
var/music = null
|
|
var/has_gravity = 1
|
|
var/secret_name = FALSE // This tells certain things that display areas' names that they shouldn't display this area's name.
|
|
var/obj/machinery/power/apc/apc = null
|
|
var/no_air = null
|
|
// var/list/lights // list of all lights on this area
|
|
var/list/all_doors = null //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area
|
|
var/firedoors_closed = 0
|
|
var/list/ambience = list()
|
|
var/list/forced_ambience = null
|
|
var/sound_env = STANDARD_STATION
|
|
var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf
|
|
var/forbid_events = FALSE // If true, random events will not start inside this area.
|
|
var/no_spoilers = FALSE // If true, makes it much more difficult to see what is inside an area with things like mesons.
|
|
|
|
/area/Initialize()
|
|
. = ..()
|
|
|
|
luminosity = !(dynamic_lighting)
|
|
icon_state = ""
|
|
|
|
return INITIALIZE_HINT_LATELOAD // Areas tradiationally are initialized AFTER other atoms.
|
|
|
|
/area/LateInitialize()
|
|
if(!requires_power || !apc)
|
|
power_light = 0
|
|
power_equip = 0
|
|
power_environ = 0
|
|
power_change() // all machines set to current power level, also updates lighting icon
|
|
if(no_spoilers)
|
|
set_spoiler_obfuscation(TRUE)
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
// Changes the area of T to A. Do not do this manually.
|
|
// Area is expected to be a non-null instance.
|
|
/proc/ChangeArea(var/turf/T, var/area/A)
|
|
if(!istype(A))
|
|
CRASH("Area change attempt failed: invalid area supplied.")
|
|
var/area/old_area = get_area(T)
|
|
if(old_area == A)
|
|
return
|
|
// NOTE: BayStation calles area.Exited/Entered for the TURF T. So far we don't do that.s
|
|
// NOTE: There probably won't be any atoms in these turfs, but just in case we should call these procs.
|
|
A.contents.Add(T)
|
|
if(old_area)
|
|
// Handle dynamic lighting update if
|
|
if(T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting)
|
|
if(A.dynamic_lighting)
|
|
T.lighting_build_overlay()
|
|
else
|
|
T.lighting_clear_overlay()
|
|
for(var/atom/movable/AM in T)
|
|
old_area.Exited(AM, A)
|
|
for(var/atom/movable/AM in T)
|
|
A.Entered(AM, old_area)
|
|
for(var/obj/machinery/M in T)
|
|
M.area_changed(old_area, A)
|
|
|
|
/area/proc/get_contents()
|
|
return contents
|
|
|
|
/area/proc/get_cameras()
|
|
var/list/cameras = list()
|
|
for (var/obj/machinery/camera/C in src)
|
|
cameras += C
|
|
return cameras
|
|
|
|
/area/proc/atmosalert(danger_level, var/alarm_source)
|
|
if (danger_level == 0)
|
|
atmosphere_alarm.clearAlarm(src, alarm_source)
|
|
else
|
|
var/obj/machinery/alarm/atmosalarm = alarm_source //maybe other things can trigger these, who knows
|
|
if(istype(atmosalarm))
|
|
atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level, hidden = atmosalarm.alarms_hidden)
|
|
else
|
|
atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level)
|
|
|
|
//Check all the alarms before lowering atmosalm. Raising is perfectly fine.
|
|
for (var/obj/machinery/alarm/AA in src)
|
|
if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted && AA.report_danger_level)
|
|
danger_level = max(danger_level, AA.danger_level)
|
|
|
|
if(danger_level != atmosalm)
|
|
atmosalm = danger_level
|
|
//closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
|
|
if (danger_level < 1 || danger_level >= 2)
|
|
firedoors_update()
|
|
|
|
for (var/obj/machinery/alarm/AA in src)
|
|
AA.update_icon()
|
|
|
|
return 1
|
|
return 0
|
|
|
|
// Either close or open firedoors depending on current alert statuses
|
|
/area/proc/firedoors_update()
|
|
if(fire || party || atmosalm)
|
|
firedoors_close()
|
|
// VOREStation Edit - Make the lights colored!
|
|
if(fire)
|
|
for(var/obj/machinery/light/L in src)
|
|
L.set_alert_fire()
|
|
else if(atmosalm)
|
|
for(var/obj/machinery/light/L in src)
|
|
L.set_alert_atmos()
|
|
// VOREStation Edit End
|
|
else
|
|
firedoors_open()
|
|
// VOREStation Edit - Put the lights back!
|
|
for(var/obj/machinery/light/L in src)
|
|
L.reset_alert()
|
|
// VOREStation Edit End
|
|
|
|
// Close all firedoors in the area
|
|
/area/proc/firedoors_close()
|
|
if(!firedoors_closed)
|
|
firedoors_closed = TRUE
|
|
if(!all_doors)
|
|
return
|
|
for(var/obj/machinery/door/firedoor/E in all_doors)
|
|
if(!E.blocked)
|
|
if(E.operating)
|
|
E.nextstate = FIREDOOR_CLOSED
|
|
else if(!E.density)
|
|
spawn(0)
|
|
E.close()
|
|
|
|
// Open all firedoors in the area
|
|
/area/proc/firedoors_open()
|
|
if(firedoors_closed)
|
|
firedoors_closed = FALSE
|
|
if(!all_doors)
|
|
return
|
|
for(var/obj/machinery/door/firedoor/E in all_doors)
|
|
if(!E.blocked)
|
|
if(E.operating)
|
|
E.nextstate = FIREDOOR_OPEN
|
|
else if(E.density)
|
|
spawn(0)
|
|
E.open()
|
|
|
|
|
|
/area/proc/fire_alert()
|
|
if(!fire)
|
|
fire = 1 //used for firedoor checks
|
|
updateicon()
|
|
firedoors_update()
|
|
|
|
/area/proc/fire_reset()
|
|
if (fire)
|
|
fire = 0 //used for firedoor checks
|
|
updateicon()
|
|
firedoors_update()
|
|
|
|
/area/proc/readyalert()
|
|
if(!eject)
|
|
eject = 1
|
|
updateicon()
|
|
return
|
|
|
|
/area/proc/readyreset()
|
|
if(eject)
|
|
eject = 0
|
|
updateicon()
|
|
return
|
|
|
|
/area/proc/partyalert()
|
|
if (!( party ))
|
|
party = 1
|
|
updateicon()
|
|
firedoors_update()
|
|
return
|
|
|
|
/area/proc/partyreset()
|
|
if (party)
|
|
party = 0
|
|
updateicon()
|
|
firedoors_update()
|
|
return
|
|
|
|
/area/proc/updateicon()
|
|
if ((fire || eject || party) && (!requires_power||power_environ) && !istype(src, /area/space))//If it doesn't require power, can still activate this proc.
|
|
if(fire && !eject && !party)
|
|
icon_state = null // Let lights take care of it
|
|
/*else if(atmosalm && !fire && !eject && !party)
|
|
icon_state = "bluenew"*/
|
|
else if(!fire && eject && !party)
|
|
icon_state = "red"
|
|
else if(party && !fire && !eject)
|
|
icon_state = "party"
|
|
else
|
|
icon_state = "blue-red"
|
|
else
|
|
// new lighting behaviour with obj lights
|
|
icon_state = null
|
|
|
|
|
|
/*
|
|
#define EQUIP 1
|
|
#define LIGHT 2
|
|
#define ENVIRON 3
|
|
*/
|
|
|
|
/area/proc/powered(var/chan) // return true if the area has power to given channel
|
|
|
|
if(!requires_power)
|
|
return 1
|
|
if(always_unpowered)
|
|
return 0
|
|
switch(chan)
|
|
if(EQUIP)
|
|
return power_equip
|
|
if(LIGHT)
|
|
return power_light
|
|
if(ENVIRON)
|
|
return power_environ
|
|
|
|
return 0
|
|
|
|
// called when power status changes
|
|
/area/proc/power_change()
|
|
for(var/obj/machinery/M in src) // for each machine in the area
|
|
M.power_change() // reverify power status (to update icons etc.)
|
|
if (fire || eject || party)
|
|
updateicon()
|
|
|
|
/area/proc/usage(var/chan, var/include_static = TRUE)
|
|
var/used = 0
|
|
switch(chan)
|
|
if(LIGHT)
|
|
used += oneoff_light + (include_static * static_light)
|
|
if(EQUIP)
|
|
used += oneoff_equip + (include_static * static_equip)
|
|
if(ENVIRON)
|
|
used += oneoff_environ + (include_static * static_environ)
|
|
if(TOTAL)
|
|
used += oneoff_light + (include_static * static_light)
|
|
used += oneoff_equip + (include_static * static_equip)
|
|
used += oneoff_environ + (include_static * static_environ)
|
|
return used
|
|
|
|
// Helper for APCs; will generally be called every tick.
|
|
/area/proc/clear_usage()
|
|
oneoff_equip = 0
|
|
oneoff_light = 0
|
|
oneoff_environ = 0
|
|
|
|
// Use this for a one-time power draw from the area, typically for non-machines.
|
|
/area/proc/use_power_oneoff(var/amount, var/chan)
|
|
switch(chan)
|
|
if(EQUIP)
|
|
oneoff_equip += amount
|
|
if(LIGHT)
|
|
oneoff_light += amount
|
|
if(ENVIRON)
|
|
oneoff_environ += amount
|
|
return amount
|
|
|
|
// This is used by machines to properly update the area of power changes.
|
|
/area/proc/power_use_change(old_amount, new_amount, chan)
|
|
use_power_static(new_amount - old_amount, chan) // Simultaneously subtract old_amount and add new_amount.
|
|
|
|
// Not a proc you want to use directly unless you know what you are doing; see use_power_oneoff above instead.
|
|
/area/proc/use_power_static(var/amount, var/chan)
|
|
switch(chan)
|
|
if(EQUIP)
|
|
static_equip += amount
|
|
if(LIGHT)
|
|
static_light += amount
|
|
if(ENVIRON)
|
|
static_environ += amount
|
|
|
|
// This recomputes the continued power usage; can be used for testing or error recovery, but is not called every tick.
|
|
/area/proc/retally_power()
|
|
static_equip = 0
|
|
static_light = 0
|
|
static_environ = 0
|
|
for(var/obj/machinery/M in src)
|
|
switch(M.power_channel)
|
|
if(EQUIP)
|
|
static_equip += M.get_power_usage()
|
|
if(LIGHT)
|
|
static_light += M.get_power_usage()
|
|
if(ENVIRON)
|
|
static_environ += M.get_power_usage()
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
/area/vv_get_dropdown()
|
|
. = ..()
|
|
VV_DROPDOWN_OPTION("check_static_power", "Check Static Power")
|
|
|
|
/area/vv_do_topic(list/href_list)
|
|
. = ..()
|
|
IF_VV_OPTION("check_static_power")
|
|
if(!check_rights(R_DEBUG))
|
|
return
|
|
src.check_static_power(usr)
|
|
href_list["datumrefresh"] = "\ref[src]"
|
|
|
|
// Debugging proc to report if static power is correct or not.
|
|
/area/proc/check_static_power(var/user)
|
|
set name = "Check Static Power"
|
|
var/actual_static_equip = static_equip
|
|
var/actual_static_light = static_light
|
|
var/actual_static_environ = static_environ
|
|
retally_power()
|
|
if(user)
|
|
var/list/report = list("[src] ([type]) static power tally:")
|
|
report += "EQUIP: Actual: [actual_static_equip] Correct: [static_equip] Difference: [actual_static_equip - static_equip]"
|
|
report += "LIGHT: Actual: [actual_static_light] Correct: [static_light] Difference: [actual_static_light - static_light]"
|
|
report += "ENVIRON: Actual: [actual_static_environ] Correct: [static_environ] Difference: [actual_static_environ - static_environ]"
|
|
to_chat(user, report.Join("\n"))
|
|
return (actual_static_equip == static_equip && actual_static_light == static_light && actual_static_environ == static_environ)
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
var/list/mob/living/forced_ambiance_list = new
|
|
|
|
/area/Entered(A)
|
|
if(!istype(A,/mob/living)) return
|
|
|
|
var/mob/living/L = A
|
|
if(!L.ckey) return
|
|
|
|
if(!L.lastarea)
|
|
L.lastarea = get_area(L.loc)
|
|
var/area/newarea = get_area(L.loc)
|
|
var/area/oldarea = L.lastarea
|
|
if((oldarea.has_gravity == 0) && (newarea.has_gravity == 1) && (L.m_intent == "run")) // Being ready when you change areas gives you a chance to avoid falling all together.
|
|
thunk(L)
|
|
L.update_floating( L.Check_Dense_Object() )
|
|
|
|
L.lastarea = newarea
|
|
L.lastareachange = world.time
|
|
play_ambience(L, initial = TRUE)
|
|
if(no_spoilers)
|
|
L.disable_spoiler_vision()
|
|
|
|
/area/proc/play_ambience(var/mob/living/L, initial = TRUE)
|
|
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
|
|
if(!(L && L.is_preference_enabled(/datum/client_preference/play_ambiance)))
|
|
return
|
|
|
|
var/volume_mod = L.get_preference_volume_channel(VOLUME_CHANNEL_AMBIENCE)
|
|
|
|
// If we previously were in an area with force-played ambiance, stop it.
|
|
if((L in forced_ambiance_list) && initial)
|
|
L << sound(null, channel = CHANNEL_AMBIENCE_FORCED)
|
|
forced_ambiance_list -= L
|
|
|
|
if(forced_ambience)
|
|
if(L in forced_ambiance_list)
|
|
return
|
|
if(forced_ambience.len)
|
|
forced_ambiance_list |= L
|
|
var/sound/chosen_ambiance = pick(forced_ambience)
|
|
if(!istype(chosen_ambiance))
|
|
chosen_ambiance = sound(chosen_ambiance, repeat = 1, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE_FORCED)
|
|
chosen_ambiance.volume *= volume_mod
|
|
L << chosen_ambiance
|
|
else
|
|
L << sound(null, channel = CHANNEL_AMBIENCE_FORCED)
|
|
else if(src.ambience.len)
|
|
var/ambience_odds = L?.client.prefs.ambience_chance
|
|
if(prob(ambience_odds) && (world.time >= L.client.time_last_ambience_played + 1 MINUTE))
|
|
var/sound = pick(ambience)
|
|
L << sound(sound, repeat = 0, wait = 0, volume = 50 * volume_mod, channel = CHANNEL_AMBIENCE)
|
|
L.client.time_last_ambience_played = world.time
|
|
|
|
/area/proc/gravitychange(var/gravitystate = 0)
|
|
src.has_gravity = gravitystate
|
|
|
|
for(var/mob/M in src)
|
|
if(has_gravity)
|
|
thunk(M)
|
|
M.update_floating( M.Check_Dense_Object() )
|
|
M.update_gravity(has_gravity)
|
|
|
|
/area/proc/thunk(mob)
|
|
if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing.
|
|
return
|
|
|
|
if(istype(mob,/mob/living/carbon/human/))
|
|
var/mob/living/carbon/human/H = mob
|
|
if(H.buckled)
|
|
return // Being buckled to something solid keeps you in place.
|
|
if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.item_flags & NOSLIP))
|
|
return
|
|
|
|
if(H.m_intent == "run")
|
|
H.AdjustStunned(6)
|
|
H.AdjustWeakened(6)
|
|
else
|
|
H.AdjustStunned(3)
|
|
H.AdjustWeakened(3)
|
|
to_chat(mob, "<span class='notice'>The sudden appearance of gravity makes you fall to the floor!</span>")
|
|
playsound(mob, "bodyfall", 50, 1)
|
|
|
|
/area/proc/prison_break(break_lights = TRUE, open_doors = TRUE, open_blast_doors = TRUE)
|
|
var/obj/machinery/power/apc/theAPC = get_apc()
|
|
if(theAPC.operating)
|
|
if(break_lights)
|
|
for(var/obj/machinery/power/apc/temp_apc in src)
|
|
temp_apc.overload_lighting(70)
|
|
if(open_doors)
|
|
for(var/obj/machinery/door/airlock/temp_airlock in src)
|
|
temp_airlock.prison_open()
|
|
for(var/obj/machinery/door/window/temp_windoor in src)
|
|
temp_windoor.open()
|
|
if(open_blast_doors)
|
|
for(var/obj/machinery/door/blast/temp_blast in src)
|
|
temp_blast.open()
|
|
|
|
/area/has_gravity()
|
|
return has_gravity
|
|
|
|
/area/space/has_gravity()
|
|
return 0
|
|
|
|
/proc/has_gravity(atom/AT, turf/T)
|
|
if(!T)
|
|
T = get_turf(AT)
|
|
var/area/A = get_area(T)
|
|
if(A && A.has_gravity())
|
|
return 1
|
|
return 0
|
|
|
|
/area/proc/shuttle_arrived()
|
|
return TRUE
|
|
|
|
/area/proc/shuttle_departed()
|
|
return TRUE
|
|
|
|
/area/AllowDrop()
|
|
CRASH("Bad op: area/AllowDrop() called")
|
|
|
|
/area/drop_location()
|
|
CRASH("Bad op: area/drop_location() called")
|
|
|
|
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
|
|
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
|
|
var/list/teleportlocs = list()
|
|
|
|
/hook/startup/proc/setupTeleportLocs()
|
|
for(var/area/AR in world)
|
|
if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue
|
|
if(teleportlocs.Find(AR.name)) continue
|
|
var/turf/picked = pick(get_area_turfs(AR.type))
|
|
if (picked.z in using_map.station_levels)
|
|
teleportlocs += AR.name
|
|
teleportlocs[AR.name] = AR
|
|
|
|
teleportlocs = sortAssoc(teleportlocs)
|
|
|
|
return 1
|
|
|
|
var/list/ghostteleportlocs = list()
|
|
|
|
/hook/startup/proc/setupGhostTeleportLocs()
|
|
for(var/area/AR in world)
|
|
if(ghostteleportlocs.Find(AR.name)) continue
|
|
if(istype(AR, /area/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom))
|
|
ghostteleportlocs += AR.name
|
|
ghostteleportlocs[AR.name] = AR
|
|
var/turf/picked = pick(get_area_turfs(AR.type))
|
|
if (picked.z in using_map.player_levels)
|
|
ghostteleportlocs += AR.name
|
|
ghostteleportlocs[AR.name] = AR
|
|
|
|
ghostteleportlocs = sortAssoc(ghostteleportlocs)
|
|
|
|
return 1
|
|
|
|
/area/proc/get_name()
|
|
if(secret_name)
|
|
return "Unknown Area"
|
|
return name
|
|
|
|
GLOBAL_DATUM(spoiler_obfuscation_image, /image)
|
|
|
|
/area/proc/set_spoiler_obfuscation(should_obfuscate)
|
|
if(!GLOB.spoiler_obfuscation_image)
|
|
GLOB.spoiler_obfuscation_image = image(icon = 'icons/misc/static.dmi')
|
|
GLOB.spoiler_obfuscation_image.plane = PLANE_MESONS
|
|
|
|
if(should_obfuscate)
|
|
add_overlay(GLOB.spoiler_obfuscation_image)
|
|
else
|
|
cut_overlay(GLOB.spoiler_obfuscation_image) |