mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
[MIRROR] Unit Test rework & Master/Ticker update (#11372)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: C.L. <killer65311@gmail.com>
This commit is contained in:
@@ -79,7 +79,7 @@ ADMIN_VERB(debug_controller, R_DEBUG, "Debug Controller", "Debug the various per
|
||||
//Goon PS stuff, and other yet-to-be-subsystem things.
|
||||
options["LEGACY: master_controller"] = master_controller
|
||||
options["LEGACY: job_master"] = job_master
|
||||
options["LEGACY: radio_controller"] = radio_controller
|
||||
options["LEGACY: SSradio"] = SSradio
|
||||
options["LEGACY: emergency_shuttle"] = emergency_shuttle
|
||||
options["LEGACY: paiController"] = paiController
|
||||
options["LEGACY: cameranet"] = cameranet
|
||||
|
||||
@@ -1,400 +0,0 @@
|
||||
/*
|
||||
HOW IT WORKS
|
||||
|
||||
The radio_controller is a global object maintaining all radio transmissions, think about it as about "ether".
|
||||
Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way.
|
||||
procs:
|
||||
|
||||
add_object(obj/device as obj, var/new_frequency as num, var/radio_filter as text|null = null)
|
||||
Adds listening object.
|
||||
parameters:
|
||||
device - device receiving signals, must have proc receive_signal (see description below).
|
||||
one device may listen several frequencies, but not same frequency twice.
|
||||
new_frequency - see possibly frequencies below;
|
||||
radio_filter - thing for optimization. Optional, but recommended.
|
||||
All filters should be consolidated in this file, see defines later.
|
||||
Device without listening filter will receive all signals (on specified frequency).
|
||||
Device with filter will receive any signals sent without filter.
|
||||
Device with filter will not receive any signals sent with different filter.
|
||||
returns:
|
||||
Reference to frequency object.
|
||||
|
||||
remove_object (obj/device, old_frequency)
|
||||
Obliviously, after calling this proc, device will not receive any signals on old_frequency.
|
||||
Other frequencies will left unaffected.
|
||||
|
||||
return_frequency(var/frequency as num)
|
||||
returns:
|
||||
Reference to frequency object. Use it if you need to send and do not need to listen.
|
||||
|
||||
radio_frequency is a global object maintaining list of devices that listening specific frequency.
|
||||
procs:
|
||||
|
||||
post_signal(obj/source as obj|null, datum/signal/signal, var/radio_filter as text|null = null, var/range as num|null = null)
|
||||
Sends signal to all devices that wants such signal.
|
||||
parameters:
|
||||
source - object, emitted signal. Usually, devices will not receive their own signals.
|
||||
signal - see description below.
|
||||
radio_filter - described above.
|
||||
range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels.
|
||||
|
||||
obj/proc/receive_signal(datum/signal/signal, var/receive_method as num, var/receive_param)
|
||||
Handler from received signals. By default does nothing. Define your own for your object.
|
||||
Avoid of sending signals directly from this proc, use spawn(-1). DO NOT use sleep() here or call procs that sleep please. If you must, use spawn()
|
||||
parameters:
|
||||
signal - see description below. Extract all needed data from the signal before doing sleep(), spawn() or return!
|
||||
receive_method - may be TRANSMISSION_WIRE or TRANSMISSION_RADIO.
|
||||
TRANSMISSION_WIRE is currently unused.
|
||||
receive_param - for TRANSMISSION_RADIO here comes frequency.
|
||||
|
||||
datum/signal
|
||||
vars:
|
||||
source
|
||||
an object that emitted signal. Used for debug and bearing.
|
||||
data
|
||||
list with transmitting data. Usual use pattern:
|
||||
data["msg"] = "hello world"
|
||||
encryption
|
||||
Some number symbolizing "encryption key".
|
||||
Note that game actually do not use any cryptography here.
|
||||
If receiving object don't know right key, it must ignore encrypted signal in its receive_signal.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Frequency range: 1200 to 1600
|
||||
Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking)
|
||||
|
||||
Radio:
|
||||
1459 - standard radio chat
|
||||
1351 - Science
|
||||
1353 - Command
|
||||
1355 - Medical
|
||||
1357 - Engineering
|
||||
1359 - Security
|
||||
1341 - deathsquad
|
||||
1443 - Confession Intercom
|
||||
1347 - Cargo techs
|
||||
1349 - Service people
|
||||
|
||||
Devices:
|
||||
1451 - tracking implant
|
||||
1457 - RSD default
|
||||
|
||||
On the map:
|
||||
1311 for prison shuttle console (in fact, it is not used)
|
||||
1433 for engine components
|
||||
1435 for status displays
|
||||
1437 for atmospherics/fire alerts
|
||||
1439 for air pumps, air scrubbers, atmo control
|
||||
1441 for atmospherics - supply tanks
|
||||
1443 for atmospherics - distribution loop/mixed air tank
|
||||
1445 for bot nav beacons
|
||||
1447 for mulebot, secbot and ed209 control
|
||||
1449 for airlock controls, electropack, magnets
|
||||
1451 for toxin lab access
|
||||
1453 for engineering access
|
||||
1455 for AI access
|
||||
*/
|
||||
|
||||
var/const/RADIO_LOW_FREQ = 1200
|
||||
var/const/PUBLIC_LOW_FREQ = 1441
|
||||
var/const/PUBLIC_HIGH_FREQ = 1489
|
||||
var/const/RADIO_HIGH_FREQ = 1600
|
||||
|
||||
var/const/BOT_FREQ = 1447
|
||||
var/const/COMM_FREQ = 1353
|
||||
var/const/ERT_FREQ = 1345
|
||||
var/const/AI_FREQ = 1343
|
||||
var/const/DTH_FREQ = 1341
|
||||
var/const/SYND_FREQ = 1213
|
||||
var/const/RAID_FREQ = 1277
|
||||
var/const/ENT_FREQ = 1461 //entertainment frequency. This is not a diona exclusive frequency.
|
||||
var/const/BDCM_FREQ = 1481 // CHOMPEdit
|
||||
|
||||
// department channels
|
||||
var/const/PUB_FREQ = 1459
|
||||
var/const/SEC_FREQ = 1359
|
||||
var/const/ENG_FREQ = 1357
|
||||
var/const/MED_FREQ = 1355
|
||||
var/const/SCI_FREQ = 1351
|
||||
var/const/SRV_FREQ = 1349
|
||||
var/const/SUP_FREQ = 1347
|
||||
var/const/EXP_FREQ = 1361
|
||||
|
||||
// internal department channels
|
||||
var/const/MED_I_FREQ = 1485
|
||||
var/const/SEC_I_FREQ = 1475
|
||||
|
||||
var/const/TALON_FREQ = 1363 //VOREStation Add
|
||||
var/const/CSN_FREQ = 1365 //VOREStation Add
|
||||
var/const/OUT_FREQ = 1367 //CHOMPstation Add
|
||||
|
||||
var/list/radiochannels = list(
|
||||
CHANNEL_COMMON = PUB_FREQ,
|
||||
CHANNEL_SCIENCE = SCI_FREQ,
|
||||
CHANNEL_COMMAND = COMM_FREQ,
|
||||
CHANNEL_MEDICAL = MED_FREQ,
|
||||
CHANNEL_ENGINEERING = ENG_FREQ,
|
||||
CHANNEL_SECURITY = SEC_FREQ,
|
||||
CHANNEL_BODYCAM = BDCM_FREQ, // CHOMPEdit
|
||||
CHANNEL_RESPONSE_TEAM = ERT_FREQ,
|
||||
CHANNEL_SPECIAL_OPS = DTH_FREQ,
|
||||
CHANNEL_MERCENARY = SYND_FREQ,
|
||||
CHANNEL_RAIDER = RAID_FREQ,
|
||||
CHANNEL_SUPPLY = SUP_FREQ,
|
||||
CHANNEL_SERVICE = SRV_FREQ,
|
||||
CHANNEL_EXPLORATION = EXP_FREQ,
|
||||
CHANNEL_AI_PRIVATE = AI_FREQ,
|
||||
CHANNEL_ENTERTAINMENT = ENT_FREQ,
|
||||
CHANNEL_MEDICAL_1 = MED_I_FREQ,
|
||||
CHANNEL_SECURITY_1 = SEC_I_FREQ,
|
||||
CHANNEL_TALON = TALON_FREQ, //VOREStation Add
|
||||
CHANNEL_CASINO = CSN_FREQ,
|
||||
CHANNEL_OUTSIDER = OUT_FREQ //CHOMPstation Add
|
||||
)
|
||||
|
||||
// Hey, if anyone ever needs to update tgui/packages/tgui/constants.js with new radio channels
|
||||
// I've kept this around just for you.
|
||||
/* /client/verb/generate_tgui_radio_constants()
|
||||
set name = "Generate TGUI Radio Constants"
|
||||
set category = "Generate TGUI Radio Constants"
|
||||
|
||||
var/list/channel_info = list()
|
||||
|
||||
for(var/i in RADIO_LOW_FREQ to RADIO_HIGH_FREQ)
|
||||
for(var/key in radiochannels)
|
||||
if(i == radiochannels[key])
|
||||
channel_info.Add(list(list("name" = key, "freq" = i, "color" = frequency_span_class(i))))
|
||||
|
||||
for(var/list/channel in channel_info)
|
||||
switch(channel["color"])
|
||||
if("deadsay") channel["color"] = "#530FAD"
|
||||
if("radio") channel["color"] = "#008000"
|
||||
if("deptradio") channel["color"] = "#ff00ff"
|
||||
if("newscaster") channel["color"] = "#750000"
|
||||
if("comradio") channel["color"] = "#193A7A"
|
||||
if("syndradio") channel["color"] = "#6D3F40"
|
||||
if("centradio") channel["color"] = "#5C5C8A"
|
||||
if("airadio") channel["color"] = "#FF00FF"
|
||||
if("entradio") channel["color"] = "#339966"
|
||||
if("secradio") channel["color"] = "#A30000"
|
||||
if("engradio") channel["color"] = "#A66300"
|
||||
if("medradio") channel["color"] = "#008160"
|
||||
if("sciradio") channel["color"] = "#993399"
|
||||
if("supradio") channel["color"] = "#5F4519"
|
||||
if("srvradio") channel["color"] = "#6eaa2c"
|
||||
if("expradio") channel["color"] = "#555555"
|
||||
|
||||
to_chat(src, json_encode(channel_info)) */
|
||||
|
||||
|
||||
// central command channels, i.e deathsquid & response teams
|
||||
var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ)
|
||||
|
||||
// Antag channels, i.e. Syndicate
|
||||
var/list/ANTAG_FREQS = list(SYND_FREQ, RAID_FREQ)
|
||||
|
||||
//Department channels, arranged lexically
|
||||
var/list/DEPT_FREQS = list(AI_FREQ, BDCM_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ) // CHOMPEdit
|
||||
|
||||
var/list/OFFMAP_FREQS = list(TALON_FREQ, CSN_FREQ, OUT_FREQ) //VOREStation Add CHOMPEdit: Added outsider
|
||||
|
||||
/proc/frequency_span_class(var/frequency)
|
||||
// Antags!
|
||||
if (frequency in ANTAG_FREQS)
|
||||
return "syndradio"
|
||||
// CentCom channels (deathsquid and ert)
|
||||
if(frequency in CENT_FREQS)
|
||||
return "centradio"
|
||||
// command channel
|
||||
if(frequency == COMM_FREQ)
|
||||
return "comradio"
|
||||
// AI private channel
|
||||
if(frequency == AI_FREQ)
|
||||
return "airadio"
|
||||
// department radio formatting (poorly optimized, ugh)
|
||||
if(frequency == SEC_FREQ)
|
||||
return "secradio"
|
||||
if(frequency == BDCM_FREQ) // CHOMPEdit
|
||||
return "bdcmradio"
|
||||
if (frequency == ENG_FREQ)
|
||||
return "engradio"
|
||||
if(frequency == SCI_FREQ)
|
||||
return "sciradio"
|
||||
if(frequency == MED_FREQ)
|
||||
return "medradio"
|
||||
if(frequency == SUP_FREQ) // cargo
|
||||
return "supradio"
|
||||
if(frequency == SRV_FREQ) // service
|
||||
return "srvradio"
|
||||
if(frequency == EXP_FREQ) // explorer
|
||||
return "expradio"
|
||||
if(frequency == ENT_FREQ) // entertainment
|
||||
return "entradio"
|
||||
if(frequency in DEPT_FREQS)
|
||||
return "deptradio"
|
||||
//VOREStation Add
|
||||
if(frequency in OFFMAP_FREQS)
|
||||
return "expradio"
|
||||
//VOREStation Add End
|
||||
return "radio"
|
||||
|
||||
/* filters */
|
||||
//When devices register with the radio controller, they might register under a certain filter.
|
||||
//Other devices can then choose to send signals to only those devices that belong to a particular filter.
|
||||
//This is done for performance, so we don't send signals to lots of machines unnecessarily.
|
||||
|
||||
//This filter is special because devices belonging to default also recieve signals sent to any other filter.
|
||||
var/const/RADIO_DEFAULT = "radio_default"
|
||||
|
||||
var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms
|
||||
var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in recieving signals from air alarms
|
||||
var/const/RADIO_CHAT = "radio_telecoms"
|
||||
var/const/RADIO_ATMOSIA = "radio_atmos"
|
||||
var/const/RADIO_NAVBEACONS = "radio_navbeacon"
|
||||
var/const/RADIO_AIRLOCK = "radio_airlock"
|
||||
var/const/RADIO_SECBOT = "radio_secbot"
|
||||
var/const/RADIO_MULEBOT = "radio_mulebot"
|
||||
var/const/RADIO_MAGNETS = "radio_magnet"
|
||||
|
||||
var/global/datum/controller/radio/radio_controller
|
||||
|
||||
/hook/startup/proc/createRadioController()
|
||||
radio_controller = new /datum/controller/radio()
|
||||
return 1
|
||||
|
||||
//callback used by objects to react to incoming radio signals
|
||||
/obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
|
||||
return null
|
||||
|
||||
//The global radio controller
|
||||
/datum/controller/radio
|
||||
var/list/datum/radio_frequency/frequencies = list()
|
||||
|
||||
/datum/controller/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/radio_filter = null as text|null)
|
||||
var/f_text = num2text(new_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
if(!frequency)
|
||||
frequency = new
|
||||
frequency.frequency = new_frequency
|
||||
frequencies[f_text] = frequency
|
||||
|
||||
frequency.add_listener(device, radio_filter)
|
||||
return frequency
|
||||
|
||||
/datum/controller/radio/proc/remove_object(obj/device, old_frequency)
|
||||
var/f_text = num2text(old_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
if(frequency)
|
||||
frequency.remove_listener(device)
|
||||
|
||||
if(frequency.devices.len == 0)
|
||||
qdel(frequency)
|
||||
frequencies -= f_text
|
||||
|
||||
return 1
|
||||
|
||||
/datum/controller/radio/proc/return_frequency(var/new_frequency as num)
|
||||
var/f_text = num2text(new_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
if(!frequency)
|
||||
frequency = new
|
||||
frequency.frequency = new_frequency
|
||||
frequencies[f_text] = frequency
|
||||
|
||||
return frequency
|
||||
|
||||
/datum/radio_frequency
|
||||
var/frequency as num
|
||||
var/list/list/obj/devices = list()
|
||||
|
||||
/datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, var/radio_filter = null as text|null, var/range = null as num|null)
|
||||
var/turf/start_point
|
||||
if(range)
|
||||
start_point = get_turf(source)
|
||||
if(!start_point)
|
||||
qdel(signal)
|
||||
return 0
|
||||
if (radio_filter)
|
||||
send_to_filter(source, signal, radio_filter, start_point, range)
|
||||
send_to_filter(source, signal, RADIO_DEFAULT, start_point, range)
|
||||
else
|
||||
//Broadcast the signal to everyone!
|
||||
for (var/next_filter in devices)
|
||||
send_to_filter(source, signal, next_filter, start_point, range)
|
||||
|
||||
//Sends a signal to all machines belonging to a given filter. Should be called by post_signal()
|
||||
/datum/radio_frequency/proc/send_to_filter(obj/source, datum/signal/signal, var/radio_filter, var/turf/start_point = null, var/range = null)
|
||||
if (range && !start_point)
|
||||
return
|
||||
|
||||
for(var/obj/device in devices[radio_filter])
|
||||
if(device == source)
|
||||
continue
|
||||
if(range)
|
||||
var/turf/end_point = get_turf(device)
|
||||
if(!end_point)
|
||||
continue
|
||||
if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range)
|
||||
continue
|
||||
|
||||
device.receive_signal(signal, TRANSMISSION_RADIO, frequency)
|
||||
|
||||
/datum/radio_frequency/proc/add_listener(obj/device as obj, var/radio_filter as text|null)
|
||||
if (!radio_filter)
|
||||
radio_filter = RADIO_DEFAULT
|
||||
//log_admin("add_listener(device=[device],radio_filter=[radio_filter]) frequency=[frequency]")
|
||||
var/list/obj/devices_line = devices[radio_filter]
|
||||
if (!devices_line)
|
||||
devices_line = new
|
||||
devices[radio_filter] = devices_line
|
||||
devices_line+=device
|
||||
// var/list/obj/devices_line___ = devices[filter_str]
|
||||
// var/l = devices_line___.len
|
||||
//log_admin("DEBUG: devices_line.len=[devices_line.len]")
|
||||
//log_admin("DEBUG: devices(filter_str).len=[l]")
|
||||
|
||||
/datum/radio_frequency/proc/remove_listener(obj/device)
|
||||
for (var/devices_filter in devices)
|
||||
var/list/devices_line = devices[devices_filter]
|
||||
devices_line-=device
|
||||
while (null in devices_line)
|
||||
devices_line -= null
|
||||
if (devices_line.len==0)
|
||||
devices -= devices_filter
|
||||
|
||||
/datum/signal
|
||||
var/obj/source
|
||||
|
||||
var/transmission_method = 0 //unused at the moment
|
||||
//0 = wire
|
||||
//1 = radio transmission
|
||||
//2 = subspace transmission
|
||||
|
||||
var/list/data = list()
|
||||
var/encryption
|
||||
|
||||
var/frequency = 0
|
||||
|
||||
/datum/signal/proc/copy_from(datum/signal/model)
|
||||
source = model.source
|
||||
transmission_method = model.transmission_method
|
||||
data = model.data
|
||||
encryption = model.encryption
|
||||
frequency = model.frequency
|
||||
|
||||
/datum/signal/proc/debug_print()
|
||||
if (source)
|
||||
. = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n"
|
||||
else
|
||||
. = "signal = {source = '[source]' ()\n"
|
||||
for (var/i in data)
|
||||
. += "data\[\"[i]\"\] = \"[data[i]]\"\n"
|
||||
if(islist(data[i]))
|
||||
var/list/L = data[i]
|
||||
for(var/t in L)
|
||||
. += "data\[\"[i]\"\] list has: [t]"
|
||||
@@ -24,6 +24,9 @@
|
||||
/// If the configuration is loaded
|
||||
var/loaded = FALSE
|
||||
|
||||
/// If a reload is in progress
|
||||
var/reload_in_progress = FALSE
|
||||
|
||||
/// A regex that matches words blocked IC
|
||||
var/static/regex/ic_filter_regex
|
||||
|
||||
@@ -64,13 +67,23 @@
|
||||
var/static/list/configuration_errors
|
||||
|
||||
/datum/controller/configuration/proc/admin_reload()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
if(IsAdminAdvancedProcCall() || !PreConfigReload())
|
||||
return
|
||||
log_admin("[key_name_admin(usr)] has forcefully reloaded the configuration from disk.")
|
||||
message_admins("[key_name_admin(usr)] has forcefully reloaded the configuration from disk.")
|
||||
full_wipe()
|
||||
Load(world.params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
|
||||
|
||||
/datum/controller/configuration/proc/PreConfigReload()
|
||||
if(reload_in_progress)
|
||||
to_chat(usr, span_warning("Another user is already reloading the config!"))
|
||||
return FALSE
|
||||
|
||||
reload_in_progress = TRUE
|
||||
world.TgsTriggerEvent("tg-PreConfigReload", wait_for_completion = TRUE)
|
||||
reload_in_progress = FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/controller/configuration/proc/Load(_directory)
|
||||
if(IsAdminAdvancedProcCall()) //If admin proccall is detected down the line it will horribly break everything.
|
||||
return
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
/datum/config_entry/number/walk_speed
|
||||
default = 0
|
||||
|
||||
/datum/config_entry/flag/force_random_names
|
||||
|
||||
///Mob specific modifiers. NOTE: These will affect different mob types in different ways
|
||||
/datum/config_entry/number/human_delay
|
||||
default = 0
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/// server name (the name of the game window)
|
||||
/datum/config_entry/string/servername
|
||||
|
||||
/// Countdown between lobby and the round starting.
|
||||
/datum/config_entry/number/lobby_countdown
|
||||
default = 120
|
||||
integer = FALSE
|
||||
min_val = 0
|
||||
|
||||
/// Post round murder death kill countdown.
|
||||
/datum/config_entry/number/round_end_countdown
|
||||
default = 25
|
||||
integer = FALSE
|
||||
min_val = 0
|
||||
|
||||
/// generate numeric suffix based on server port
|
||||
/datum/config_entry/flag/server_suffix
|
||||
|
||||
@@ -222,9 +234,6 @@
|
||||
|
||||
// var/static/Tickcomp = 0 // FIXME: Unused
|
||||
|
||||
/// use socket_talk to communicate with other processes
|
||||
/datum/config_entry/flag/socket_talk
|
||||
|
||||
// var/static/list/resource_urls = null // FIXME: Unused
|
||||
|
||||
/// Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round.
|
||||
@@ -787,6 +796,60 @@
|
||||
/datum/config_entry/flag/discord_ahelps_all
|
||||
default = FALSE
|
||||
|
||||
/datum/config_entry/number/mc_tick_rate/base_mc_tick_rate
|
||||
integer = FALSE
|
||||
default = 1
|
||||
|
||||
/datum/config_entry/number/mc_tick_rate/high_pop_mc_tick_rate
|
||||
integer = FALSE
|
||||
default = 1.1
|
||||
|
||||
/datum/config_entry/number/mc_tick_rate/high_pop_mc_mode_amount
|
||||
default = 65
|
||||
|
||||
/datum/config_entry/number/mc_tick_rate/disable_high_pop_mc_mode_amount
|
||||
default = 60
|
||||
|
||||
/datum/config_entry/number/mc_tick_rate
|
||||
abstract_type = /datum/config_entry/number/mc_tick_rate
|
||||
|
||||
/datum/config_entry/number/mc_tick_rate/ValidateAndSet(str_val)
|
||||
. = ..()
|
||||
if (.)
|
||||
Master.UpdateTickRate()
|
||||
|
||||
/datum/config_entry/flag/resume_after_initializations
|
||||
|
||||
/datum/config_entry/flag/resume_after_initializations/ValidateAndSet(str_val)
|
||||
. = ..()
|
||||
if(. && MC_RUNNING())
|
||||
world.sleep_offline = !config_entry_value
|
||||
|
||||
/datum/config_entry/number/rounds_until_hard_restart
|
||||
default = -1
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/auto_profile
|
||||
|
||||
/datum/config_entry/number/profiler_interval
|
||||
default = 300 SECONDS
|
||||
|
||||
/datum/config_entry/number/drift_dump_threshold
|
||||
default = 4 SECONDS
|
||||
|
||||
/datum/config_entry/number/drift_profile_delay
|
||||
default = 15 SECONDS
|
||||
|
||||
/datum/config_entry/flag/forbid_all_profiling
|
||||
|
||||
/datum/config_entry/flag/forbid_admin_profiling
|
||||
|
||||
/datum/config_entry/flag/toast_notification_on_init
|
||||
|
||||
/// If admins with +DEBUG can initialize byond-tracy midround.
|
||||
/datum/config_entry/flag/allow_tracy_start
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/// If admins with +DEBUG can queue byond-tracy to run the next round.
|
||||
/datum/config_entry/flag/allow_tracy_queue
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
@@ -161,8 +161,8 @@
|
||||
|
||||
/datum/emergency_shuttle_controller/proc/get_shuttle_prep_time()
|
||||
// During mutiny rounds, the shuttle takes twice as long.
|
||||
if(ticker && ticker.mode)
|
||||
return SHUTTLE_PREPTIME * ticker.mode.shuttle_delay
|
||||
if(SSticker && SSticker.mode)
|
||||
return SHUTTLE_PREPTIME * SSticker.mode.shuttle_delay
|
||||
return SHUTTLE_PREPTIME
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
var/running = TRUE
|
||||
|
||||
/datum/controller/failsafe/New()
|
||||
// Ensure usr is null, to prevent any potential weirdness resulting from the failsafe having a usr if it's manually restarted.
|
||||
usr = null
|
||||
|
||||
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
|
||||
if(Failsafe != src)
|
||||
if(istype(Failsafe))
|
||||
@@ -149,7 +152,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
/proc/recover_all_SS_and_recreate_master()
|
||||
del(Master)
|
||||
var/list/subsytem_types = subtypesof(/datum/controller/subsystem)
|
||||
sortTim(subsytem_types, GLOBAL_PROC_REF(cmp_subsystem_init))
|
||||
sortTim(subsytem_types, GLOBAL_PROC_REF(cmp_subsystem_init_stage))
|
||||
for(var/I in subsytem_types)
|
||||
new I
|
||||
. = Recreate_MC()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// See initialization order in /code/game/world.dm
|
||||
GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
|
||||
/datum/controller/global_vars
|
||||
name = "Global Variables"
|
||||
|
||||
var/list/gvars_datum_protected_varlist
|
||||
var/static/list/gvars_datum_protected_varlist
|
||||
var/list/gvars_datum_in_built_vars
|
||||
var/list/gvars_datum_init_order
|
||||
|
||||
@@ -13,30 +14,24 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
GLOB = src
|
||||
|
||||
var/datum/controller/exclude_these = new
|
||||
gvars_datum_in_built_vars = exclude_these.vars + list("gvars_datum_protected_varlist", "gvars_datum_in_built_vars", "gvars_datum_init_order")
|
||||
// I know this is dumb but the nested vars list hangs a ref to the datum. This fixes that
|
||||
// I have an issue report open, lummox has not responded. It might be a FeaTuRE
|
||||
// Sooo we gotta be dumb
|
||||
var/list/controller_vars = exclude_these.vars.Copy()
|
||||
controller_vars["vars"] = null
|
||||
gvars_datum_in_built_vars = controller_vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order))
|
||||
|
||||
log_world("[vars.len - gvars_datum_in_built_vars.len] global variables")
|
||||
QDEL_IN(exclude_these, 0) //signal logging isn't ready
|
||||
|
||||
Initialize(exclude_these)
|
||||
Initialize()
|
||||
|
||||
/datum/controller/global_vars/Destroy(force)
|
||||
stack_trace("There was an attempt to qdel the global vars holder!")
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
QDEL_NULL(statclick)
|
||||
gvars_datum_protected_varlist.Cut()
|
||||
gvars_datum_in_built_vars.Cut()
|
||||
|
||||
GLOB = null
|
||||
|
||||
return ..()
|
||||
// This is done to prevent an exploit where admins can get around protected vars
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
/datum/controller/global_vars/stat_entry(msg)
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
|
||||
|
||||
msg = "GLOB: [statclick.update("Edit")]"
|
||||
msg = "Edit"
|
||||
return msg
|
||||
|
||||
/datum/controller/global_vars/vv_edit_var(var_name, var_value)
|
||||
@@ -44,6 +39,14 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/*
|
||||
/datum/controller/global_vars/vv_get_var(var_name)
|
||||
switch(var_name)
|
||||
if (NAMEOF(src, vars))
|
||||
return debug_variable(var_name, list(), 0, src)
|
||||
return debug_variable(var_name, vars[var_name], 0, src, display_flags = VV_ALWAYS_CONTRACT_LIST)
|
||||
*/
|
||||
|
||||
/datum/controller/global_vars/Initialize()
|
||||
gvars_datum_init_order = list()
|
||||
gvars_datum_protected_varlist = list(NAMEOF(src, gvars_datum_protected_varlist) = TRUE)
|
||||
@@ -55,8 +58,8 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
var/list/expected_global_procs = vars - gvars_datum_in_built_vars
|
||||
for(var/I in global_procs)
|
||||
expected_global_procs -= replacetext("[I]", "InitGlobal", "")
|
||||
var/english_missing = expected_global_procs.Join(", ")
|
||||
log_world("Missing procs: [english_missing]")
|
||||
log_world("Missing procs: [expected_global_procs.Join(", ")]")
|
||||
|
||||
for(var/I in global_procs)
|
||||
var/start_tick = world.time
|
||||
call(src, I)()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@ var/global/last_tick_duration = 0
|
||||
transfer_controller = new
|
||||
admin_notice(span_danger("Initializations complete."), R_DEBUG)
|
||||
|
||||
// #if UNIT_TEST
|
||||
// #if UNIT_TESTS
|
||||
// # define CHECK_SLEEP_MASTER // For unit tests we don't care about a smooth lobby screen experience. We care about speed.
|
||||
// #else
|
||||
// # define CHECK_SLEEP_MASTER if(++initialized_objects > 500) { initialized_objects=0;sleep(world.tick_lag); }
|
||||
|
||||
@@ -13,27 +13,48 @@
|
||||
/// Name of the subsystem - you must change this
|
||||
name = "fire coderbus"
|
||||
|
||||
/// Order of initialization. Higher numbers are initialized first, lower numbers later. Use or create defines such as [INIT_ORDER_DEFAULT] so we can see the order in one file.
|
||||
var/init_order = INIT_ORDER_DEFAULT
|
||||
/// Determines which subsystems this subsystem is dependant on to initialize. Will initialize after all specified subsystems.
|
||||
/// If init_stage is earlier than a dependent subsystem, will throw an error and push the init stage forward to that subsystem.
|
||||
/// Usage: Put the typepaths of the subsystems that need to init before this one in this list.
|
||||
var/list/dependencies = list()
|
||||
|
||||
/// The inverse of the dependencies. Can be set manually, but will also get evaluated at runtime. Turns into a list of instances at runtime.
|
||||
/// Usage: Put the typepaths of the subsystems that need to init after this one in this list.
|
||||
var/list/dependents
|
||||
|
||||
/// ID of the subsystem. Set automatically when the dependency graph is evaluated. Used primarily in determining order.
|
||||
var/ordering_id = 0
|
||||
|
||||
/// Do not modify. Automatically set when the dependency graph is evaluated. Similar to ordering_id, but evaluated after init_stage.
|
||||
var/init_order = 0
|
||||
|
||||
/// Time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
|
||||
var/wait = 20
|
||||
|
||||
/// Priority Weight: When mutiple subsystems need to run in the same tick, higher priority subsystems will be given a higher share of the tick before MC_TICK_CHECK triggers a sleep, higher priority subsystems also run before lower priority subsystems.
|
||||
/// Priority Weight: When multiple subsystems need to run in the same tick, higher priority subsystems will be given a higher share of the tick before MC_TICK_CHECK triggers a sleep, higher priority subsystems also run before lower priority subsystems
|
||||
var/priority = FIRE_PRIORITY_DEFAULT
|
||||
|
||||
/// [Subsystem Flags][SS_NO_INIT] to control binary behavior. Flags must be set at compile time or before preinit finishes to take full effect. (You can also restart the mc to force them to process again)
|
||||
var/flags = NONE
|
||||
|
||||
/// This var is set to TRUE after the subsystem has been initialized.
|
||||
var/subsystem_initialized = FALSE
|
||||
/// Which stage does this subsystem init at. Earlier stages can fire while later stages init.
|
||||
var/init_stage = INITSTAGE_MAIN
|
||||
|
||||
/// This var is set to `INITIALIZATION_INNEW_REGULAR` after the subsystem has been initialized.
|
||||
var/initialized = FALSE
|
||||
|
||||
/// Set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
|
||||
/// use the [SS_NO_FIRE] flag instead for systems that never fire to keep it from even being added to list that is checked every tick
|
||||
var/can_fire = TRUE
|
||||
|
||||
///Bitmap of what game states can this subsystem fire at. See [RUNLEVELS_DEFAULT] for more details.
|
||||
var/runlevels = RUNLEVELS_DEFAULT
|
||||
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
|
||||
|
||||
/**
|
||||
* boolean set by admins. if TRUE then this subsystem will stop the world profiler after ignite() returns and start it again when called.
|
||||
* used so that you can audit a specific subsystem or group of subsystems' synchronous call chain.
|
||||
*/
|
||||
var/profiler_focused = FALSE
|
||||
|
||||
/*
|
||||
* The following variables are managed by the MC and should not be modified directly.
|
||||
@@ -54,6 +75,9 @@
|
||||
/// Running average of the amount of tick usage (in percents of a game tick) the subsystem has spent past its allocated time without pausing
|
||||
var/tick_overrun = 0
|
||||
|
||||
/// Flat list of usage and time, every odd index is a log time, every even index is a usage
|
||||
var/list/rolling_usage = list()
|
||||
|
||||
/// How much of a tick (in percents of a tick) were we allocated last fire.
|
||||
var/tick_allocation_last = 0
|
||||
|
||||
@@ -78,6 +102,9 @@
|
||||
/// Tracks the amount of completed runs for the subsystem
|
||||
var/times_fired = 0
|
||||
|
||||
/// How many fires have we been requested to postpone
|
||||
var/postponed_fires = 0
|
||||
|
||||
/// Time the subsystem entered the queue, (for timing and priority reasons)
|
||||
var/queued_time = 0
|
||||
|
||||
@@ -92,9 +119,13 @@
|
||||
/// Previous subsystem in the queue of subsystems to run this tick
|
||||
var/datum/controller/subsystem/queue_prev
|
||||
|
||||
/// String to store an applicable error message for a subsystem crashing, used to help debug crashes in contexts such as Continuous Integration/Unit Tests
|
||||
var/initialization_failure_message = null
|
||||
|
||||
//Do not blindly add vars here to the bottom, put it where it goes above
|
||||
//If your var only has two values, put it in as a flag.
|
||||
|
||||
|
||||
//Do not override
|
||||
///datum/controller/subsystem/New()
|
||||
|
||||
@@ -107,7 +138,7 @@
|
||||
///This is used so the mc knows when the subsystem sleeps. do not override.
|
||||
/datum/controller/subsystem/proc/ignite(resumed = FALSE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
set waitfor = 0
|
||||
set waitfor = FALSE
|
||||
. = SS_IDLE
|
||||
|
||||
tick_allocation_last = Master.current_ticklimit-(TICK_USAGE)
|
||||
@@ -131,7 +162,7 @@
|
||||
///Sleeping in here prevents future fires until returned.
|
||||
/datum/controller/subsystem/proc/fire(resumed = FALSE)
|
||||
flags |= SS_NO_FIRE
|
||||
throw EXCEPTION("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.")
|
||||
CRASH("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.")
|
||||
|
||||
/datum/controller/subsystem/Destroy()
|
||||
dequeue()
|
||||
@@ -141,6 +172,31 @@
|
||||
Master.subsystems -= src
|
||||
return ..()
|
||||
|
||||
|
||||
/** Update next_fire for the next run.
|
||||
* reset_time (bool) - Ignore things that would normally alter the next fire, like tick_overrun, and last_fire. (also resets postpone)
|
||||
*/
|
||||
/datum/controller/subsystem/proc/update_nextfire(reset_time = FALSE)
|
||||
var/queue_node_flags = flags
|
||||
|
||||
if (reset_time)
|
||||
postponed_fires = 0
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
next_fire = world.time + (world.tick_lag * wait)
|
||||
else
|
||||
next_fire = world.time + wait
|
||||
return
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
next_fire = world.time + (world.tick_lag * wait)
|
||||
else if (queue_node_flags & SS_POST_FIRE_TIMING)
|
||||
next_fire = world.time + wait + (world.tick_lag * (tick_overrun/100))
|
||||
else if (queue_node_flags & SS_KEEP_TIMING)
|
||||
next_fire += wait
|
||||
else
|
||||
next_fire = queued_time + wait + (world.tick_lag * (tick_overrun/100))
|
||||
|
||||
|
||||
///Queue it to run.
|
||||
/// (we loop thru a linked list until we get to the end or find the right point)
|
||||
/// (this lets us sort our run order correctly without having to re-sort the entire already sorted list)
|
||||
@@ -155,8 +211,8 @@
|
||||
queue_node_priority = queue_node.queued_priority
|
||||
queue_node_flags = queue_node.flags
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
if (!(SS_flags & SS_TICKER))
|
||||
if (queue_node_flags & (SS_TICKER|SS_BACKGROUND) == SS_TICKER)
|
||||
if ((SS_flags & (SS_TICKER|SS_BACKGROUND)) != SS_TICKER)
|
||||
continue
|
||||
if (queue_node_priority < SS_priority)
|
||||
break
|
||||
@@ -207,9 +263,9 @@
|
||||
queue_next.queue_prev = queue_prev
|
||||
if (queue_prev)
|
||||
queue_prev.queue_next = queue_next
|
||||
if (src == Master.queue_tail)
|
||||
if (Master && (src == Master.queue_tail))
|
||||
Master.queue_tail = queue_prev
|
||||
if (src == Master.queue_head)
|
||||
if (Master && (src == Master.queue_head))
|
||||
Master.queue_head = queue_next
|
||||
queued_time = 0
|
||||
if (state == SS_QUEUED)
|
||||
@@ -228,14 +284,13 @@
|
||||
/datum/controller/subsystem/proc/OnConfigLoad()
|
||||
|
||||
/**
|
||||
* Used to initialize the subsystem. This is expected to be overriden by subtypes.
|
||||
* Used to initialize the subsystem. This is expected to be overridden by subtypes.
|
||||
*/
|
||||
/datum/controller/subsystem/Initialize()
|
||||
return SS_INIT_NONE
|
||||
|
||||
//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
|
||||
/datum/controller/subsystem/stat_entry(msg)
|
||||
if(can_fire && !(SS_NO_FIRE & flags))
|
||||
if(can_fire && !(SS_NO_FIRE & flags) && init_stage <= Master.init_stage_completed)
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
|
||||
else
|
||||
msg = "OFFLINE\t[msg]"
|
||||
@@ -254,45 +309,30 @@
|
||||
if (SS_IDLE)
|
||||
. = " "
|
||||
|
||||
//could be used to postpone a costly subsystem for (default one) var/cycles, cycles
|
||||
//for instance, during cpu intensive operations like explosions
|
||||
/// Causes the next "cycle" fires to be missed. Effect is accumulative but can reset by calling update_nextfire(reset_time = TRUE)
|
||||
/datum/controller/subsystem/proc/postpone(cycles = 1)
|
||||
if(next_fire - world.time < wait)
|
||||
next_fire += (wait*cycles)
|
||||
if (can_fire && cycles >= 1)
|
||||
postponed_fires += cycles
|
||||
|
||||
/// Prunes out of date entries in our rolling usage list
|
||||
/datum/controller/subsystem/proc/prune_rolling_usage()
|
||||
var/list/rolling_usage = src.rolling_usage
|
||||
var/cut_to = 0
|
||||
while(cut_to + 2 <= length(rolling_usage) && rolling_usage[cut_to + 1] < DS2TICKS(world.time - Master.rolling_usage_length))
|
||||
cut_to += 2
|
||||
if(cut_to)
|
||||
rolling_usage.Cut(1, cut_to + 1)
|
||||
|
||||
//usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
|
||||
//should attempt to salvage what it can from the old instance of subsystem
|
||||
/datum/controller/subsystem/Recover()
|
||||
|
||||
// Suspends this subsystem from being queued for running. If already in the queue, sleeps until idle. Returns FALSE if the subsystem was already suspended.
|
||||
/datum/controller/subsystem/proc/suspend()
|
||||
. = (can_fire > 0) // Return true if we were previously runnable, false if previously suspended.
|
||||
can_fire = FALSE
|
||||
// Safely sleep in a loop until the subsystem is idle, (or its been un-suspended somehow)
|
||||
while(can_fire <= 0 && state != SS_IDLE)
|
||||
stoplag() // Safely sleep in a loop until
|
||||
|
||||
// Wakes a suspended subsystem.
|
||||
/datum/controller/subsystem/proc/wake()
|
||||
can_fire = TRUE
|
||||
|
||||
// This subsystem has destabilized the game and is being put on warning. At this point there may be
|
||||
// an opportunity to clean up the subsystem or check it for errors in ways that would otherwise be too slow.
|
||||
// You should log the errors/cleanup results, so you can fix the problem rather than using this as a crutch.
|
||||
/datum/controller/subsystem/proc/fail()
|
||||
var/msg = "[name] subsystem being blamed for MC failure"
|
||||
log_world(msg)
|
||||
log_game(msg)
|
||||
|
||||
// DO NOT ATTEMPT RECOVERY. Only log debugging info. You should leave the subsystem as it is.
|
||||
// Attempting recovery here could make things worse, create hard recursions with the MC disabling it every run, etc.
|
||||
/datum/controller/subsystem/proc/critfail()
|
||||
var/msg = "[name] subsystem received final blame for MC failure"
|
||||
log_world(msg)
|
||||
log_game(msg)
|
||||
|
||||
/datum/controller/subsystem/vv_edit_var(var_name, var_value)
|
||||
switch (var_name)
|
||||
if (NAMEOF(src, can_fire))
|
||||
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
|
||||
if (var_value)
|
||||
update_nextfire(reset_time = TRUE)
|
||||
if (NAMEOF(src, queued_priority)) //editing this breaks things.
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
@@ -3,7 +3,7 @@ GENERAL_PROTECT_DATUM(/datum/controller/subsystem/admin_verbs)
|
||||
SUBSYSTEM_DEF(admin_verbs)
|
||||
name = "Admin Verbs"
|
||||
flags = SS_NO_FIRE
|
||||
//init_stage = INITSTAGE_EARLY
|
||||
init_stage = INITSTAGE_EARLY
|
||||
/// A list of all admin verbs indexed by their type.
|
||||
var/list/datum/admin_verb/admin_verbs_by_type = list()
|
||||
/// A list of all admin verbs indexed by their visibility flag.
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
SUBSYSTEM_DEF(ai)
|
||||
name = "AI"
|
||||
init_order = INIT_ORDER_AI
|
||||
priority = FIRE_PRIORITY_AI
|
||||
wait = 2 SECONDS
|
||||
flags = SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/air,
|
||||
/datum/controller/subsystem/mobs
|
||||
)
|
||||
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
SUBSYSTEM_DEF(aifast)
|
||||
name = "AI (Fast)"
|
||||
init_order = INIT_ORDER_AI_FAST
|
||||
priority = FIRE_PRIORITY_AI
|
||||
wait = 0.25 SECONDS // Every quarter second
|
||||
flags = SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/ai
|
||||
)
|
||||
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
|
||||
@@ -65,7 +65,9 @@ Class Procs:
|
||||
|
||||
SUBSYSTEM_DEF(air)
|
||||
name = "Air"
|
||||
init_order = INIT_ORDER_AIR
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/atoms
|
||||
)
|
||||
priority = FIRE_PRIORITY_AIR
|
||||
wait = 2 SECONDS // seconds (We probably can speed this up actually)
|
||||
flags = SS_BACKGROUND // TODO - Should this really be background? It might be important.
|
||||
|
||||
@@ -6,7 +6,7 @@ SUBSYSTEM_DEF(atc)
|
||||
priority = FIRE_PRIORITY_ATC
|
||||
runlevels = RUNLEVEL_GAME
|
||||
wait = 2 SECONDS
|
||||
init_order = INIT_ORDER_ATC
|
||||
init_stage = INITSTAGE_LAST
|
||||
flags = SS_BACKGROUND
|
||||
|
||||
VAR_PRIVATE/next_tick = 0
|
||||
|
||||
@@ -16,6 +16,11 @@ SUBSYSTEM_DEF(airflow)
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
priority = FIRE_PRIORITY_AIRFLOW
|
||||
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/atoms,
|
||||
/datum/controller/subsystem/air
|
||||
)
|
||||
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ SUBSYSTEM_DEF(alarm)
|
||||
name = "Alarm"
|
||||
wait = 2 SECONDS
|
||||
priority = FIRE_PRIORITY_ALARM
|
||||
init_order = INIT_ORDER_ALARM
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping
|
||||
)
|
||||
var/list/datum/alarm/all_handlers
|
||||
var/tmp/list/currentrun = null
|
||||
var/static/list/active_alarm_cache = list()
|
||||
|
||||
@@ -13,7 +13,6 @@ SUBSYSTEM_DEF(asset_loading)
|
||||
while(length(generate_queue))
|
||||
var/datum/asset/to_load = generate_queue[generate_queue.len]
|
||||
|
||||
|
||||
last_queue_len = length(generate_queue)
|
||||
generate_queue.len--
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
SUBSYSTEM_DEF(assets)
|
||||
name = "Assets"
|
||||
init_order = INIT_ORDER_ASSETS
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/holomaps,
|
||||
/datum/controller/subsystem/robot_sprites
|
||||
///datum/controller/subsystem/persistent_paintings,
|
||||
///datum/controller/subsystem/greyscale_previews,
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
var/list/datum/asset_cache_item/cache = list()
|
||||
var/list/preload = list()
|
||||
@@ -32,7 +37,7 @@ SUBSYSTEM_DEF(assets)
|
||||
|
||||
transport.Initialize(cache)
|
||||
|
||||
subsystem_initialized = TRUE
|
||||
initialized = TRUE
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/assets/Recover()
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
SUBSYSTEM_DEF(atoms)
|
||||
name = "Atoms"
|
||||
init_order = INIT_ORDER_ATOMS
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/garbage,
|
||||
/datum/controller/subsystem/mapping,
|
||||
/datum/controller/subsystem/planets,
|
||||
/datum/controller/subsystem/transcore,
|
||||
/datum/controller/subsystem/chemistry,
|
||||
/datum/controller/subsystem/sounds,
|
||||
/datum/controller/subsystem/job
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
/// A stack of list(source, desired initialized state)
|
||||
@@ -8,7 +16,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
var/list/initialized_state = list()
|
||||
var/base_initialized
|
||||
|
||||
var/initialized = INITIALIZATION_INSSATOMS
|
||||
var/atom_initialized = INITIALIZATION_INSSATOMS
|
||||
var/list/late_loaders = list()
|
||||
|
||||
var/list/BadInitializeCalls = list()
|
||||
@@ -25,19 +33,19 @@ SUBSYSTEM_DEF(atoms)
|
||||
var/list/mapload_init_times = list()
|
||||
#endif
|
||||
|
||||
initialized = INITIALIZATION_INSSATOMS
|
||||
atom_initialized = INITIALIZATION_INSSATOMS
|
||||
|
||||
/datum/controller/subsystem/atoms/Initialize()
|
||||
init_start_time = world.time
|
||||
|
||||
initialized = INITIALIZATION_INNEW_MAPLOAD
|
||||
atom_initialized = INITIALIZATION_INNEW_MAPLOAD
|
||||
InitializeAtoms()
|
||||
initialized = INITIALIZATION_INNEW_REGULAR
|
||||
atom_initialized = INITIALIZATION_INNEW_REGULAR
|
||||
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms, list/atoms_to_return)
|
||||
if(initialized == INITIALIZATION_INSSATOMS)
|
||||
if(atom_initialized == INITIALIZATION_INSSATOMS)
|
||||
return
|
||||
|
||||
// Generate a unique mapload source for this run of InitializeAtoms
|
||||
@@ -142,9 +150,9 @@ SUBSYSTEM_DEF(atoms)
|
||||
/// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentally
|
||||
/datum/controller/subsystem/atoms/proc/set_tracked_initalized(state, source)
|
||||
if(!length(initialized_state))
|
||||
base_initialized = initialized
|
||||
base_initialized = atom_initialized
|
||||
initialized_state += list(list(source, state))
|
||||
initialized = state
|
||||
atom_initialized = state
|
||||
|
||||
/datum/controller/subsystem/atoms/proc/clear_tracked_initalize(source)
|
||||
if(!length(initialized_state))
|
||||
@@ -155,18 +163,18 @@ SUBSYSTEM_DEF(atoms)
|
||||
break
|
||||
|
||||
if(!length(initialized_state))
|
||||
initialized = base_initialized
|
||||
atom_initialized = base_initialized
|
||||
base_initialized = INITIALIZATION_INNEW_REGULAR
|
||||
return
|
||||
initialized = initialized_state[length(initialized_state)][2]
|
||||
atom_initialized = initialized_state[length(initialized_state)][2]
|
||||
|
||||
/// Returns TRUE if anything is currently being initialized
|
||||
/datum/controller/subsystem/atoms/proc/initializing_something()
|
||||
return length(initialized_state) > 1
|
||||
|
||||
/datum/controller/subsystem/atoms/Recover()
|
||||
initialized = SSatoms.initialized
|
||||
if(initialized == INITIALIZATION_INNEW_MAPLOAD)
|
||||
atom_initialized = SSatoms.atom_initialized
|
||||
if(atom_initialized == INITIALIZATION_INNEW_MAPLOAD)
|
||||
InitializeAtoms()
|
||||
initialized_state = SSatoms.initialized_state
|
||||
BadInitializeCalls = SSatoms.BadInitializeCalls
|
||||
@@ -187,7 +195,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
|
||||
/// Prepares an atom to be deleted once the atoms SS is initialized.
|
||||
/datum/controller/subsystem/atoms/proc/prepare_deletion(atom/target)
|
||||
if (initialized == INITIALIZATION_INNEW_REGULAR)
|
||||
if (atom_initialized == INITIALIZATION_INNEW_REGULAR)
|
||||
// Atoms SS has already completed, just kill it now.
|
||||
qdel(target)
|
||||
else
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
SUBSYSTEM_DEF(character_setup)
|
||||
name = "Character Setup"
|
||||
init_order = INIT_ORDER_DEFAULT
|
||||
priority = FIRE_PRIORITY_CHARSETUP
|
||||
flags = SS_BACKGROUND | SS_NO_INIT
|
||||
wait = 1 SECOND
|
||||
|
||||
@@ -8,7 +8,7 @@ SUBSYSTEM_DEF(chat)
|
||||
flags = SS_TICKER|SS_NO_INIT
|
||||
wait = 1
|
||||
priority = FIRE_PRIORITY_CHAT
|
||||
init_order = INIT_ORDER_CHAT
|
||||
init_stage = INITSTAGE_LAST
|
||||
|
||||
/// Assosciates a ckey with a list of messages to send to them.
|
||||
var/list/list/datum/chat_payload/client_to_payloads = list()
|
||||
|
||||
@@ -2,7 +2,9 @@ SUBSYSTEM_DEF(chemistry)
|
||||
name = "Chemistry"
|
||||
wait = 20
|
||||
flags = SS_NO_FIRE
|
||||
init_order = INIT_ORDER_CHEMISTRY
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/garbage
|
||||
)
|
||||
|
||||
var/list/chemical_reactions = list()
|
||||
var/list/chemical_reactions_by_product = list()
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
//
|
||||
SUBSYSTEM_DEF(circuit)
|
||||
name = "Circuit"
|
||||
init_order = INIT_ORDER_CIRCUIT
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/atoms
|
||||
)
|
||||
|
||||
var/list/all_components = list() // Associative list of [component_name]:[component_path] pairs
|
||||
var/list/cached_components = list() // Associative list of [component_path]:[component] pairs
|
||||
var/list/all_assemblies = list() // Associative list of [assembly_name]:[assembly_path] pairs
|
||||
|
||||
207
code/controllers/subsystems/communications.dm
Normal file
207
code/controllers/subsystems/communications.dm
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
HOW IT WORKS
|
||||
|
||||
The SSradio is a global object maintaining all radio transmissions, think about it as about "ether".
|
||||
Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way.
|
||||
procs:
|
||||
|
||||
add_object(obj/device as obj, var/new_frequency as num, var/radio_filter as text|null = null)
|
||||
Adds listening object.
|
||||
parameters:
|
||||
device - device receiving signals, must have proc receive_signal (see description below).
|
||||
one device may listen several frequencies, but not same frequency twice.
|
||||
new_frequency - see possibly frequencies below;
|
||||
radio_filter - thing for optimization. Optional, but recommended.
|
||||
All filters should be consolidated in this file, see defines later.
|
||||
Device without listening filter will receive all signals (on specified frequency).
|
||||
Device with filter will receive any signals sent without filter.
|
||||
Device with filter will not receive any signals sent with different filter.
|
||||
returns:
|
||||
Reference to frequency object.
|
||||
|
||||
remove_object (obj/device, old_frequency)
|
||||
Obliviously, after calling this proc, device will not receive any signals on old_frequency.
|
||||
Other frequencies will left unaffected.
|
||||
|
||||
return_frequency(var/frequency as num)
|
||||
returns:
|
||||
Reference to frequency object. Use it if you need to send and do not need to listen.
|
||||
|
||||
radio_frequency is a global object maintaining list of devices that listening specific frequency.
|
||||
procs:
|
||||
|
||||
post_signal(obj/source as obj|null, datum/signal/signal, var/radio_filter as text|null = null, var/range as num|null = null)
|
||||
Sends signal to all devices that wants such signal.
|
||||
parameters:
|
||||
source - object, emitted signal. Usually, devices will not receive their own signals.
|
||||
signal - see description below.
|
||||
radio_filter - described above.
|
||||
range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels.
|
||||
|
||||
obj/proc/receive_signal(datum/signal/signal, var/receive_method as num, var/receive_param)
|
||||
Handler from received signals. By default does nothing. Define your own for your object.
|
||||
Avoid of sending signals directly from this proc, use spawn(-1). DO NOT use sleep() here or call procs that sleep please. If you must, use spawn()
|
||||
parameters:
|
||||
signal - see description below. Extract all needed data from the signal before doing sleep(), spawn() or return!
|
||||
receive_method - may be TRANSMISSION_WIRE or TRANSMISSION_RADIO.
|
||||
TRANSMISSION_WIRE is currently unused.
|
||||
receive_param - for TRANSMISSION_RADIO here comes frequency.
|
||||
|
||||
datum/signal
|
||||
vars:
|
||||
source
|
||||
an object that emitted signal. Used for debug and bearing.
|
||||
data
|
||||
list with transmitting data. Usual use pattern:
|
||||
data["msg"] = "hello world"
|
||||
encryption
|
||||
Some number symbolizing "encryption key".
|
||||
Note that game actually do not use any cryptography here.
|
||||
If receiving object don't know right key, it must ignore encrypted signal in its receive_signal.
|
||||
|
||||
*/
|
||||
|
||||
SUBSYSTEM_DEF(radio)
|
||||
name = "Radio"
|
||||
flags = SS_NO_FIRE
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/machines
|
||||
)
|
||||
var/list/datum/radio_frequency/frequencies = list()
|
||||
|
||||
/datum/controller/subsystem/radio/Initialize()
|
||||
GLOB.autospeaker = new (null, FALSE, null, null, TRUE) //Set up Global Announcer
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/radio_filter = null as text|null)
|
||||
var/f_text = num2text(new_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
if(!frequency)
|
||||
frequency = new
|
||||
frequency.frequency = new_frequency
|
||||
frequencies[f_text] = frequency
|
||||
|
||||
frequency.add_listener(device, radio_filter)
|
||||
return frequency
|
||||
|
||||
/datum/controller/subsystem/radio/proc/remove_object(obj/device, old_frequency)
|
||||
var/f_text = num2text(old_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
if(frequency)
|
||||
frequency.remove_listener(device)
|
||||
|
||||
if(frequency.devices.len == 0)
|
||||
qdel(frequency)
|
||||
frequencies -= f_text
|
||||
|
||||
return 1
|
||||
|
||||
/datum/controller/subsystem/radio/proc/return_frequency(var/new_frequency as num)
|
||||
var/f_text = num2text(new_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
if(!frequency)
|
||||
frequency = new
|
||||
frequency.frequency = new_frequency
|
||||
frequencies[f_text] = frequency
|
||||
|
||||
return frequency
|
||||
|
||||
//Frequency channels
|
||||
|
||||
/datum/radio_frequency
|
||||
var/frequency as num
|
||||
var/list/list/obj/devices = list()
|
||||
|
||||
/datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, var/radio_filter = null as text|null, var/range = null as num|null)
|
||||
var/turf/start_point
|
||||
if(range)
|
||||
start_point = get_turf(source)
|
||||
if(!start_point)
|
||||
qdel(signal)
|
||||
return 0
|
||||
if (radio_filter)
|
||||
send_to_filter(source, signal, radio_filter, start_point, range)
|
||||
send_to_filter(source, signal, RADIO_DEFAULT, start_point, range)
|
||||
else
|
||||
//Broadcast the signal to everyone!
|
||||
for (var/next_filter in devices)
|
||||
send_to_filter(source, signal, next_filter, start_point, range)
|
||||
|
||||
//Sends a signal to all machines belonging to a given filter. Should be called by post_signal()
|
||||
/datum/radio_frequency/proc/send_to_filter(obj/source, datum/signal/signal, var/radio_filter, var/turf/start_point = null, var/range = null)
|
||||
if (range && !start_point)
|
||||
return
|
||||
|
||||
for(var/obj/device in devices[radio_filter])
|
||||
if(device == source)
|
||||
continue
|
||||
if(range)
|
||||
var/turf/end_point = get_turf(device)
|
||||
if(!end_point)
|
||||
continue
|
||||
if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range)
|
||||
continue
|
||||
|
||||
device.receive_signal(signal, TRANSMISSION_RADIO, frequency)
|
||||
|
||||
/datum/radio_frequency/proc/add_listener(obj/device as obj, var/radio_filter as text|null)
|
||||
if (!radio_filter)
|
||||
radio_filter = RADIO_DEFAULT
|
||||
//log_admin("add_listener(device=[device],radio_filter=[radio_filter]) frequency=[frequency]")
|
||||
var/list/obj/devices_line = devices[radio_filter]
|
||||
if (!devices_line)
|
||||
devices_line = new
|
||||
devices[radio_filter] = devices_line
|
||||
devices_line+=device
|
||||
// var/list/obj/devices_line___ = devices[filter_str]
|
||||
// var/l = devices_line___.len
|
||||
//log_admin("DEBUG: devices_line.len=[devices_line.len]")
|
||||
//log_admin("DEBUG: devices(filter_str).len=[l]")
|
||||
|
||||
/datum/radio_frequency/proc/remove_listener(obj/device)
|
||||
for (var/devices_filter in devices)
|
||||
var/list/devices_line = devices[devices_filter]
|
||||
devices_line-=device
|
||||
while (null in devices_line)
|
||||
devices_line -= null
|
||||
if (devices_line.len==0)
|
||||
devices -= devices_filter
|
||||
|
||||
/datum/signal
|
||||
var/obj/source
|
||||
|
||||
var/transmission_method = 0 //unused at the moment
|
||||
//0 = wire
|
||||
//1 = radio transmission
|
||||
//2 = subspace transmission
|
||||
|
||||
var/list/data = list()
|
||||
var/encryption
|
||||
|
||||
var/frequency = 0
|
||||
|
||||
/datum/signal/proc/copy_from(datum/signal/model)
|
||||
source = model.source
|
||||
transmission_method = model.transmission_method
|
||||
data = model.data
|
||||
encryption = model.encryption
|
||||
frequency = model.frequency
|
||||
|
||||
/datum/signal/proc/debug_print()
|
||||
if (source)
|
||||
. = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n"
|
||||
else
|
||||
. = "signal = {source = '[source]' ()\n"
|
||||
for (var/i in data)
|
||||
. += "data\[\"[i]\"\] = \"[data[i]]\"\n"
|
||||
if(islist(data[i]))
|
||||
var/list/L = data[i]
|
||||
for(var/t in L)
|
||||
. += "data\[\"[i]\"\] list has: [t]"
|
||||
|
||||
//callback used by objects to react to incoming radio signals
|
||||
/obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
|
||||
return null
|
||||
@@ -1,8 +1,10 @@
|
||||
SUBSYSTEM_DEF(dbcore)
|
||||
name = "Database"
|
||||
flags = SS_TICKER
|
||||
init_stage = INITSTAGE_EARLY
|
||||
wait = 10 // Not seconds because we're running on SS_TICKER
|
||||
init_order = INIT_ORDER_DBCORE
|
||||
runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT
|
||||
priority = FIRE_PRIORITY_DATABASE
|
||||
|
||||
var/failed_connection_timeout = 0
|
||||
|
||||
@@ -41,6 +43,7 @@ SUBSYSTEM_DEF(dbcore)
|
||||
//var/db_daemon_started = FALSE
|
||||
|
||||
/datum/controller/subsystem/dbcore/Initialize()
|
||||
Connect()
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/dbcore/stat_entry(msg)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Sends a message to TGS chat channels.
|
||||
*
|
||||
* message - The message to send.
|
||||
* channel_tag - Required. If "", the message with be sent to all connected (Game-type for TGS3) channels. Otherwise, it will be sent to TGS4 channels with that tag (Delimited by ','s).
|
||||
*/
|
||||
/proc/send2chat(message, channel_tag)
|
||||
if(channel_tag == null || !world.TgsAvailable())
|
||||
return
|
||||
|
||||
var/datum/tgs_version/version = world.TgsVersion()
|
||||
if(channel_tag == "" || version.suite == 3)
|
||||
world.TgsTargetedChatBroadcast(message, FALSE)
|
||||
return
|
||||
|
||||
var/list/channels_to_use = list()
|
||||
for(var/I in world.TgsChatChannelInfo())
|
||||
var/datum/tgs_chat_channel/channel = I
|
||||
var/list/applicable_tags = splittext(channel.tag, ",")
|
||||
if(channel_tag in applicable_tags)
|
||||
channels_to_use += channel
|
||||
|
||||
if(channels_to_use.len)
|
||||
world.TgsChatBroadcast(message, channels_to_use)
|
||||
|
||||
/**
|
||||
* Sends a message to TGS admin chat channels.
|
||||
*
|
||||
* category - The category of the mssage.
|
||||
* message - The message to send.
|
||||
*/
|
||||
/proc/send2adminchat(category, message)
|
||||
category = replacetext(replacetext(category, "\proper", ""), "\improper", "")
|
||||
message = replacetext(replacetext(message, "\proper", ""), "\improper", "")
|
||||
world.TgsTargetedChatBroadcast("[category] | [message]", TRUE)
|
||||
@@ -1,6 +1,7 @@
|
||||
SUBSYSTEM_DEF(events)
|
||||
name = "Events" // VOREStation Edit - This is still the main events subsystem for us.
|
||||
wait = 2 SECONDS
|
||||
init_stage = INITSTAGE_LAST
|
||||
|
||||
var/tmp/list/currentrun = null
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ SUBSYSTEM_DEF(event_ticker)
|
||||
name = "Events (Ticker)"
|
||||
wait = 2 SECONDS
|
||||
runlevels = RUNLEVEL_GAME
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/events
|
||||
)
|
||||
|
||||
// List of `/datum/event2/event`s that are currently active, and receiving process() ticks.
|
||||
var/list/active_events = list()
|
||||
|
||||
@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(game_master)
|
||||
// These are ran before committing to an event.
|
||||
// Returns TRUE if the system is allowed to procede, otherwise returns FALSE.
|
||||
/datum/controller/subsystem/game_master/proc/pre_event_checks(quiet = FALSE)
|
||||
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
|
||||
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
|
||||
if(!quiet)
|
||||
log_game_master("Unable to start event: Ticker is nonexistent, or the game is not ongoing.")
|
||||
return FALSE
|
||||
|
||||
@@ -27,8 +27,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
wait = 2 SECONDS
|
||||
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
init_order = INIT_ORDER_GARBAGE
|
||||
// init_stage = INITSTAGE_EARLY
|
||||
init_stage = INITSTAGE_FIRST
|
||||
|
||||
var/list/collection_timeout = list(GC_FILTER_QUEUE, GC_CHECK_QUEUE, GC_DEL_QUEUE) // deciseconds to wait before moving something up in the queue to the next level
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
//
|
||||
SUBSYSTEM_DEF(holomaps)
|
||||
name = "HoloMiniMaps"
|
||||
init_order = INIT_ORDER_HOLOMAPS
|
||||
flags = SS_NO_FIRE
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/atoms
|
||||
)
|
||||
var/static/holomaps_initialized = FALSE
|
||||
var/static/list/holoMiniMaps = list()
|
||||
var/static/list/extraMiniMaps = list()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBSYSTEM_DEF(input)
|
||||
name = "Input"
|
||||
wait = 1 // SS_TICKER means this runs every tick
|
||||
init_order = INIT_ORDER_INPUT
|
||||
init_stage = INITSTAGE_EARLY
|
||||
flags = SS_TICKER | SS_NO_INIT
|
||||
priority = FIRE_PRIORITY_INPUT
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
SUBSYSTEM_DEF(internal_wiki)
|
||||
name = "Wiki"
|
||||
wait = 1
|
||||
init_order = INIT_ORDER_WIKI
|
||||
//dependencies = list(
|
||||
// /datum/controller/subsystem/chemistry,
|
||||
// /datum/controller/subsystem/plants,
|
||||
// /datum/controller/subsystem/supply
|
||||
//)
|
||||
init_stage = INITSTAGE_LAST
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
VAR_PRIVATE/list/pages = list()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
SUBSYSTEM_DEF(job)
|
||||
name = "Job"
|
||||
init_order = INIT_ORDER_JOB
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping,
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/occupations = list() //List of all jobs
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
SUBSYSTEM_DEF(lighting)
|
||||
name = "Lighting"
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/machines
|
||||
)
|
||||
wait = 1
|
||||
init_order = INIT_ORDER_LIGHTING
|
||||
flags = SS_TICKER
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY // Do some work during lobby waiting period. May as well.
|
||||
var/sun_mult = 1.0
|
||||
@@ -19,8 +21,8 @@ SUBSYSTEM_DEF(lighting)
|
||||
|
||||
|
||||
/datum/controller/subsystem/lighting/Initialize()
|
||||
if(!subsystem_initialized)
|
||||
subsystem_initialized = TRUE
|
||||
if(!initialized)
|
||||
initialized = TRUE
|
||||
create_all_lighting_objects()
|
||||
|
||||
for(var/datum/planet/planet in SSplanets.planets)
|
||||
@@ -177,5 +179,5 @@ SUBSYSTEM_DEF(lighting)
|
||||
/datum/controller/subsystem/lighting
|
||||
|
||||
/datum/controller/subsystem/lighting/Recover()
|
||||
subsystem_initialized = SSlighting.subsystem_initialized
|
||||
initialized = SSlighting.initialized
|
||||
..()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
SUBSYSTEM_DEF(lobby_monitor)
|
||||
name = "Lobby Art"
|
||||
init_order = INIT_ORDER_LOBBY
|
||||
// init_stage = INITSTAGE_EARLY
|
||||
init_stage = INITSTAGE_EARLY
|
||||
flags = SS_NO_INIT
|
||||
wait = 1 SECOND
|
||||
runlevels = ALL
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
|
||||
SUBSYSTEM_DEF(machines)
|
||||
name = "Machines"
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/points_of_interest
|
||||
)
|
||||
priority = FIRE_PRIORITY_MACHINES
|
||||
init_order = INIT_ORDER_MACHINES
|
||||
flags = SS_KEEP_TIMING
|
||||
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
|
||||
|
||||
|
||||
@@ -1,19 +1,32 @@
|
||||
// Handles map-related tasks, mostly here to ensure it does so after the MC initializes.
|
||||
SUBSYSTEM_DEF(mapping)
|
||||
name = "Mapping"
|
||||
init_order = INIT_ORDER_MAPPING
|
||||
//dependencies = list(
|
||||
// /datum/controller/subsystem/job,
|
||||
///datum/controller/subsystem/processing/station,
|
||||
// /datum/controller/subsystem/chemistry
|
||||
// ///datum/controller/subsystem/processing/reagents
|
||||
//)
|
||||
dependencies = list(
|
||||
///datum/controller/subsystem/garbage,
|
||||
/datum/controller/subsystem/vis_overlays,
|
||||
/datum/controller/subsystem/chemistry
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/map_templates = list()
|
||||
var/obj/effect/landmark/engine_loader/engine_loader
|
||||
var/list/shelter_templates = list()
|
||||
|
||||
// TODO: Implement Later
|
||||
var/datum/map/current_map
|
||||
|
||||
/datum/controller/subsystem/mapping/Recover()
|
||||
flags |= SS_NO_INIT // Make extra sure we don't initialize twice.
|
||||
shelter_templates = SSmapping.shelter_templates
|
||||
|
||||
/datum/controller/subsystem/mapping/Initialize()
|
||||
if(subsystem_initialized)
|
||||
if(initialized)
|
||||
return
|
||||
world.max_z_changed() // This is to set up the player z-level list, maxz hasn't actually changed (probably)
|
||||
load_map_templates()
|
||||
@@ -24,6 +37,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
// TODO - Other stuff related to maps and areas could be moved here too. Look at /tg
|
||||
// Lateload Code related to Expedition areas.
|
||||
if(using_map) // VOREStation Edit: Re-enable this.
|
||||
current_map = using_map
|
||||
loadLateMaps()
|
||||
|
||||
if(CONFIG_GET(flag/generate_map)) // VOREStation Edit: Re-order this.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBSYSTEM_DEF(media_tracks)
|
||||
name = "Media Tracks"
|
||||
flags = SS_NO_FIRE
|
||||
init_order = INIT_ORDER_MEDIA_TRACKS
|
||||
init_stage = INITSTAGE_EARLY
|
||||
|
||||
/// Every track, including secret
|
||||
var/list/all_tracks = list()
|
||||
|
||||
@@ -12,6 +12,12 @@ SUBSYSTEM_DEF(mobs)
|
||||
flags = SS_KEEP_TIMING|SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/atoms,
|
||||
/datum/controller/subsystem/points_of_interest,
|
||||
/datum/controller/subsystem/shuttles
|
||||
)
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/log_extensively = FALSE
|
||||
var/list/timelog = list()
|
||||
@@ -101,22 +107,14 @@ SUBSYSTEM_DEF(mobs)
|
||||
log_game(msg)
|
||||
log_world(msg)
|
||||
|
||||
/datum/controller/subsystem/mobs/fail()
|
||||
..()
|
||||
log_recent()
|
||||
|
||||
/datum/controller/subsystem/mobs/critfail()
|
||||
..()
|
||||
log_recent()
|
||||
|
||||
/datum/controller/subsystem/mobs/proc/report_death(var/mob/living/L)
|
||||
if(!L)
|
||||
return
|
||||
if(!L.key || !L.mind)
|
||||
return
|
||||
if(!ticker || !ticker.mode)
|
||||
if(!SSticker || !SSticker.mode)
|
||||
return
|
||||
ticker.mode.check_win()
|
||||
SSticker.mode.check_win()
|
||||
|
||||
// Don't bother with the rest if we've not got a DB to do anything with
|
||||
if(!CONFIG_GET(flag/enable_stat_tracking) || !CONFIG_GET(flag/sql_enabled))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
SUBSYSTEM_DEF(nightshift)
|
||||
name = "Night Shift"
|
||||
init_order = INIT_ORDER_NIGHTSHIFT
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/lighting
|
||||
)
|
||||
priority = FIRE_PRIORITY_NIGHTSHIFT
|
||||
wait = 60 SECONDS
|
||||
flags = SS_NO_TICK_CHECK
|
||||
|
||||
@@ -5,7 +5,9 @@ SUBSYSTEM_DEF(overlays)
|
||||
flags = SS_TICKER
|
||||
wait = 1 // SS_TICKER - Ticks
|
||||
priority = FIRE_PRIORITY_OVERLAYS
|
||||
init_order = INIT_ORDER_OVERLAY
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/atoms
|
||||
)
|
||||
|
||||
/// The queue of atoms that need overlay updates.
|
||||
var/static/tmp/list/queue = list()
|
||||
|
||||
@@ -4,8 +4,12 @@ Readme at code\modules\awaymissions\overmap_renamer\readme.md
|
||||
|
||||
SUBSYSTEM_DEF(overmap_renamer)
|
||||
name = "Overmap Renamer"
|
||||
init_order = INIT_ORDER_MAPRENAME //Loaded very late in initializations. Must come before mapping and objs. Uses both as inputs.
|
||||
runlevels = RUNLEVEL_INIT
|
||||
//Loaded very late in initializations. Must come before mapping and objs. Uses both as inputs.
|
||||
init_stage = INITSTAGE_LAST
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/skybox
|
||||
)
|
||||
runlevels = RUNLEVEL_SETUP
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
SUBSYSTEM_DEF(persistence)
|
||||
name = "Persistence"
|
||||
init_order = INIT_ORDER_PERSISTENCE
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping,
|
||||
/datum/controller/subsystem/atoms,
|
||||
/datum/controller/subsystem/points_of_interest
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/tracking_values = list()
|
||||
var/list/persistence_datums = list()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
SUBSYSTEM_DEF(ping)
|
||||
name = "Ping"
|
||||
priority = FIRE_PRIORITY_PING
|
||||
// init_stage = INITSTAGE_EARLY
|
||||
init_stage = INITSTAGE_EARLY
|
||||
wait = 4 SECONDS
|
||||
flags = SS_NO_INIT
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
SUBSYSTEM_DEF(planets)
|
||||
name = "Planets"
|
||||
init_order = INIT_ORDER_PLANETS
|
||||
priority = FIRE_PRIORITY_PLANETS
|
||||
wait = 2 SECONDS
|
||||
flags = SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/plants
|
||||
)
|
||||
|
||||
var/static/list/planets = list()
|
||||
var/static/list/z_to_planet = list()
|
||||
@@ -75,7 +77,7 @@ SUBSYSTEM_DEF(planets)
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
#ifndef UNIT_TEST // Don't be updating temperatures and such during unit tests
|
||||
#ifndef UNIT_TESTS // Don't be updating temperatures and such during unit tests
|
||||
var/list/needs_temp_update = src.needs_temp_update
|
||||
while(needs_temp_update.len)
|
||||
var/datum/planet/P = needs_temp_update[needs_temp_update.len]
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
SUBSYSTEM_DEF(plants)
|
||||
name = "Plants"
|
||||
init_order = INIT_ORDER_PLANTS
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping
|
||||
)
|
||||
priority = FIRE_PRIORITY_PLANTS
|
||||
wait = PLANT_TICK_TIME
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ SUBSYSTEM_DEF(points_of_interest)
|
||||
name = "Points of Interest"
|
||||
wait = 1 SECONDS
|
||||
priority = FIRE_PRIORITY_POIS
|
||||
init_order = INIT_ORDER_POIS
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT //POIs can be loaded mid-round.
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/holomaps
|
||||
)
|
||||
var/list/obj/effect/landmark/poi_loader/poi_queue = list()
|
||||
|
||||
/datum/controller/subsystem/points_of_interest/Initialize()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(instruments)
|
||||
name = "Instruments"
|
||||
wait = 0.5
|
||||
init_order = INIT_ORDER_INSTRUMENTS
|
||||
flags = SS_KEEP_TIMING
|
||||
priority = FIRE_PRIORITY_INSTRUMENTS
|
||||
/// List of all instrument data, associative id = datum
|
||||
|
||||
@@ -96,14 +96,6 @@ SUBSYSTEM_DEF(processing)
|
||||
log_game(msg)
|
||||
log_world(msg)
|
||||
|
||||
/datum/controller/subsystem/processing/fail()
|
||||
..()
|
||||
log_recent()
|
||||
|
||||
/datum/controller/subsystem/processing/critfail()
|
||||
..()
|
||||
log_recent()
|
||||
|
||||
/datum/proc/DebugSubsystemProcess(var/wait, var/times_fired, var/datum/controller/subsystem/processing/subsystem)
|
||||
subsystem.debug_last_thing = src
|
||||
var/start_tick = world.time
|
||||
|
||||
69
code/controllers/subsystems/profiler.dm
Normal file
69
code/controllers/subsystems/profiler.dm
Normal file
@@ -0,0 +1,69 @@
|
||||
SUBSYSTEM_DEF(profiler)
|
||||
name = "Profiler"
|
||||
init_stage = INITSTAGE_FIRST
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
wait = 300 SECONDS
|
||||
var/fetch_cost = 0
|
||||
var/write_cost = 0
|
||||
|
||||
/datum/controller/subsystem/profiler/stat_entry(msg)
|
||||
msg += "F:[round(fetch_cost,1)]ms"
|
||||
msg += "|W:[round(write_cost,1)]ms"
|
||||
return msg
|
||||
|
||||
/datum/controller/subsystem/profiler/Initialize()
|
||||
if(CONFIG_GET(flag/auto_profile))
|
||||
StartProfiling()
|
||||
else
|
||||
StopProfiling() //Stop the early start profiler
|
||||
wait = CONFIG_GET(number/profiler_interval)
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/profiler/OnConfigLoad()
|
||||
if(CONFIG_GET(flag/auto_profile))
|
||||
StartProfiling()
|
||||
can_fire = TRUE
|
||||
else
|
||||
StopProfiling()
|
||||
can_fire = FALSE
|
||||
|
||||
/datum/controller/subsystem/profiler/fire()
|
||||
DumpFile()
|
||||
|
||||
/datum/controller/subsystem/profiler/Shutdown()
|
||||
if(CONFIG_GET(flag/auto_profile))
|
||||
DumpFile(allow_yield = FALSE)
|
||||
world.Profile(PROFILE_CLEAR, type = "sendmaps")
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/profiler/proc/StartProfiling()
|
||||
world.Profile(PROFILE_START)
|
||||
world.Profile(PROFILE_START, type = "sendmaps")
|
||||
|
||||
/datum/controller/subsystem/profiler/proc/StopProfiling()
|
||||
world.Profile(PROFILE_STOP)
|
||||
world.Profile(PROFILE_STOP, type = "sendmaps")
|
||||
|
||||
/datum/controller/subsystem/profiler/proc/DumpFile(allow_yield = TRUE)
|
||||
var/timer = TICK_USAGE_REAL
|
||||
var/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json")
|
||||
var/current_sendmaps_data = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json")
|
||||
fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(allow_yield)
|
||||
CHECK_TICK
|
||||
|
||||
if(!length(current_profile_data)) //Would be nice to have explicit proc to check this
|
||||
stack_trace("Warning, profiling stopped manually before dump.")
|
||||
var/prof_file = file("[GLOB.log_directory]/profiler/profiler-[round(world.time * 0.1, 10)].json")
|
||||
if(fexists(prof_file))
|
||||
fdel(prof_file)
|
||||
if(!length(current_sendmaps_data)) //Would be nice to have explicit proc to check this
|
||||
stack_trace("Warning, sendmaps profiling stopped manually before dump.")
|
||||
var/sendmaps_file = file("[GLOB.log_directory]/profiler/sendmaps-[round(world.time * 0.1, 10)].json")
|
||||
if(fexists(sendmaps_file))
|
||||
fdel(sendmaps_file)
|
||||
|
||||
timer = TICK_USAGE_REAL
|
||||
WRITE_FILE(prof_file, current_profile_data)
|
||||
WRITE_FILE(sendmaps_file, current_sendmaps_data)
|
||||
write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
@@ -2,11 +2,13 @@
|
||||
SUBSYSTEM_DEF(research)
|
||||
name = "Research"
|
||||
// priority = FIRE_PRIORITY_RESEARCH
|
||||
init_order = INIT_ORDER_RESEARCH
|
||||
wait = 10
|
||||
// dependencies = list(
|
||||
// /datum/controller/subsystem/processing/station,
|
||||
// )
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping
|
||||
)
|
||||
//TECHWEB STATIC
|
||||
var/list/techweb_nodes = list() //associative id = node datum
|
||||
var/list/techweb_designs = list() //associative id = node datum
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
SUBSYSTEM_DEF(robot_sprites)
|
||||
name = "Robot Sprites"
|
||||
init_order = INIT_ORDER_ROBOT_SPRITES
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/garbage
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
var/list/all_cyborg_sprites = list()
|
||||
var/list/cyborg_sprites_by_module = list()
|
||||
|
||||
@@ -5,8 +5,7 @@ SUBSYSTEM_DEF(server_maint)
|
||||
wait = 6
|
||||
flags = SS_POST_FIRE_TIMING
|
||||
priority = FIRE_PRIORITY_SERVER_MAINT
|
||||
init_order = INIT_ORDER_SERVER_MAINT
|
||||
//init_stage = INITSTAGE_EARLY
|
||||
init_stage = INITSTAGE_FIRST
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
||||
var/list/currentrun
|
||||
///Associated list of list names to lists to clear of nulls
|
||||
|
||||
@@ -8,7 +8,11 @@ SUBSYSTEM_DEF(shuttles)
|
||||
name = "Shuttles"
|
||||
wait = 2 SECONDS
|
||||
priority = FIRE_PRIORITY_SHUTTLES
|
||||
init_order = INIT_ORDER_SHUTTLES
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/machines,
|
||||
/datum/controller/subsystem/atoms,
|
||||
/datum/controller/subsystem/radio
|
||||
)
|
||||
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
|
||||
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//Exists to handle a few global variables that change enough to justify this. Technically a parallax, but it exhibits a skybox effect.
|
||||
SUBSYSTEM_DEF(skybox)
|
||||
name = "Space skybox"
|
||||
init_order = INIT_ORDER_SKYBOX
|
||||
init_stage = INITSTAGE_LAST
|
||||
flags = SS_NO_FIRE
|
||||
var/static/list/skybox_cache = list()
|
||||
|
||||
@@ -64,7 +64,7 @@ SUBSYSTEM_DEF(skybox)
|
||||
speedspace_cache["EW_[i]"] = MA
|
||||
|
||||
//Over-the-edge images
|
||||
for (var/dir in GLOB.alldirs)
|
||||
for (var/dir in ALL_POSSIBLE_DIRS)
|
||||
var/mutable_appearance/MA = new(normal_space)
|
||||
var/matrix/M = matrix()
|
||||
var/horizontal = (dir & (WEST|EAST))
|
||||
@@ -93,7 +93,7 @@ SUBSYSTEM_DEF(skybox)
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/skybox/proc/get_skybox(z)
|
||||
if(!subsystem_initialized)
|
||||
if(!initialized)
|
||||
return // WAIT
|
||||
if(!skybox_cache["[z]"])
|
||||
skybox_cache["[z]"] = generate_skybox(z)
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
SUBSYSTEM_DEF(sounds)
|
||||
name = "Sounds"
|
||||
flags = SS_NO_FIRE
|
||||
init_order = INIT_ORDER_SOUNDS
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping
|
||||
)
|
||||
var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels
|
||||
/// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up.
|
||||
var/static/random_channels_min = 50
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
// however this makes it a lot easier to test, and it is natively supported by BYOND.
|
||||
SUBSYSTEM_DEF(sqlite)
|
||||
name = "SQLite"
|
||||
init_order = INIT_ORDER_SQLITE
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/dbcore
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
var/database/sqlite_db = null
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
//
|
||||
SUBSYSTEM_DEF(starmover)
|
||||
name = "Shuttle Star Movement"
|
||||
init_order = INIT_ORDER_STARMOVER
|
||||
priority = FIRE_PRIORITY_STARMOVER
|
||||
wait = 1 // This needs to be done pretty quickly
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/points_of_interest
|
||||
)
|
||||
var/list/zqueue = list()
|
||||
var/list/current_movement = null
|
||||
//list used to track which zlevels are being 'moved' by the proc below
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
SUBSYSTEM_DEF(statpanels)
|
||||
name = "Stat Panels"
|
||||
wait = 4
|
||||
init_order = INIT_ORDER_STATPANELS
|
||||
//init_stage = INITSTAGE_EARLY
|
||||
priority = FIRE_PRIORITY_STATPANEL
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
flags = SS_NO_INIT
|
||||
@@ -42,6 +40,15 @@ SUBSYSTEM_DEF(statpanels)
|
||||
var/ETA = emergency_shuttle.get_status_panel_eta()
|
||||
if(ETA)
|
||||
global_data += "[ETA]"
|
||||
|
||||
if(SSticker.reboot_timer)
|
||||
var/reboot_time = timeleft(SSticker.reboot_timer)
|
||||
if(reboot_time)
|
||||
global_data += "Reboot: [DisplayTimeText(reboot_time, 1)]"
|
||||
// admin must have delayed round end
|
||||
else if(SSticker.ready_for_reboot)
|
||||
global_data += "Reboot: DELAYED"
|
||||
|
||||
src.currentrun = GLOB.clients.Copy()
|
||||
mc_data = null
|
||||
|
||||
@@ -140,7 +147,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
var/coord_entry = COORD(eye_turf)
|
||||
if(!mc_data)
|
||||
generate_mc_data()
|
||||
target.stat_panel.send_message("update_mc", list(mc_data = mc_data, coord_entry = coord_entry))
|
||||
target.stat_panel.send_message("update_mc", list("mc_data" = mc_data, "coord_entry" = coord_entry))
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_examine_tab(client/target)
|
||||
var/description_holders = target.description_holders
|
||||
@@ -206,13 +213,31 @@ SUBSYSTEM_DEF(statpanels)
|
||||
list("CPU:", world.cpu),
|
||||
list("Instances:", "[num2text(world.contents.len, 10)]"),
|
||||
list("World Time:", "[world.time]"),
|
||||
list("Globals:", GLOB.stat_entry(), "\ref[GLOB]"),
|
||||
list("[config]:", config.stat_entry(), "\ref[config]"),
|
||||
list("Globals:", GLOB.stat_entry(), text_ref(GLOB)),
|
||||
list("[config]:", config.stat_entry(), text_ref(config)),
|
||||
list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)"),
|
||||
list("Master Controller:", Master.stat_entry(), "\ref[Master]"),
|
||||
list("Failsafe Controller:", Failsafe.stat_entry(), "\ref[Failsafe]"),
|
||||
list("Master Controller:", Master.stat_entry(), text_ref(Master)),
|
||||
list("Failsafe Controller:", Failsafe.stat_entry(), text_ref(Failsafe)),
|
||||
list("","")
|
||||
)
|
||||
#if defined(MC_TAB_TRACY_INFO) || defined(SPACEMAN_DMM)
|
||||
var/static/tracy_dll
|
||||
var/static/tracy_present
|
||||
if(isnull(tracy_dll))
|
||||
tracy_dll = TRACY_DLL_PATH
|
||||
tracy_present = fexists(tracy_dll)
|
||||
if(tracy_present)
|
||||
if(Tracy.enabled)
|
||||
mc_data.Insert(2, list(list("byond-tracy:", "Active (reason: [Tracy.init_reason || "N/A"])")))
|
||||
else if(Tracy.error)
|
||||
mc_data.Insert(2, list(list("byond-tracy:", "Errored ([Tracy.error])")))
|
||||
else if(fexists(TRACY_ENABLE_PATH))
|
||||
mc_data.Insert(2, list(list("byond-tracy:", "Queued for next round")))
|
||||
else
|
||||
mc_data.Insert(2, list(list("byond-tracy:", "Inactive")))
|
||||
else
|
||||
mc_data.Insert(2, list(list("byond-tracy:", "[tracy_dll] not present")))
|
||||
#endif
|
||||
for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems)
|
||||
mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]")
|
||||
mc_data[++mc_data.len] = list("Camera Net", "Cameras: [global.cameranet.cameras.len] | Chunks: [global.cameranet.chunks.len]", "\ref[global.cameranet]")
|
||||
|
||||
@@ -1,59 +1,85 @@
|
||||
//
|
||||
// Ticker controls the state of the game, being responsible for round start, game mode, and round end.
|
||||
//
|
||||
SUBSYSTEM_DEF(ticker)
|
||||
name = "Gameticker"
|
||||
wait = 2 SECONDS
|
||||
init_order = INIT_ORDER_TICKER
|
||||
name = "Ticker"
|
||||
priority = FIRE_PRIORITY_TICKER
|
||||
flags = SS_NO_TICK_CHECK | SS_KEEP_TIMING
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME // Every runlevel!
|
||||
flags = SS_KEEP_TIMING
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME
|
||||
|
||||
var/const/restart_timeout = 4 MINUTES // Default time to wait before rebooting in desiseconds.
|
||||
var/current_state = GAME_STATE_INIT // We aren't even at pregame yet // TODO replace with CURRENT_GAME_STATE
|
||||
/// state of current round (used by process()) Use the defines GAME_STATE_* !
|
||||
var/current_state = GAME_STATE_STARTUP
|
||||
/// Boolean to track if round should be forcibly ended next ticker tick.
|
||||
/// Set by admin intervention ([ADMIN_FORCE_END_ROUND])
|
||||
/// or a "round-ending" event, like summoning Nar'Sie, a blob victory, the nuke going off, etc. ([FORCE_END_ROUND])
|
||||
var/force_ending = END_ROUND_AS_NORMAL
|
||||
/// If TRUE, there is no lobby phase, the game starts immediately.
|
||||
var/start_immediately = FALSE
|
||||
/// Boolean to track and check if our subsystem setup is done.
|
||||
var/setup_done = FALSE
|
||||
|
||||
/* Relies upon the following globals (TODO move those in here) */
|
||||
// var/GLOB.master_mode = "extended" //The underlying game mode (so "secret" or the voted mode).
|
||||
// Set by SSvote when VOTE_GAMEMODE finishes.
|
||||
// var/round_progressing = 1 //Whether the lobby clock is ticking down.
|
||||
var/hide_mode = FALSE
|
||||
var/datum/game_mode/mode = null
|
||||
|
||||
var/pregame_timeleft = 0 // Time remaining until game starts in seconds. Set by config
|
||||
var/start_immediately = FALSE // If true there is no lobby phase, the game starts immediately.
|
||||
var/login_music //music played in pregame lobby
|
||||
var/round_end_sound //music/jingle played when the world reboots
|
||||
var/round_end_sound_sent = TRUE //If all clients have loaded it
|
||||
|
||||
var/hide_mode = FALSE // If the true game mode should be hidden (because we chose "secret")
|
||||
var/datum/game_mode/mode = null // The actual gamemode, if selected.
|
||||
var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking.
|
||||
|
||||
var/end_game_state = END_GAME_NOT_OVER // Track where we are ending game/round
|
||||
var/restart_timeleft // Time remaining until restart in desiseconds
|
||||
var/last_restart_notify // world.time of last restart warning.
|
||||
var/delay_end = FALSE // If set, the round will not restart on its own.
|
||||
var/delay_end = FALSE //if set true, the round will not restart on it's own
|
||||
var/admin_delay_notice = "" //a message to display to anyone who tries to restart the world after a delay
|
||||
var/ready_for_reboot = FALSE //all roundend preparation done with, all that's left is reboot
|
||||
|
||||
// var/login_music // music played in pregame lobby // VOREStation Edit - We do music differently
|
||||
var/tipped = FALSE //Did we broadcast the tip of the day yet?
|
||||
var/selected_tip // What will be the tip of the day?
|
||||
|
||||
var/list/datum/mind/minds = list() // The people in the game. Used for objective tracking.
|
||||
var/timeLeft //pregame timer
|
||||
var/start_at
|
||||
|
||||
var/random_players = FALSE // If set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
|
||||
var/gametime_offset = 432000 //Deciseconds to add to world.time for station time.
|
||||
var/station_time_rate_multiplier = 12 //factor of station time progressal vs real time.
|
||||
|
||||
// TODO - Should this go here or in the job subsystem?
|
||||
var/triai = FALSE // Global flag for Triumvirate AI being enabled
|
||||
/// Num of players, used for pregame stats on statpanel
|
||||
var/totalPlayers = 0
|
||||
/// Num of ready players, used for pregame stats on statpanel (only viewable by admins)
|
||||
var/totalPlayersReady = 0
|
||||
/// Num of ready admins, used for pregame stats on statpanel (only viewable by admins)
|
||||
var/total_admins_ready = 0
|
||||
|
||||
//station_explosion used to be a variable for every mob's hud. Which was a waste!
|
||||
//Now we have a general cinematic centrally held within the gameticker....far more efficient!
|
||||
var/obj/screen/cinematic = null
|
||||
var/queue_delay = 0
|
||||
var/list/queued_players = list() //used for join queues when the server exceeds the hard population cap
|
||||
|
||||
/// What is going to be reported to other stations at end of round?
|
||||
var/news_report
|
||||
|
||||
|
||||
var/roundend_check_paused = FALSE
|
||||
|
||||
var/round_start_time = 0
|
||||
var/list/round_start_events
|
||||
var/list/round_end_events
|
||||
var/mode_result = "undefined"
|
||||
var/end_state = "undefined"
|
||||
|
||||
/// People who have been commended and will receive a heart
|
||||
var/list/hearts
|
||||
|
||||
/// Why an emergency shuttle was called
|
||||
var/emergency_reason
|
||||
|
||||
// This global variable exists for legacy support so we don't have to rename every 'ticker' to 'SSticker' yet.
|
||||
var/global/datum/controller/subsystem/ticker/ticker
|
||||
/datum/controller/subsystem/ticker/PreInit()
|
||||
global.ticker = src // TODO - Remove this! Change everything to point at SSticker intead
|
||||
/// ID of round reboot timer, if it exists
|
||||
var/reboot_timer = null
|
||||
|
||||
/// ### LEGACY VARS ###
|
||||
/// Default time to wait before rebooting in desiseconds.
|
||||
var/const/restart_timeout = 4 MINUTES
|
||||
/// Track where we are ending game/round
|
||||
var/end_game_state = END_GAME_NOT_OVER
|
||||
/// Time remaining until restart in desiseconds
|
||||
var/restart_timeleft
|
||||
/// world.time of last restart warning.
|
||||
var/last_restart_notify
|
||||
|
||||
/datum/controller/subsystem/ticker/Initialize()
|
||||
pregame_timeleft = CONFIG_GET(number/pregame_time)
|
||||
send2mainirc("Server lobby is loaded and open at byond://[CONFIG_GET(string/serverurl) ? CONFIG_GET(string/serverurl) : (CONFIG_GET(string/server) ? CONFIG_GET(string/server) : "[world.address]:[world.port]")]")
|
||||
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_ROUNDPREP,
|
||||
list(
|
||||
@@ -61,63 +87,183 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
"url" = get_world_url()
|
||||
)
|
||||
)
|
||||
GLOB.autospeaker = new (null, FALSE, null, null, TRUE) //Set up Global Announcer
|
||||
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/ticker/fire(resumed = FALSE)
|
||||
switch(current_state)
|
||||
if(GAME_STATE_INIT)
|
||||
pregame_welcome()
|
||||
if(GAME_STATE_STARTUP)
|
||||
if(Master.initializations_finished_with_no_players_logged_in)
|
||||
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
|
||||
for(var/client/C in GLOB.clients)
|
||||
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
|
||||
to_chat(world, span_notice("<b>Welcome to [station_name()]!</b>"))
|
||||
current_state = GAME_STATE_PREGAME
|
||||
SEND_SIGNAL(src, COMSIG_TICKER_ENTER_PREGAME)
|
||||
|
||||
fire()
|
||||
if(GAME_STATE_PREGAME)
|
||||
pregame_tick()
|
||||
//lobby stats for statpanels
|
||||
if(isnull(timeLeft))
|
||||
timeLeft = max(0,start_at - world.time)
|
||||
totalPlayers = LAZYLEN(GLOB.new_player_list)
|
||||
totalPlayersReady = 0
|
||||
total_admins_ready = 0
|
||||
for(var/mob/new_player/player as anything in GLOB.new_player_list)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY)
|
||||
++totalPlayersReady
|
||||
if(player.client?.holder)
|
||||
++total_admins_ready
|
||||
|
||||
if(start_immediately)
|
||||
timeLeft = 0
|
||||
|
||||
//countdown
|
||||
if(timeLeft < 0)
|
||||
return
|
||||
timeLeft -= wait
|
||||
|
||||
//if(timeLeft <= 300 && !tipped)
|
||||
// send_tip_of_the_round(world, selected_tip)
|
||||
// tipped = TRUE
|
||||
|
||||
if(timeLeft <= 0)
|
||||
SEND_SIGNAL(src, COMSIG_TICKER_ENTER_SETTING_UP)
|
||||
current_state = GAME_STATE_SETTING_UP
|
||||
Master.SetRunLevel(RUNLEVEL_SETUP)
|
||||
if(start_immediately)
|
||||
fire()
|
||||
|
||||
if(GAME_STATE_SETTING_UP)
|
||||
setup_tick()
|
||||
if(!setup())
|
||||
//setup failed
|
||||
current_state = GAME_STATE_STARTUP
|
||||
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
|
||||
timeLeft = null
|
||||
Master.SetRunLevel(RUNLEVEL_LOBBY)
|
||||
SEND_SIGNAL(src, COMSIG_TICKER_ERROR_SETTING_UP)
|
||||
|
||||
if(GAME_STATE_PLAYING)
|
||||
playing_tick()
|
||||
mode.process() // So THIS is where we run mode.process() huh? Okay
|
||||
|
||||
if(mode.explosion_in_progress)
|
||||
return // wait until explosion is done.
|
||||
|
||||
if(force_ending)
|
||||
current_state = GAME_STATE_FINISHED
|
||||
declare_completion(force_ending)
|
||||
Master.SetRunLevel(RUNLEVEL_POSTGAME)
|
||||
else
|
||||
// Calculate if game and/or mode are finished (Complicated by the continuous_rounds config option)
|
||||
var/game_finished = FALSE
|
||||
var/mode_finished = FALSE
|
||||
if (CONFIG_GET(flag/continuous_rounds)) // Game keeps going after mode ends.
|
||||
game_finished = (emergency_shuttle.returned() || mode.station_was_nuked)
|
||||
mode_finished = ((end_game_state >= END_GAME_MODE_FINISHED) || mode.check_finished()) // Short circuit if already finished.
|
||||
else // Game ends when mode does
|
||||
game_finished = (mode.check_finished() || (emergency_shuttle.returned() && emergency_shuttle.evac == 1)) || GLOB.universe_has_ended
|
||||
mode_finished = game_finished
|
||||
|
||||
if(game_finished && mode_finished)
|
||||
end_game_state = END_GAME_READY_TO_END
|
||||
current_state = GAME_STATE_FINISHED
|
||||
Master.SetRunLevel(RUNLEVEL_POSTGAME)
|
||||
INVOKE_ASYNC(src, PROC_REF(declare_completion))
|
||||
else if (mode_finished && (end_game_state < END_GAME_MODE_FINISHED))
|
||||
end_game_state = END_GAME_MODE_FINISHED // Only do this cleanup once!
|
||||
mode.cleanup()
|
||||
//call a transfer shuttle vote
|
||||
to_world(span_boldannounce("The round has ended!"))
|
||||
SSvote.start_vote(new /datum/vote/crew_transfer)
|
||||
|
||||
// FIXME: IMPROVE THIS LATER!
|
||||
if(GAME_STATE_FINISHED)
|
||||
post_game_tick()
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/pregame_welcome()
|
||||
to_world(span_boldannounce(span_notice("<em>Welcome to the pregame lobby!</em>")))
|
||||
to_world(span_boldannounce(span_notice("Please set up your character and select ready. The round will start in [pregame_timeleft] seconds.")))
|
||||
world << sound('sound/misc/server-ready.ogg', volume = 100)
|
||||
if (world.time - last_restart_notify >= 1 MINUTE && !delay_end)
|
||||
to_world(span_boldannounce("Restarting in [round(restart_timeleft/600, 1)] minute\s."))
|
||||
last_restart_notify = world.time
|
||||
|
||||
// Called during GAME_STATE_PREGAME (RUNLEVEL_LOBBY)
|
||||
/datum/controller/subsystem/ticker/proc/pregame_tick()
|
||||
if(GLOB.round_progressing && last_fire)
|
||||
pregame_timeleft -= (world.time - last_fire) / (1 SECOND)
|
||||
/datum/controller/subsystem/ticker/proc/setup()
|
||||
to_chat(world, span_boldannounce("Starting game..."))
|
||||
var/init_start = world.timeofday
|
||||
|
||||
if(start_immediately)
|
||||
pregame_timeleft = 0
|
||||
else if(SSvote.active_vote)
|
||||
return // vote still going, wait for it.
|
||||
CHECK_TICK
|
||||
setup_choose_gamemode()
|
||||
// TODO
|
||||
|
||||
// Time to start the game!
|
||||
if(pregame_timeleft <= 0)
|
||||
current_state = GAME_STATE_SETTING_UP
|
||||
Master.SetRunLevel(RUNLEVEL_SETUP)
|
||||
if(start_immediately)
|
||||
fire() // Don't wait for next tick, do it now!
|
||||
return
|
||||
CHECK_TICK
|
||||
setup_economy()
|
||||
create_characters() //Create player characters
|
||||
collect_minds()
|
||||
equip_characters()
|
||||
|
||||
//if(pregame_timeleft <= CONFIG_GET(number/vote_autogamemode_timeleft) && !SSvote.gamemode_vote_called) //CHOMPEdit
|
||||
//SSvote.autogamemode() // Start the game mode vote (if we haven't had one already) //CHOMPEdit
|
||||
// data_core.manifest()
|
||||
|
||||
// Called during GAME_STATE_SETTING_UP (RUNLEVEL_SETUP)
|
||||
/datum/controller/subsystem/ticker/proc/setup_tick(resumed = FALSE)
|
||||
round_start_time = world.time // otherwise round_start_time would be 0 for the signals
|
||||
if(!setup_choose_gamemode())
|
||||
// It failed, go back to lobby state and re-send the welcome message
|
||||
pregame_timeleft = CONFIG_GET(number/pregame_time)
|
||||
// SSvote.gamemode_vote_called = FALSE // Allow another autogamemode vote
|
||||
current_state = GAME_STATE_PREGAME
|
||||
Master.SetRunLevel(RUNLEVEL_LOBBY)
|
||||
pregame_welcome()
|
||||
return
|
||||
// If we got this far we succeeded in picking a game mode. Punch it!
|
||||
setup_startgame()
|
||||
return
|
||||
for(var/I in round_start_events)
|
||||
var/datum/callback/cb = I
|
||||
cb.InvokeAsync()
|
||||
LAZYCLEARLIST(round_start_events)
|
||||
|
||||
round_start_time = world.time //otherwise round_start_time would be 0 for the signals
|
||||
SEND_SIGNAL(src, COMSIG_TICKER_ROUND_STARTING, world.time)
|
||||
callHook("roundstart")
|
||||
|
||||
log_world("Game start took [(world.timeofday - init_start)/10]s")
|
||||
INVOKE_ASYNC(SSdbcore, TYPE_PROC_REF(/datum/controller/subsystem/dbcore,SetRoundStart))
|
||||
|
||||
to_chat(world, span_notice(span_bold("Welcome to [station_name()], enjoy your stay!")))
|
||||
world << sound('sound/AI/welcome.ogg') // Skie
|
||||
//SEND_SOUND(world, sound(SSstation.announcer.get_rand_welcome_sound()))
|
||||
|
||||
current_state = GAME_STATE_PLAYING
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
|
||||
//Holiday Round-start stuff ~Carn
|
||||
Holiday_Game_Start()
|
||||
|
||||
// TODO END
|
||||
|
||||
PostSetup()
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/PostSetup()
|
||||
set waitfor = FALSE
|
||||
mode.post_setup()
|
||||
// TODO
|
||||
|
||||
var/list/adm = get_admin_counts()
|
||||
var/list/allmins = adm["present"]
|
||||
// TODO: IMPLEMENT: send2adminchat("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]" : ""] has started[allmins.len ? ".":" with no active admins online!"]")
|
||||
if(!allmins.len)
|
||||
send2adminirc("A round has started with no admins online.")
|
||||
|
||||
setup_done = TRUE
|
||||
// TODO START
|
||||
|
||||
// TODO END
|
||||
for(var/obj/effect/landmark/start/S in GLOB.landmarks_list)
|
||||
//Deleting Startpoints but we need the ai point to AI-ize people later
|
||||
if (S.name != "AI")
|
||||
qdel(S)
|
||||
|
||||
if(CONFIG_GET(flag/sql_enabled))
|
||||
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE
|
||||
|
||||
//These callbacks will fire after roundstart key transfer
|
||||
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)
|
||||
if(!HasRoundStarted())
|
||||
LAZYADD(round_start_events, cb)
|
||||
else
|
||||
cb.InvokeAsync()
|
||||
|
||||
//These callbacks will fire before roundend report
|
||||
/datum/controller/subsystem/ticker/proc/OnRoundend(datum/callback/cb)
|
||||
if(current_state >= GAME_STATE_FINISHED)
|
||||
cb.InvokeAsync()
|
||||
else
|
||||
LAZYADD(round_end_events, cb)
|
||||
|
||||
// Formerly the first half of setup() - The part that chooses the game mode.
|
||||
// Returns 0 if failed to pick a mode, otherwise 1
|
||||
@@ -170,74 +316,6 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
src.mode.announce()
|
||||
return 1
|
||||
|
||||
// Formerly the second half of setup() - The part that actually initializes everything and starts the game.
|
||||
/datum/controller/subsystem/ticker/proc/setup_startgame()
|
||||
setup_economy()
|
||||
create_characters() //Create player characters and transfer them.
|
||||
collect_minds()
|
||||
equip_characters()
|
||||
// data_core.manifest()
|
||||
|
||||
callHook("roundstart")
|
||||
for(var/I in round_start_events)
|
||||
var/datum/callback/cb = I
|
||||
cb.InvokeAsync()
|
||||
LAZYCLEARLIST(round_start_events)
|
||||
|
||||
spawn(0)//Forking here so we dont have to wait for this to finish
|
||||
mode.post_setup()
|
||||
//Cleanup some stuff
|
||||
for(var/obj/effect/landmark/start/S in GLOB.landmarks_list)
|
||||
//Deleting Startpoints but we need the ai point to AI-ize people later
|
||||
if (S.name != "AI")
|
||||
qdel(S)
|
||||
to_world(span_boldannounce(span_notice("<em>Enjoy the game!</em>")))
|
||||
world << sound('sound/AI/welcome.ogg') // Skie
|
||||
//Holiday Round-start stuff ~Carn
|
||||
Holiday_Game_Start()
|
||||
|
||||
var/list/adm = get_admin_counts()
|
||||
if(adm["total"] == 0)
|
||||
send2adminirc("A round has started with no admins online.")
|
||||
|
||||
current_state = GAME_STATE_PLAYING
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
|
||||
if(CONFIG_GET(flag/sql_enabled))
|
||||
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
// Called during GAME_STATE_PLAYING (RUNLEVEL_GAME)
|
||||
/datum/controller/subsystem/ticker/proc/playing_tick(resumed = FALSE)
|
||||
mode.process() // So THIS is where we run mode.process() huh? Okay
|
||||
|
||||
if(mode.explosion_in_progress)
|
||||
return // wait until explosion is done.
|
||||
|
||||
// Calculate if game and/or mode are finished (Complicated by the continuous_rounds config option)
|
||||
var/game_finished = FALSE
|
||||
var/mode_finished = FALSE
|
||||
if (CONFIG_GET(flag/continuous_rounds)) // Game keeps going after mode ends.
|
||||
game_finished = (emergency_shuttle.returned() || mode.station_was_nuked)
|
||||
mode_finished = ((end_game_state >= END_GAME_MODE_FINISHED) || mode.check_finished()) // Short circuit if already finished.
|
||||
else // Game ends when mode does
|
||||
game_finished = (mode.check_finished() || (emergency_shuttle.returned() && emergency_shuttle.evac == 1)) || GLOB.universe_has_ended
|
||||
mode_finished = game_finished
|
||||
|
||||
if(game_finished && mode_finished)
|
||||
end_game_state = END_GAME_READY_TO_END
|
||||
current_state = GAME_STATE_FINISHED
|
||||
Master.SetRunLevel(RUNLEVEL_POSTGAME)
|
||||
INVOKE_ASYNC(src, PROC_REF(declare_completion))
|
||||
else if (mode_finished && (end_game_state < END_GAME_MODE_FINISHED))
|
||||
end_game_state = END_GAME_MODE_FINISHED // Only do this cleanup once!
|
||||
mode.cleanup()
|
||||
//call a transfer shuttle vote
|
||||
to_world(span_boldannounce("The round has ended!"))
|
||||
SSvote.start_vote(new /datum/vote/crew_transfer)
|
||||
|
||||
// Called during GAME_STATE_FINISHED (RUNLEVEL_POSTGAME)
|
||||
/datum/controller/subsystem/ticker/proc/post_game_tick()
|
||||
switch(end_game_state)
|
||||
@@ -259,148 +337,6 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
|
||||
end_game_state = END_GAME_ENDING
|
||||
return
|
||||
if(END_GAME_ENDING)
|
||||
restart_timeleft -= (world.time - last_fire)
|
||||
if(delay_end)
|
||||
to_world(span_boldannounce("An admin has delayed the round end."))
|
||||
end_game_state = END_GAME_DELAYED
|
||||
else if(restart_timeleft <= 0)
|
||||
to_world(span_boldannounce("Restarting world!"))
|
||||
sleep(5)
|
||||
world.Reboot()
|
||||
else if (world.time - last_restart_notify >= 1 MINUTE)
|
||||
to_world(span_boldannounce("Restarting in [round(restart_timeleft/600, 1)] minute\s."))
|
||||
last_restart_notify = world.time
|
||||
return
|
||||
if(END_GAME_DELAYED)
|
||||
restart_timeleft -= (world.time - last_fire)
|
||||
if(!delay_end)
|
||||
end_game_state = END_GAME_ENDING
|
||||
else
|
||||
log_error("Ticker arrived at round end in an unexpected endgame state '[end_game_state]'.")
|
||||
end_game_state = END_GAME_READY_TO_END
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// These two below are not used! But they could be
|
||||
|
||||
// Use these preferentially to directly examining ticker.current_state to help prepare for transition to ticker as subsystem!
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/PreRoundStart()
|
||||
return (current_state < GAME_STATE_PLAYING)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/IsSettingUp()
|
||||
return (current_state == GAME_STATE_SETTING_UP)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/IsRoundInProgress()
|
||||
return (current_state == GAME_STATE_PLAYING)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
|
||||
return (current_state >= GAME_STATE_PLAYING)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HELPER PROCS!
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//Plus it provides an easy way to make cinematics for other events. Just use this as a template :)
|
||||
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(var/station_missed=0, var/override = null)
|
||||
if( cinematic ) return //already a cinematic in progress!
|
||||
|
||||
//initialise our cinematic screen object
|
||||
cinematic = new(src)
|
||||
cinematic.icon = 'icons/effects/station_explosion.dmi'
|
||||
cinematic.icon_state = "station_intact"
|
||||
cinematic.layer = 100
|
||||
cinematic.plane = PLANE_PLAYER_HUD
|
||||
cinematic.mouse_opacity = 0
|
||||
cinematic.screen_loc = "1,0"
|
||||
|
||||
var/obj/structure/bed/temp_buckle = new(src)
|
||||
//Incredibly hackish. It creates a bed within the gameticker (lol) to stop mobs running around
|
||||
if(station_missed)
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
M.buckled = temp_buckle //buckles the mob so it can't do anything
|
||||
if(M.client)
|
||||
M.client.screen += cinematic //show every client the cinematic
|
||||
else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived"
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
M.buckled = temp_buckle
|
||||
if(M.client)
|
||||
M.client.screen += cinematic
|
||||
|
||||
switch(M.z)
|
||||
if(0) //inside a crate or something
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && (T.z in using_map.station_levels)) //we don't use M.death(0) because it calls a for(/mob) loop and
|
||||
M.health = 0
|
||||
M.set_stat(DEAD)
|
||||
if(1) //on a z-level 1 turf.
|
||||
M.health = 0
|
||||
M.set_stat(DEAD)
|
||||
|
||||
//Now animate the cinematic
|
||||
switch(station_missed)
|
||||
if(1) //nuke was nearby but (mostly) missed
|
||||
if( mode && !override )
|
||||
override = mode.name
|
||||
switch( override )
|
||||
if("mercenary") //Nuke wasn't on station when it blew up
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
flick("station_intact_fade_red",cinematic)
|
||||
cinematic.icon_state = "summary_nukefail"
|
||||
else
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
//flick("end",cinematic)
|
||||
|
||||
|
||||
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
sleep(50)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
|
||||
|
||||
else //station was destroyed
|
||||
if( mode && !override )
|
||||
override = mode.name
|
||||
switch( override )
|
||||
if("mercenary") //Nuke Ops successfully bombed the station
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
cinematic.icon_state = "summary_nukewin"
|
||||
if("AI malfunction") //Malf (screen,explosion,summary)
|
||||
flick("intro_malf",cinematic)
|
||||
sleep(76)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
cinematic.icon_state = "summary_malf"
|
||||
if("blob") //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
else //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red", cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
if(M.loc.z in using_map.station_levels)
|
||||
M.death()//No mercy
|
||||
//If its actually the end of the round, wait for it to end.
|
||||
//Otherwise if its a verb it will continue on afterwards.
|
||||
sleep(300)
|
||||
|
||||
if(cinematic) qdel(cinematic) //end the cinematic
|
||||
if(temp_buckle) qdel(temp_buckle) //release everybody
|
||||
return
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/create_characters()
|
||||
for(var/mob/new_player/player in GLOB.player_list)
|
||||
@@ -431,12 +367,13 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
// If they're a carbon, they can get manifested
|
||||
if(J?.mob_type & JOB_CARBON)
|
||||
GLOB.data_core.manifest_inject(new_char)
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/collect_minds()
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(player.mind)
|
||||
minds += player.mind
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/equip_characters()
|
||||
var/captainless=1
|
||||
@@ -457,147 +394,107 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
if(imp.handle_implant(player,player.zone_sel.selecting))
|
||||
imp.post_implant(player)
|
||||
//VOREStation Addition End
|
||||
CHECK_TICK
|
||||
if(captainless)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M))
|
||||
to_chat(M, span_notice("Site Management is not forced on anyone."))
|
||||
|
||||
///Whether the game has started, including roundend.
|
||||
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
|
||||
return current_state >= GAME_STATE_PLAYING
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/declare_completion()
|
||||
to_world(span_filter_system("<br><br><br><H1>A round of [mode.name] has ended!</H1>"))
|
||||
for(var/mob/Player in GLOB.player_list)
|
||||
if(Player.mind && !isnewplayer(Player))
|
||||
if(Player.stat != DEAD)
|
||||
var/turf/playerTurf = get_turf(Player)
|
||||
if(emergency_shuttle.departed && emergency_shuttle.evac)
|
||||
if(isNotAdminLevel(playerTurf.z))
|
||||
to_chat(Player, span_filter_system(span_blue(span_bold("You survived the round, but remained on [station_name()] as [Player.real_name]."))))
|
||||
else
|
||||
to_chat(Player, span_filter_system(span_green(span_bold("You managed to survive the events on [station_name()] as [Player.real_name]."))))
|
||||
else if(isAdminLevel(playerTurf.z))
|
||||
to_chat(Player, span_filter_system(span_green(span_bold("You successfully underwent crew transfer after events on [station_name()] as [Player.real_name]."))))
|
||||
else if(issilicon(Player))
|
||||
to_chat(Player, span_filter_system(span_green(span_bold("You remain operational after the events on [station_name()] as [Player.real_name]."))))
|
||||
else
|
||||
to_chat(Player, span_filter_system(span_blue(span_bold("You missed the crew transfer after the events on [station_name()] as [Player.real_name]."))))
|
||||
else
|
||||
if(isobserver(Player))
|
||||
var/mob/observer/dead/O = Player
|
||||
if(!O.started_as_observer)
|
||||
to_chat(Player, span_filter_system(span_red(span_bold("You did not survive the events on [station_name()]..."))))
|
||||
else
|
||||
to_chat(Player, span_filter_system(span_red(span_bold("You did not survive the events on [station_name()]..."))))
|
||||
to_world(span_filter_system("<br>"))
|
||||
///Whether the game is currently in progress, excluding roundend
|
||||
/datum/controller/subsystem/ticker/proc/IsRoundInProgress()
|
||||
return current_state == GAME_STATE_PLAYING
|
||||
|
||||
for (var/mob/living/silicon/ai/aiPlayer in GLOB.mob_list)
|
||||
if (aiPlayer.stat != 2)
|
||||
to_world(span_filter_system(span_bold("[aiPlayer.name]'s laws at the end of the round were:"))) // VOREStation edit
|
||||
else
|
||||
to_world(span_filter_system(span_bold("[aiPlayer.name]'s laws when it was deactivated were:"))) // VOREStation edit
|
||||
aiPlayer.show_laws(1)
|
||||
|
||||
if (aiPlayer.connected_robots.len)
|
||||
var/robolist = span_bold("The AI's loyal minions were:") + " "
|
||||
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
|
||||
robolist += "[robo.name][robo.stat?" (Deactivated), ":", "]" // VOREStation edit
|
||||
to_world(span_filter_system("[robolist]"))
|
||||
|
||||
var/dronecount = 0
|
||||
|
||||
for (var/mob/living/silicon/robot/robo in GLOB.mob_list)
|
||||
|
||||
if(istype(robo, /mob/living/silicon/robot/platform))
|
||||
var/mob/living/silicon/robot/platform/tank = robo
|
||||
if(!tank.has_had_player)
|
||||
continue
|
||||
|
||||
if(istype(robo,/mob/living/silicon/robot/drone) && !istype(robo,/mob/living/silicon/robot/drone/swarm))
|
||||
dronecount++
|
||||
continue
|
||||
|
||||
if (!robo.connected_ai)
|
||||
if (robo.stat != 2)
|
||||
to_world(span_filter_system(span_bold("[robo.name] survived as an AI-less stationbound synthetic! Its laws were:"))) // VOREStation edit
|
||||
else
|
||||
to_world(span_filter_system(span_bold("[robo.name] was unable to survive the rigors of being a stationbound synthetic without an AI. Its laws were:"))) // VOREStation edit
|
||||
|
||||
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
|
||||
robo.laws.show_laws(world)
|
||||
|
||||
if(dronecount)
|
||||
to_world(span_filter_system(span_bold("There [dronecount>1 ? "were" : "was"] [dronecount] industrious maintenance [dronecount>1 ? "drones" : "drone"] at the end of this round.")))
|
||||
|
||||
mode.declare_completion()//To declare normal completion.
|
||||
|
||||
//Ask the event manager to print round end information
|
||||
SSevents.RoundEnd()
|
||||
|
||||
//Print a list of antagonists to the server log
|
||||
var/list/total_antagonists = list()
|
||||
//Look into all mobs in world, dead or alive
|
||||
for(var/datum/mind/Mind in minds)
|
||||
var/temprole = Mind.special_role
|
||||
if(temprole) //if they are an antagonist of some sort.
|
||||
if(temprole in total_antagonists) //If the role exists already, add the name to it
|
||||
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
|
||||
else
|
||||
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
|
||||
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
|
||||
|
||||
//Now print them all into the log!
|
||||
log_game("Antagonists at round end were...")
|
||||
for(var/i in total_antagonists)
|
||||
log_game("[i]s[total_antagonists[i]].")
|
||||
|
||||
SSdbcore.SetRoundEnd()
|
||||
|
||||
return 1
|
||||
|
||||
/datum/controller/subsystem/ticker/stat_entry(msg)
|
||||
switch(current_state)
|
||||
if(GAME_STATE_INIT)
|
||||
..()
|
||||
if(GAME_STATE_PREGAME) // RUNLEVEL_LOBBY
|
||||
msg = "START [GLOB.round_progressing ? "[round(pregame_timeleft)]s" : "(PAUSED)"]"
|
||||
if(GAME_STATE_SETTING_UP) // RUNLEVEL_SETUP
|
||||
msg = "SETUP"
|
||||
if(GAME_STATE_PLAYING) // RUNLEVEL_GAME
|
||||
msg = "GAME"
|
||||
if(GAME_STATE_FINISHED) // RUNLEVEL_POSTGAME
|
||||
switch(end_game_state)
|
||||
if(END_GAME_MODE_FINISHED)
|
||||
msg = "MODE OVER, WAITING"
|
||||
if(END_GAME_READY_TO_END)
|
||||
msg = "ENDGAME PROCESSING"
|
||||
if(END_GAME_ENDING)
|
||||
msg = "END IN [round(restart_timeleft/10)]s"
|
||||
if(END_GAME_DELAYED)
|
||||
msg = "END PAUSED"
|
||||
else
|
||||
msg = "ENDGAME ERROR:[end_game_state]"
|
||||
return ..()
|
||||
///Whether the game is currently in progress, excluding roundend
|
||||
/datum/controller/subsystem/ticker/proc/IsPostgame()
|
||||
return current_state == GAME_STATE_FINISHED
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
flags |= SS_NO_INIT // Don't initialize again
|
||||
|
||||
current_state = SSticker.current_state
|
||||
mode = SSticker.mode
|
||||
pregame_timeleft = SSticker.pregame_timeleft
|
||||
force_ending = SSticker.force_ending
|
||||
|
||||
end_game_state = SSticker.end_game_state
|
||||
delay_end = SSticker.delay_end
|
||||
restart_timeleft = SSticker.restart_timeleft
|
||||
login_music = SSticker.login_music
|
||||
round_end_sound = SSticker.round_end_sound
|
||||
|
||||
minds = SSticker.minds
|
||||
|
||||
random_players = SSticker.random_players
|
||||
delay_end = SSticker.delay_end
|
||||
|
||||
tipped = SSticker.tipped
|
||||
selected_tip = SSticker.selected_tip
|
||||
|
||||
timeLeft = SSticker.timeLeft
|
||||
|
||||
totalPlayers = SSticker.totalPlayers
|
||||
totalPlayersReady = SSticker.totalPlayersReady
|
||||
total_admins_ready = SSticker.total_admins_ready
|
||||
|
||||
queue_delay = SSticker.queue_delay
|
||||
queued_players = SSticker.queued_players
|
||||
round_start_time = SSticker.round_start_time
|
||||
|
||||
queue_delay = SSticker.queue_delay
|
||||
queued_players = SSticker.queued_players
|
||||
|
||||
//These callbacks will fire after roundstart key transfer
|
||||
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)
|
||||
if(!HasRoundStarted())
|
||||
LAZYADD(round_start_events, cb)
|
||||
else
|
||||
cb.InvokeAsync()
|
||||
if (Master) //Set Masters run level if it exists
|
||||
switch (current_state)
|
||||
if(GAME_STATE_SETTING_UP)
|
||||
Master.SetRunLevel(RUNLEVEL_SETUP)
|
||||
if(GAME_STATE_PLAYING)
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
if(GAME_STATE_FINISHED)
|
||||
Master.SetRunLevel(RUNLEVEL_POSTGAME)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/Reboot(reason, end_string, delay)
|
||||
set waitfor = FALSE
|
||||
if(usr && !check_rights(R_SERVER, TRUE))
|
||||
return
|
||||
|
||||
if(!delay)
|
||||
delay = CONFIG_GET(number/round_end_countdown) * 10
|
||||
|
||||
var/skip_delay = check_rights()
|
||||
if(delay_end && !skip_delay)
|
||||
to_chat(world, span_boldannounce("An admin has delayed the round end."))
|
||||
return
|
||||
|
||||
to_chat(world, span_boldannounce("Rebooting World in [DisplayTimeText(delay)]. [reason]"))
|
||||
|
||||
// We dont have those
|
||||
//var/statspage = CONFIG_GET(string/roundstatsurl)
|
||||
//var/gamelogloc = CONFIG_GET(string/gamelogurl)
|
||||
//if(statspage)
|
||||
// to_chat(world, span_info("Round statistics and logs can be viewed <a href=\"[statspage][GLOB.round_id]\">at this website!</a>"))
|
||||
//else if(gamelogloc)
|
||||
// to_chat(world, span_info("Round logs can be located <a href=\"[gamelogloc]\">at this website!</a>"))
|
||||
|
||||
var/start_wait = world.time
|
||||
UNTIL(round_end_sound_sent || (world.time - start_wait) > (delay * 2)) //don't wait forever
|
||||
reboot_timer = addtimer(CALLBACK(src, PROC_REF(reboot_callback), reason, end_string), delay - (world.time - start_wait), TIMER_STOPPABLE)
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/reboot_callback(reason, end_string)
|
||||
if(end_string)
|
||||
end_state = end_string
|
||||
|
||||
log_game(span_boldannounce("Rebooting World. [reason]"))
|
||||
|
||||
world.Reboot()
|
||||
|
||||
/**
|
||||
* Deletes the current reboot timer and nulls the var
|
||||
*
|
||||
* Arguments:
|
||||
* * user - the user that cancelled the reboot, may be null
|
||||
*/
|
||||
/datum/controller/subsystem/ticker/proc/cancel_reboot(mob/user)
|
||||
if(!reboot_timer)
|
||||
to_chat(user, span_warning("There is no pending reboot!"))
|
||||
return FALSE
|
||||
to_chat(world, span_boldannounce("An admin has delayed the round end."))
|
||||
deltimer(reboot_timer)
|
||||
reboot_timer = null
|
||||
return TRUE
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
SUBSYSTEM_DEF(timer)
|
||||
name = "Timer"
|
||||
wait = 1 // SS_TICKER subsystem, so wait is in ticks
|
||||
init_order = INIT_ORDER_TIMER
|
||||
priority = FIRE_PRIORITY_TIMER
|
||||
flags = SS_TICKER|SS_NO_INIT
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/machines
|
||||
)
|
||||
|
||||
/// Queue used for storing timers that do not fit into the current buckets
|
||||
var/list/datum/timedevent/second_queue = list()
|
||||
|
||||
@@ -12,7 +12,9 @@ SUBSYSTEM_DEF(transcore)
|
||||
wait = 3 MINUTES
|
||||
flags = SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME
|
||||
init_order = INIT_ORDER_TRANSCORE
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/mapping
|
||||
)
|
||||
|
||||
// THINGS
|
||||
var/overdue_time = 6 MINUTES // Has to be a multiple of wait var, or else will just round up anyway.
|
||||
|
||||
@@ -78,7 +78,7 @@ SUBSYSTEM_DEF(verb_manager)
|
||||
|
||||
//we want unit tests to be able to directly call verbs that attempt to queue, and since unit tests should test internal behavior, we want the queue
|
||||
//to happen as if it was actually from player input if its called on a mob.
|
||||
#ifdef UNIT_TEST
|
||||
#ifdef UNIT_TESTS
|
||||
if(QDELETED(usr) && ismob(incoming_callback.object))
|
||||
incoming_callback.user = WEAKREF(incoming_callback.object)
|
||||
var/datum/callback/new_us = CALLBACK(arglist(list(GLOBAL_PROC, GLOBAL_PROC_REF(_queue_verb)) + args.Copy()))
|
||||
@@ -120,7 +120,7 @@ SUBSYSTEM_DEF(verb_manager)
|
||||
return TRUE
|
||||
|
||||
if((usr.client?.holder && !can_queue_admin_verbs) \
|
||||
|| (!subsystem_initialized && !(flags & SS_NO_INIT)) \
|
||||
|| (!initialized && !(flags & SS_NO_INIT)) \
|
||||
|| FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs \
|
||||
|| !(runlevels & Master.current_runlevel))
|
||||
return FALSE
|
||||
|
||||
@@ -2,7 +2,6 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
name = "Vis contents overlays"
|
||||
wait = 1 MINUTES
|
||||
priority = FIRE_PRIORITY_VIS
|
||||
init_order = INIT_ORDER_VIS
|
||||
|
||||
var/list/vis_overlay_cache
|
||||
var/list/currentrun
|
||||
|
||||
@@ -24,7 +24,7 @@ SUBSYSTEM_DEF(vote)
|
||||
/datum/controller/subsystem/vote/fire(resumed)
|
||||
if(mode)
|
||||
time_remaining = round((started_time + duration - world.time)/10)
|
||||
if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP)
|
||||
if(mode == VOTE_GAMEMODE && SSticker.current_state >= GAME_STATE_SETTING_UP)
|
||||
to_chat(world, span_bold("Gamemode vote aborted: Game has already started."))
|
||||
reset()
|
||||
return
|
||||
@@ -164,7 +164,7 @@ SUBSYSTEM_DEF(vote)
|
||||
if(VOTE_GAMEMODE)
|
||||
if(GLOB.master_mode != .)
|
||||
world.save_mode(.)
|
||||
if(ticker && ticker.mode)
|
||||
if(SSticker && SSticker.mode)
|
||||
restart = 1
|
||||
else
|
||||
GLOB.master_mode = .
|
||||
@@ -216,7 +216,7 @@ SUBSYSTEM_DEF(vote)
|
||||
if(VOTE_RESTART)
|
||||
choices.Add("Restart Round", "Continue Playing")
|
||||
if(VOTE_GAMEMODE)
|
||||
if(ticker.current_state >= GAME_STATE_SETTING_UP)
|
||||
if(SSticker.current_state >= GAME_STATE_SETTING_UP)
|
||||
return 0
|
||||
choices.Add(config.votable_modes)
|
||||
for(var/F in choices)
|
||||
@@ -231,13 +231,13 @@ SUBSYSTEM_DEF(vote)
|
||||
if(get_security_level() == "red" || get_security_level() == "delta")
|
||||
to_chat(initiator_key, "The current alert status is too high to call for a crew transfer!")
|
||||
return 0
|
||||
if(ticker.current_state <= GAME_STATE_SETTING_UP)
|
||||
if(SSticker.current_state <= GAME_STATE_SETTING_UP)
|
||||
to_chat(initiator_key, "The crew transfer button has been disabled!")
|
||||
return 0
|
||||
question = "Your PDA beeps with a message from Central. Would you like an additional hour to finish ongoing projects? (OOC Notice: Transfer votes must have a majority (70%) of all votes to initiate transfer.)" //Yawn Wider Edit //CHOMP EDIT: Changed to 'one' hour. Add notice stating transfer must contain 70% of total vote.
|
||||
choices.Add("Initiate Crew Transfer", "Extend the Shift") //VOREStation Edit
|
||||
if(VOTE_ADD_ANTAGONIST)
|
||||
if(!CONFIG_GET(flag/allow_extra_antags) || ticker.current_state >= GAME_STATE_SETTING_UP) // CHOMPEdit
|
||||
if(!CONFIG_GET(flag/allow_extra_antags) || SSticker.current_state >= GAME_STATE_SETTING_UP) // CHOMPEdit
|
||||
return 0
|
||||
for(var/antag_type in all_antag_types)
|
||||
var/datum/antagonist/antag = all_antag_types[antag_type]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
SUBSYSTEM_DEF(webhooks)
|
||||
name = "Webhooks"
|
||||
init_order = INIT_ORDER_WEBHOOKS
|
||||
dependencies = list(
|
||||
/datum/controller/subsystem/server_maint,
|
||||
)
|
||||
flags = SS_NO_FIRE
|
||||
var/list/webhook_decls = list()
|
||||
|
||||
@@ -63,7 +65,7 @@ SUBSYSTEM_DEF(webhooks)
|
||||
if(!check_rights_for(src, R_HOLDER))
|
||||
return
|
||||
|
||||
if(!SSwebhooks.subsystem_initialized)
|
||||
if(!SSwebhooks.initialized)
|
||||
to_chat(usr, span_warning("Let the webhook subsystem initialize before trying to reload it."))
|
||||
return
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
//
|
||||
SUBSYSTEM_DEF(xenoarch)
|
||||
name = "Xenoarch"
|
||||
init_order = INIT_ORDER_XENOARCH
|
||||
flags = SS_NO_FIRE
|
||||
init_stage = INITSTAGE_LAST
|
||||
var/list/artifact_spawning_turfs = list()
|
||||
var/list/digsite_spawning_turfs = list()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user