diff --git a/code/__DEFINES/controllers/_subsystems.dm b/code/__DEFINES/controllers/_subsystems.dm
index 5f94b6508e5..542b47f644f 100644
--- a/code/__DEFINES/controllers/_subsystems.dm
+++ b/code/__DEFINES/controllers/_subsystems.dm
@@ -118,7 +118,8 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_PLANETS -2
#define INIT_ORDER_ASSETS -4
#define INIT_ORDER_HOLOMAPS -5
-#define INIT_ORDER_OVERLAY -6
+#define INIT_ORDER_NIGHTSHIFT -6
+#define INIT_ORDER_OVERLAY -7
#define INIT_ORDER_EVENTS -8
#define INIT_ORDER_OVERMAPS -9
#define INIT_ORDER_TICKER -10
@@ -133,6 +134,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
#define FIRE_PRIORITY_SHUTTLES 5
+#define FIRE_PRIORITY_NIGHTSHIFT 6
#define FIRE_PRIORITY_ORBIT 8
#define FIRE_PRIORITY_VOTE 9
#define FIRE_PRIORITY_AI 10
@@ -140,7 +142,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_VIS 10
#define FIRE_PRIORITY_SERVER_MAINT 10
#define FIRE_PRIORITY_GARBAGE 15
-#define FIRE_PRIORITY_CHARSETUP 25
+#define FIRE_PRIORITY_CHARSETUP 25
#define FIRE_PRIORITY_SPACEDRIFT 25
#define FIRE_PRIORITY_AIRFLOW 30
#define FIRE_PRIORITY_AIR 35
diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm
index 4a935bc60f5..05296165da3 100644
--- a/code/__DEFINES/lighting.dm
+++ b/code/__DEFINES/lighting.dm
@@ -61,6 +61,7 @@
#define LIGHT_COLOR_INCANDESCENT_TUBE "#E0EFF0"
#define LIGHT_COLOR_INCANDESCENT_BULB "#FFFEB8"
#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66"
+#define LIGHT_COLOR_NIGHTSHIFT "#EFCC86"
#define LIGHT_RANGE_FIRE 3 //How many tiles standard fires glow.
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 062a4e2ce39..1529de95005 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -18,25 +18,25 @@
return wtime + (time_offset + wusage) * world.tick_lag
-var/roundstart_hour
+GLOBAL_VAR_INIT(roundstart_hour, pick(2,7,12,17))
var/station_date = ""
var/next_station_date_change = 1 DAY
-#define duration2stationtime(time) time2text(station_time_in_ticks + time, "hh:mm")
-#define worldtime2stationtime(time) time2text(roundstart_hour HOURS + time, "hh:mm")
-#define round_duration_in_ticks (SSticker.round_start_time ? world.time - SSticker.round_start_time : 0)
-#define station_time_in_ticks (roundstart_hour HOURS + round_duration_in_ticks)
+#define duration2stationtime(time) time2text(station_time_in_ds + time, "hh:mm")
+#define worldtime2stationtime(time) time2text(GLOB.roundstart_hour HOURS + time, "hh:mm")
+#define round_duration_in_ds (SSticker.round_start_time ? world.time - SSticker.round_start_time : 0)
+#define station_time_in_ds (GLOB.roundstart_hour HOURS + round_duration_in_ds)
/proc/stationtime2text()
- return time2text(station_time_in_ticks, "hh:mm")
+ return time2text(station_time_in_ds + GLOB.timezoneOffset, "hh:mm")
/proc/stationdate2text()
var/update_time = FALSE
- if(station_time_in_ticks > next_station_date_change)
+ if(station_time_in_ds > next_station_date_change)
next_station_date_change += 1 DAY
update_time = TRUE
if(!station_date || update_time)
- var/extra_days = round(station_time_in_ticks / (1 DAY)) DAYS
+ var/extra_days = round(station_time_in_ds / (1 DAY)) DAYS
var/timeofday = world.timeofday + extra_days
station_date = num2text((text2num(time2text(timeofday, "YYYY"))+544)) + "-" + time2text(timeofday, "MM-DD")
return station_date
@@ -47,11 +47,28 @@ var/next_station_date_change = 1 DAY
var/time_portion = time2text(world.timeofday, "hh:mm:ss")
return "[date_portion]T[time_portion]"
+/proc/get_timezone_offset()
+ var/midnight_gmt_here = text2num(time2text(0,"hh")) * 36000
+ if(midnight_gmt_here > 12 HOURS)
+ return 24 HOURS - midnight_gmt_here
+ else
+ return midnight_gmt_here
+
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
if(!wtime)
wtime = world.time
return time2text(wtime - GLOB.timezoneOffset, format)
+/* This is used for displaying the "station time" equivelent of a world.time value
+ Calling it with no args will give you the current time, but you can specify a world.time-based value as an argument
+ - You can use this, for example, to do "This will expire at [station_time_at(world.time + 500)]" to display a "station time" expiration date
+ which is much more useful for a player)*/
+/proc/station_time(time=world.time, display_only=FALSE)
+ return ((((time - SSticker.round_start_time)) + GLOB.gametime_offset) % 864000) - (display_only ? GLOB.timezoneOffset : 0)
+
+/proc/station_time_timestamp(format = "hh:mm:ss", time=world.time)
+ return time2text(station_time(time, TRUE), format)
+
/* Returns 1 if it is the selected month and day */
proc/isDay(var/month, var/day)
if(isnum(month) && isnum(day))
@@ -73,7 +90,7 @@ var/last_round_duration = 0
if(last_round_duration && world.time < next_duration_update)
return last_round_duration
- var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever
+ var/mills = round_duration_in_ds // 1/10 of a second, not real milliseconds but whatever
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
@@ -85,10 +102,6 @@ var/last_round_duration = 0
next_duration_update = world.time + 1 MINUTES
return last_round_duration
-/hook/startup/proc/set_roundstart_hour()
- roundstart_hour = pick(2,7,12,17)
- return 1
-
/var/midnight_rollovers = 0
/var/rollovercheck_last_timeofday = 0
/proc/update_midnight_rollover()
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index cff2ff865bc..9b1b658f69f 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -1,5 +1,7 @@
GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the host computer) and 0 world.ticks.
+GLOBAL_VAR_INIT(gametime_offset, 432000) // 12:00 in seconds
+
GLOBAL_VAR_INIT(TAB, " ")
GLOBAL_VAR_INIT(Debug2, FALSE)
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 3ef6ac6d2f9..a2ea4e9afd2 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -8,3 +8,6 @@
/datum/config_entry/flag/allow_holidays
config_entry_value = TRUE
+
+/datum/config_entry/flag/nightshifts_enabled
+ config_entry_value = TRUE
diff --git a/code/controllers/configuration_old/configuration.dm b/code/controllers/configuration_old/configuration.dm
index c6d15d99178..06c67c7d9c6 100644
--- a/code/controllers/configuration_old/configuration.dm
+++ b/code/controllers/configuration_old/configuration.dm
@@ -268,6 +268,7 @@
var/list/gamemode_cache = list()
+
/datum/configuration_legacy/New()
var/list/L = subtypesof(/datum/game_mode)
for (var/T in L)
diff --git a/code/controllers/subsystems/game_master.dm b/code/controllers/subsystems/game_master.dm
index 02b2d721827..a33f48511f5 100644
--- a/code/controllers/subsystems/game_master.dm
+++ b/code/controllers/subsystems/game_master.dm
@@ -58,7 +58,7 @@ SUBSYSTEM_DEF(gamemaster)
if(ignore_time_restrictions)
return TRUE
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
- var/mills = round_duration_in_ticks
+ var/mills = round_duration_in_ds
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
@@ -153,5 +153,3 @@ SUBSYSTEM_DEF(gamemaster)
return best_actions
else
log_debug("Game Master failed to find a suitable event, something very wrong is going on.")
-
-
diff --git a/code/controllers/subsystems/nightshift.dm b/code/controllers/subsystems/nightshift.dm
new file mode 100644
index 00000000000..ba06a984d93
--- /dev/null
+++ b/code/controllers/subsystems/nightshift.dm
@@ -0,0 +1,63 @@
+SUBSYSTEM_DEF(nightshift)
+ name = "Night Shift"
+ init_order = INIT_ORDER_NIGHTSHIFT
+ priority = FIRE_PRIORITY_NIGHTSHIFT
+ wait = 60 SECONDS
+ flags = SS_NO_TICK_CHECK
+
+ var/nightshift_active = FALSE
+ var/nightshift_start_time = 702000 //7:30 PM, station time
+ var/nightshift_end_time = 270000 //7:30 AM, station time
+ var/nightshift_first_check = 30 SECONDS
+
+ var/high_security_mode = FALSE
+
+/datum/controller/subsystem/nightshift/Initialize()
+ if (!CONFIG_GET(flag/nightshifts_enabled))
+ can_fire = FALSE
+ //if(CONFIG_GET(flag/randomized_start_time_enabled))
+ //GLOB.gametime_offset = rand(0, 23) HOURS
+ return ..()
+
+/datum/controller/subsystem/nightshift/fire(resumed = FALSE)
+ if(world.time - SSticker.round_start_time < nightshift_first_check)
+ return
+ check_nightshift()
+
+/datum/controller/subsystem/nightshift/proc/announce(message)
+ var/announce_z
+ if(GLOB.using_map.station_levels.len)
+ announce_z = pick(GLOB.using_map.station_levels)
+ priority_announcement.Announce(message, new_title = "Automated Lighting System Announcement", new_sound = 'sound/misc/notice2.ogg', zlevel = announce_z)
+
+/datum/controller/subsystem/nightshift/proc/check_nightshift(check_canfire=FALSE) //This is called from elsewhere, like setting the alert levels
+ if(check_canfire && !can_fire)
+ return
+ var/emergency = security_level > SEC_LEVEL_GREEN
+ var/announcing = TRUE
+ var/time = station_time()
+ var/night_time = (time < nightshift_end_time) || (time > nightshift_start_time)
+ if(high_security_mode != emergency)
+ high_security_mode = emergency
+ if(night_time)
+ announcing = FALSE
+ if(!emergency)
+ announce("Restoring night lighting configuration to normal operation.")
+ else
+ announce("Disabling night lighting: Station is in a state of emergency.")
+ if(emergency)
+ night_time = FALSE
+ if(nightshift_active != night_time)
+ update_nightshift(night_time, announcing)
+
+/datum/controller/subsystem/nightshift/proc/update_nightshift(active, announce = TRUE)
+ nightshift_active = active
+ if(announce)
+ if(active)
+ announce("Good evening, crew. To reduce power consumption and stimulate the circadian rhythms of some species, all of the lights aboard the station have been dimmed for the night.")
+ else
+ announce("Good morning, crew. As it is now day time, all of the lights aboard the station have been restored to their former brightness.")
+ for(var/obj/machinery/power/apc/apc in GLOB.apcs)
+ if(apc.z in GLOB.using_map.station_levels)
+ apc.set_nightshift(active, TRUE)
+ CHECK_TICK
diff --git a/code/controllers/subsystems/planets.dm b/code/controllers/subsystems/planets.dm
index 33a27494556..70dd00954e7 100644
--- a/code/controllers/subsystems/planets.dm
+++ b/code/controllers/subsystems/planets.dm
@@ -6,16 +6,16 @@ SUBSYSTEM_DEF(planets)
flags = SS_BACKGROUND
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
- var/list/new_outdoor_turfs = list()
- var/list/new_outdoor_walls = list()
+ var/static/list/new_outdoor_turfs = list()
+ var/static/list/new_outdoor_walls = list()
- var/list/planets = list()
- var/list/z_to_planet = list()
+ var/static/list/planets = list()
+ var/static/list/z_to_planet = list()
- var/list/currentrun = list()
+ var/static/list/currentrun = list()
- var/list/needs_sun_update = list()
- var/list/needs_temp_update = list()
+ var/static/list/needs_sun_update = list()
+ var/static/list/needs_temp_update = list()
/datum/controller/subsystem/planets/Initialize(timeofday)
admin_notice("Initializing planetary weather.", R_DEBUG)
diff --git a/code/controllers/subsystems/transfer.dm b/code/controllers/subsystems/transfer.dm
index f22d38c61ea..11861331eee 100644
--- a/code/controllers/subsystems/transfer.dm
+++ b/code/controllers/subsystems/transfer.dm
@@ -18,15 +18,15 @@ SUBSYSTEM_DEF(transfer)
/datum/controller/subsystem/transfer/fire(resumed)
currenttick = currenttick + 1
//VOREStation Edit START
-/* if (round_duration_in_ticks >= shift_last_vote - 2 MINUTES)
+/* if (round_duration_in_ds >= shift_last_vote - 2 MINUTES)
shift_last_vote = 999999999999 //Setting to a stupidly high number since it'll be not used again.
to_world("Warning: This upcoming round-extend vote will be your ONLY extend vote. Wrap up your scenes in the next 60 minutes if the round is extended.") //VOREStation Edit
*/
- if (round_duration_in_ticks >= shift_hard_end - 1 MINUTE)
+ if (round_duration_in_ds >= shift_hard_end - 1 MINUTE)
init_shift_change(null, 1)
shift_hard_end = timerbuffer + config_legacy.vote_autotransfer_interval //If shuttle somehow gets recalled, let's force it to call again next time a vote would occur.
timerbuffer = timerbuffer + config_legacy.vote_autotransfer_interval //Just to make sure a vote doesn't occur immediately afterwords.
- else if (round_duration_in_ticks >= timerbuffer - 1 MINUTE)
+ else if (round_duration_in_ds >= timerbuffer - 1 MINUTE)
SSvote.autotransfer()
//VOREStation Edit END
timerbuffer = timerbuffer + config_legacy.vote_autotransfer_interval
diff --git a/code/game/gamemodes/cult/hell_universe.dm b/code/game/gamemodes/cult/hell_universe.dm
index dcdcd1a4a58..0f62f649777 100644
--- a/code/game/gamemodes/cult/hell_universe.dm
+++ b/code/game/gamemodes/cult/hell_universe.dm
@@ -78,7 +78,7 @@ In short:
alm.ex_act(2)
/datum/universal_state/hell/proc/APCSet()
- for (var/obj/machinery/power/apc/APC in machines)
+ for (var/obj/machinery/power/apc/APC in GLOB.apcs)
if (!(APC.stat & BROKEN) && !APC.is_critical)
APC.emagged = 1
APC.queue_icon_update()
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 58a3812ef35..307e5cf5b20 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -283,8 +283,8 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","