mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-25 04:57:12 +01:00
Annihilates the blackbox (#15132)
* Lets get this show on the road
* Now were talking
* These matter
* Oh the joys of CI testing
* And this
* Wrong version
* Tweaks
* More tweaks
* Lets document this
* This too
* Upgrades this
* Fixed some sanity issues
* This too
* Screw it, this too
* More sanity
* And these
* This too
* Documentation
* This too
* Fixes **awful** scoreboard logic
* Why do we care about only half-absorbing someone
* Revert "Why do we care about only half-absorbing someone"
This reverts commit 8de1cfdf05.
* Refactors these
* Hashing
* Moxian tweaks
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
// Dont touch this subsystem unless you ABSOLUTELY know what you are doing
|
||||
|
||||
SUBSYSTEM_DEF(blackbox)
|
||||
name = "Blackbox"
|
||||
flags = SS_NO_FIRE | SS_NO_INIT
|
||||
// Even though we dont initialize, we need this init_order
|
||||
// On Master.Shutdown(), it shuts down subsystems in the REVERSE order
|
||||
// The database SS has INIT_ORDER_DBCORE=20, and this SS has INIT_ORDER_BLACKBOX=19
|
||||
// So putting this ensures it shuts down in the right order
|
||||
init_order = INIT_ORDER_BLACKBOX
|
||||
|
||||
/// List of all recorded feedback
|
||||
var/list/datum/feedback_variable/feedback = list()
|
||||
/// Is it time to stop tracking stats?
|
||||
var/sealed = FALSE
|
||||
/// List of highest tech levels attained that isn't lost lost by destruction of RD computers
|
||||
var/list/research_levels = list()
|
||||
/// Associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
|
||||
var/list/versions = list()
|
||||
|
||||
/datum/controller/subsystem/blackbox/Recover()
|
||||
feedback = SSblackbox.feedback
|
||||
sealed = SSblackbox.sealed
|
||||
|
||||
//no touchie
|
||||
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
|
||||
if(var_name == "feedback")
|
||||
return debug_variable(var_name, deepCopyList(feedback), 0, src)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
|
||||
switch(var_name)
|
||||
if("feedback")
|
||||
return FALSE
|
||||
if("sealed")
|
||||
if(var_value)
|
||||
return Seal()
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Shutdown Helper
|
||||
*
|
||||
* Dumps all feedback stats to the DB. Doesnt get much simpler than that.
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/Shutdown()
|
||||
sealed = FALSE
|
||||
for(var/obj/machinery/message_server/MS in GLOB.message_servers)
|
||||
if(MS.pda_msgs.len)
|
||||
record_feedback("tally", "radio_usage", MS.pda_msgs.len, "PDA")
|
||||
if(MS.rc_msgs.len)
|
||||
record_feedback("tally", "radio_usage", MS.rc_msgs.len, "request console")
|
||||
|
||||
if(length(research_levels))
|
||||
record_feedback("associative", "high_research_level", 1, research_levels)
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
var/list/datum/db_query/queries = list()
|
||||
|
||||
for(var/datum/feedback_variable/FV in feedback)
|
||||
var/sqlversion = 1
|
||||
if(FV.key in versions)
|
||||
sqlversion = versions[FV.key]
|
||||
|
||||
var/datum/db_query/query_feedback_save = SSdbcore.NewQuery({"
|
||||
INSERT DELAYED IGNORE INTO [format_table_name("feedback")] (datetime, round_id, key_name, key_type, version, json)
|
||||
VALUES (NOW(), :rid, :keyname, :keytype, :version, :json)"}, list(
|
||||
"rid" = text2num(GLOB.round_id),
|
||||
"keyname" = FV.key,
|
||||
"keytype" = FV.key_type,
|
||||
"version" = text2num(sqlversion),
|
||||
"json" = json_encode(FV.json)
|
||||
))
|
||||
queries += query_feedback_save
|
||||
|
||||
SSdbcore.MassExecute(queries, TRUE, TRUE)
|
||||
|
||||
/**
|
||||
* Blackbox Sealer
|
||||
*
|
||||
* Seals the blackbox, preventing new data from being stored. This is to avoid data being bloated during end round grief
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/Seal()
|
||||
if(sealed)
|
||||
return FALSE
|
||||
log_game("Blackbox sealed")
|
||||
sealed = TRUE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Research level broadcast logging helper
|
||||
*
|
||||
* This is called on R&D updates for a safe way of logging tech levels if an R&D console is destroyed
|
||||
*
|
||||
* Arguments:
|
||||
* * tech - Research technology name
|
||||
* * level - Research technology level
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/log_research(tech, level)
|
||||
if(!(tech in research_levels) || research_levels[tech] < level)
|
||||
research_levels[tech] = level
|
||||
|
||||
|
||||
/**
|
||||
* Radio broadcast logging helper
|
||||
*
|
||||
* Called during [/proc/broadcast_message()] to log a message to the blackbox.
|
||||
* Translates the specific frequency to a name
|
||||
*
|
||||
* Arguments:
|
||||
* * freq - Frequency of the transmission
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/LogBroadcast(freq)
|
||||
if(sealed)
|
||||
return
|
||||
switch(freq)
|
||||
if(PUB_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "common")
|
||||
if(SCI_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "science")
|
||||
if(COMM_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "command")
|
||||
if(MED_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "medical")
|
||||
if(ENG_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "engineering")
|
||||
if(SEC_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "security")
|
||||
if(DTH_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "deathsquad")
|
||||
if(SYND_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "syndicate")
|
||||
if(SYNDTEAM_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "syndicate team")
|
||||
if(SUP_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "supply")
|
||||
if(SRV_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "service")
|
||||
if(PROC_FREQ)
|
||||
record_feedback("tally", "radio_usage", 1, "procedure")
|
||||
else
|
||||
record_feedback("tally", "radio_usage", 1, "other")
|
||||
|
||||
|
||||
/**
|
||||
* Helper to find and return a feeedback datum
|
||||
*
|
||||
* Pass in a feedback datum key and key_type to do a lookup.
|
||||
* It will create the feedback datum if it doesnt exist
|
||||
*
|
||||
* Arguments:
|
||||
* * key - Key of the variable to lookup
|
||||
* * key_type - Type of feedback to be recorded if the feedback datum cant be found
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/find_feedback_datum(key, key_type)
|
||||
for(var/datum/feedback_variable/FV in feedback)
|
||||
if(FV.key == key)
|
||||
return FV
|
||||
|
||||
var/datum/feedback_variable/FV = new(key, key_type)
|
||||
feedback += FV
|
||||
return FV
|
||||
|
||||
/**
|
||||
* Main feedback recording proc
|
||||
*
|
||||
* This is the bulk of this subsystem and is in charge of creating and using the variables.
|
||||
* See .github/USING_FEEDBACK_DATA.md for instructions
|
||||
* Note that feedback is not recorded to the DB during this function. That happens at round end.
|
||||
*
|
||||
* Arguments:
|
||||
* * key_type - Type of key. Either "text", "amount", "tally", "nested tally", "associative"
|
||||
* * key - Key of the data to be used (EG: "admin_verb")
|
||||
* * increment - If using "amount", how much to increment why
|
||||
* * data - The actual data to logged
|
||||
* * overwrite - Do we want to overwrite the existing key
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/record_feedback(key_type, key, increment, data, overwrite)
|
||||
if(sealed || !key_type || !istext(key) || !isnum(increment || !data))
|
||||
return
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(key, key_type)
|
||||
switch(key_type)
|
||||
if("text")
|
||||
if(!istext(data))
|
||||
return
|
||||
if(!islist(FV.json["data"]))
|
||||
FV.json["data"] = list()
|
||||
if(overwrite)
|
||||
FV.json["data"] = data
|
||||
else
|
||||
FV.json["data"] |= data
|
||||
if("amount")
|
||||
FV.json["data"] += increment
|
||||
if("tally")
|
||||
if(!islist(FV.json["data"]))
|
||||
FV.json["data"] = list()
|
||||
FV.json["data"]["[data]"] += increment
|
||||
if("nested tally")
|
||||
if(!islist(data))
|
||||
return
|
||||
if(!islist(FV.json["data"]))
|
||||
FV.json["data"] = list()
|
||||
FV.json["data"] = record_feedback_recurse_list(FV.json["data"], data, increment)
|
||||
if("associative")
|
||||
if(!islist(data))
|
||||
return
|
||||
if(!islist(FV.json["data"]))
|
||||
FV.json["data"] = list()
|
||||
var/pos = length(FV.json["data"]) + 1
|
||||
FV.json["data"]["[pos]"] = list()
|
||||
for(var/i in data)
|
||||
FV.json["data"]["[pos]"]["[i]"] = "[data[i]]"
|
||||
|
||||
/**
|
||||
* Recursive list recorder
|
||||
*
|
||||
* Used by the above proc for nested tallies
|
||||
*
|
||||
* Arguments:
|
||||
* * L - List to use
|
||||
* * key_list - List of keys to add
|
||||
* * increment - How much to increase by
|
||||
* * depth - Depth to use
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/record_feedback_recurse_list(list/L, list/key_list, increment, depth = 1)
|
||||
if(depth == key_list.len)
|
||||
if(L.Find(key_list[depth]))
|
||||
L["[key_list[depth]]"] += increment
|
||||
else
|
||||
var/list/list_found_index = list(key_list[depth] = increment)
|
||||
L += list_found_index
|
||||
else
|
||||
if(!L.Find(key_list[depth]))
|
||||
var/list/list_go_down = list(key_list[depth] = list())
|
||||
L += list_go_down
|
||||
L["[key_list[depth-1]]"] = .(L["[key_list[depth]]"], key_list, increment, ++depth)
|
||||
return L
|
||||
|
||||
/**
|
||||
* # feedback_variable
|
||||
*
|
||||
* Datum to hold feedback data, which gets logged at round end
|
||||
*
|
||||
* Holds all the information being logged
|
||||
*/
|
||||
/datum/feedback_variable
|
||||
var/key
|
||||
var/key_type
|
||||
var/list/json = list()
|
||||
|
||||
// Basically just takes some args and sets them
|
||||
/datum/feedback_variable/New(new_key, new_key_type)
|
||||
key = new_key
|
||||
key_type = new_key_type
|
||||
|
||||
/**
|
||||
* Death reporting proc
|
||||
*
|
||||
* Called when humans and cyborgs die, and logs death info to the `death` table
|
||||
*
|
||||
* Arguments:
|
||||
* * L - The human or cyborg to be logged
|
||||
*/
|
||||
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
|
||||
if(sealed)
|
||||
return
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
if(!L)
|
||||
return
|
||||
if(!L.key || !L.mind)
|
||||
return
|
||||
|
||||
var/area/placeofdeath = get_area(L.loc)
|
||||
var/podname = "Unknown"
|
||||
if(placeofdeath)
|
||||
podname = placeofdeath.name
|
||||
|
||||
// Empty string is important here!
|
||||
var/laname = ""
|
||||
var/lakey = ""
|
||||
if(L.lastattacker)
|
||||
laname = L.lastattacker
|
||||
if(L.lastattackerckey)
|
||||
lakey = L.lastattackerckey
|
||||
|
||||
var/datum/db_query/deathquery = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord)
|
||||
VALUES (:name, :key, :job, :special, :pod, NOW(), :laname, :lakey, :gender, :bruteloss, :fireloss, :brainloss, :oxyloss, :coord)"},
|
||||
list(
|
||||
"name" = L.real_name,
|
||||
"key" = L.key,
|
||||
"job" = L.mind.assigned_role,
|
||||
"special" = L.mind.special_role || "",
|
||||
"pod" = podname,
|
||||
"laname" = laname,
|
||||
"lakey" = lakey,
|
||||
"gender" = L.gender,
|
||||
"bruteloss" = L.getBruteLoss(),
|
||||
"fireloss" = L.getFireLoss(),
|
||||
"brainloss" = L.getBrainLoss(),
|
||||
"oxyloss" = L.getOxyLoss(),
|
||||
"coord" = "[L.x], [L.y], [L.z]"
|
||||
)
|
||||
)
|
||||
deathquery.warn_execute()
|
||||
qdel(deathquery)
|
||||
@@ -109,16 +109,16 @@ SUBSYSTEM_DEF(dbcore)
|
||||
config.sql_enabled = FALSE
|
||||
schema_valid = FALSE
|
||||
SSticker.ticker_going = FALSE
|
||||
log_world("Database connection failed: Invalid SQL Versions")
|
||||
SEND_TEXT(world.log, "Database connection failed: Invalid SQL Versions")
|
||||
return FALSE
|
||||
#endif
|
||||
if(Connect())
|
||||
log_world("Database connection established")
|
||||
SEND_TEXT(world.log, "Database connection established")
|
||||
else
|
||||
// log_sql() because then an error will be logged in the same place
|
||||
log_sql("Your server failed to establish a connection with the database")
|
||||
else
|
||||
log_sql("Database is not enabled in configuration")
|
||||
SEND_TEXT(world.log, "Database is not enabled in configuration")
|
||||
|
||||
/**
|
||||
* Disconnection Handler
|
||||
@@ -132,6 +132,73 @@ SUBSYSTEM_DEF(dbcore)
|
||||
rustg_sql_disconnect_pool(connection)
|
||||
connection = null
|
||||
|
||||
/**
|
||||
* Shutdown Handler
|
||||
*
|
||||
* Called during world/Reboot() as part of the MC shutdown
|
||||
* Finalises a round in the DB before disconnecting.
|
||||
*/
|
||||
/datum/controller/subsystem/dbcore/Shutdown()
|
||||
//This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/db_query/query_round_shutdown = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("round")] SET shutdown_datetime = Now(), end_state = :end_state WHERE id = :round_id",
|
||||
list("end_state" = SSticker.end_state, "round_id" = GLOB.round_id)
|
||||
)
|
||||
query_round_shutdown.Execute()
|
||||
qdel(query_round_shutdown)
|
||||
if(IsConnected())
|
||||
Disconnect()
|
||||
|
||||
/**
|
||||
* Round ID Setter
|
||||
*
|
||||
* Called during world/New() at the earliest point
|
||||
* Declares a round ID in the database and assigns it to a global. Also ensures that server address and ports are set
|
||||
*/
|
||||
/datum/controller/subsystem/dbcore/proc/SetRoundID()
|
||||
if(!IsConnected())
|
||||
return
|
||||
var/datum/db_query/query_round_initialize = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("round")] (initialize_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(:internet_address), :port)",
|
||||
list("internet_address" = world.internet_address || "0", "port" = "[world.port]")
|
||||
)
|
||||
query_round_initialize.Execute(async = FALSE)
|
||||
GLOB.round_id = "[query_round_initialize.last_insert_id]"
|
||||
qdel(query_round_initialize)
|
||||
|
||||
/**
|
||||
* Round End Time Setter
|
||||
*
|
||||
* Called during SSticker.setup()
|
||||
* Sets the time that the round started in the DB
|
||||
*/
|
||||
/datum/controller/subsystem/dbcore/proc/SetRoundStart()
|
||||
if(!IsConnected())
|
||||
return
|
||||
var/datum/db_query/query_round_start = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("round")] SET start_datetime=NOW(), commit_hash=:hash WHERE id=:round_id",
|
||||
list("hash" = GLOB.revision_info.commit_hash, "round_id" = GLOB.round_id)
|
||||
)
|
||||
query_round_start.Execute()
|
||||
qdel(query_round_start)
|
||||
|
||||
/**
|
||||
* Round End Time Setter
|
||||
*
|
||||
* Called during SSticker.declare_completion()
|
||||
* Sets the time that the round ended in the DB, as well as some other params
|
||||
*/
|
||||
/datum/controller/subsystem/dbcore/proc/SetRoundEnd()
|
||||
if(!IsConnected())
|
||||
return
|
||||
var/datum/db_query/query_round_end = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("round")] SET end_datetime = Now(), game_mode_result = :game_mode_result, station_name = :station_name WHERE id = :round_id",
|
||||
list("game_mode_result" = SSticker.mode_result, "station_name" = station_name(), "round_id" = GLOB.round_id)
|
||||
)
|
||||
query_round_end.Execute()
|
||||
qdel(query_round_end)
|
||||
|
||||
/**
|
||||
* IsConnected Helper
|
||||
*
|
||||
@@ -428,7 +495,7 @@ SUBSYSTEM_DEF(dbcore)
|
||||
|
||||
log_admin("[key_name(usr)] is attempting to re-establish the DB Connection")
|
||||
message_admins("[key_name_admin(usr)] is attempting to re-establish the DB Connection")
|
||||
feedback_add_details("admin_verb", "FRDBC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Force Reconnect DB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
SSdbcore.failed_connections = 0 // Reset this
|
||||
if(!SSdbcore.Connect())
|
||||
|
||||
@@ -551,40 +551,44 @@ SUBSYSTEM_DEF(jobs)
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/HandleFeedbackGathering()
|
||||
for(var/datum/job/job in occupations)
|
||||
var/tmp_str = "|[job.title]|"
|
||||
|
||||
var/level1 = 0 //high
|
||||
var/level2 = 0 //medium
|
||||
var/level3 = 0 //low
|
||||
var/level4 = 0 //never
|
||||
var/level5 = 0 //banned
|
||||
var/level6 = 0 //account too young
|
||||
var/level7 = 0 //has disability rendering them ineligible
|
||||
var/high = 0 //high
|
||||
var/medium = 0 //medium
|
||||
var/low = 0 //low
|
||||
var/never = 0 //never
|
||||
var/banned = 0 //banned
|
||||
var/young = 0 //account too young
|
||||
var/disabled = 0 //has disability rendering them ineligible
|
||||
for(var/mob/new_player/player in GLOB.player_list)
|
||||
if(!(player.ready && player.mind && !player.mind.assigned_role))
|
||||
continue //This player is not ready
|
||||
if(jobban_isbanned(player, job.title))
|
||||
level5++
|
||||
banned++
|
||||
continue
|
||||
if(!job.player_old_enough(player.client))
|
||||
level6++
|
||||
young++
|
||||
continue
|
||||
if(job.available_in_playtime(player.client))
|
||||
level6++
|
||||
young++
|
||||
continue
|
||||
if(job.barred_by_disability(player.client))
|
||||
level7++
|
||||
disabled++
|
||||
continue
|
||||
if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
|
||||
level1++
|
||||
high++
|
||||
else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)
|
||||
level2++
|
||||
medium++
|
||||
else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag)
|
||||
level3++
|
||||
else level4++ //not selected
|
||||
low++
|
||||
else never++ //not selected
|
||||
|
||||
tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|DISABILITY=[level7]|-"
|
||||
feedback_add_details("job_preferences",tmp_str)
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", high, list("[job.title]", "high"))
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", medium, list("[job.title]", "medium"))
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", low, list("[job.title]", "low"))
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", never, list("[job.title]", "never"))
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", banned, list("[job.title]", "banned"))
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", young, list("[job.title]", "young"))
|
||||
SSblackbox.record_feedback("nested tally", "job_preferences", disabled, list("[job.title]", "disabled"))
|
||||
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/CreateMoneyAccount(mob/living/H, rank, datum/job/job)
|
||||
|
||||
@@ -18,7 +18,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
/// Do we want to force-end as soon as we can
|
||||
var/force_ending = FALSE
|
||||
/// Leave here at FALSE ! setup() will take care of it when needed for Secret mode -walter0o
|
||||
var/hide_mode = FALSE
|
||||
var/hide_mode = FALSE
|
||||
/// Our current game mode
|
||||
var/datum/game_mode/mode = null
|
||||
/// The current pick of lobby music played in the lobby
|
||||
@@ -36,7 +36,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
/// Cult data. Here instead of cult for adminbus purposes
|
||||
var/datum/cult_info/cultdat = null
|
||||
/// If set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
|
||||
var/random_players = FALSE
|
||||
var/random_players = FALSE
|
||||
/// Did we broadcast the tip of the round yet?
|
||||
var/tipped = FALSE
|
||||
/// What will be the tip of the round?
|
||||
@@ -50,11 +50,15 @@ SUBSYSTEM_DEF(ticker)
|
||||
/// Holder for inital autotransfer vote timer
|
||||
var/next_autotransfer = 0
|
||||
/// Used for station explosion cinematic
|
||||
var/obj/screen/cinematic = null
|
||||
var/obj/screen/cinematic = null
|
||||
/// Spam Prevention. Announce round end only once.
|
||||
var/round_end_announced = FALSE
|
||||
/// Is the ticker currently processing? If FALSE, roundstart is delayed
|
||||
var/ticker_going = TRUE
|
||||
/// Gamemode result (For things like shadowlings or nukies which can end multiple ways)
|
||||
var/mode_result = "undefined"
|
||||
/// Server end state (Did we end properly or reboot or nuke or what)
|
||||
var/end_state = "undefined"
|
||||
|
||||
/datum/controller/subsystem/ticker/Initialize()
|
||||
login_music = pick(\
|
||||
@@ -124,9 +128,9 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
spawn(50)
|
||||
if(mode.station_was_nuked)
|
||||
world.Reboot("Station destroyed by Nuclear Device.", "end_proper", "nuke")
|
||||
world.Reboot("Station destroyed by Nuclear Device.", "nuke")
|
||||
else
|
||||
world.Reboot("Round ended.", "end_proper", "proper completion")
|
||||
world.Reboot("Round ended.", "proper completion")
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/setup()
|
||||
cultdat = setupcult()
|
||||
@@ -243,6 +247,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(S.name != "AI")
|
||||
qdel(S)
|
||||
|
||||
SSdbcore.SetRoundStart()
|
||||
to_chat(world, "<span class='darkmblue'><B>Enjoy the game!</B></span>")
|
||||
world << sound('sound/AI/welcome.ogg')
|
||||
|
||||
@@ -251,7 +256,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
for(var/holidayname in SSholiday.holidays)
|
||||
var/datum/holiday/holiday = SSholiday.holidays[holidayname]
|
||||
to_chat(world, "<h4>[holiday.greet()]</h4>")
|
||||
|
||||
|
||||
SSdiscord.send2discord_simple_noadmins("**\[Info]** Round has started")
|
||||
auto_toggle_ooc(FALSE) // Turn it off
|
||||
round_start_time = world.time
|
||||
@@ -416,9 +421,9 @@ SUBSYSTEM_DEF(ticker)
|
||||
/datum/controller/subsystem/ticker/proc/declare_completion()
|
||||
GLOB.nologevent = TRUE //end of round murder and shenanigans are legal; there's no need to jam up attack logs past this point.
|
||||
//Round statistics report
|
||||
var/datum/station_state/end_state = new /datum/station_state()
|
||||
end_state.count()
|
||||
var/station_integrity = min(round( 100.0 * GLOB.start_state.score(end_state), 0.1), 100.0)
|
||||
var/datum/station_state/ending_station_state = new /datum/station_state()
|
||||
ending_station_state.count()
|
||||
var/station_integrity = min(round( 100.0 * GLOB.start_state.score(ending_station_state), 0.1), 100.0)
|
||||
|
||||
to_chat(world, "<BR>[TAB]Shift Duration: <B>[round(ROUND_TIME / 36000)]:[add_zero("[ROUND_TIME / 600 % 60]", 2)]:[ROUND_TIME / 100 % 6][ROUND_TIME / 100 % 10]</B>")
|
||||
to_chat(world, "<BR>[TAB]Station Integrity: <B>[mode.station_was_nuked ? "<font color='red'>Destroyed</font>" : "[station_integrity]%"]</B>")
|
||||
@@ -494,6 +499,10 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/mob/M = m
|
||||
H.add_hud_to(M)
|
||||
|
||||
// Seal the blackbox, stop collecting info
|
||||
SSblackbox.Seal()
|
||||
SSdbcore.SetRoundEnd()
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
|
||||
|
||||
@@ -180,7 +180,7 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
|
||||
if(restart)
|
||||
world.Reboot("Restart vote successful.", "end_error", "restart vote")
|
||||
world.Reboot("Restart vote successful.", "restart vote")
|
||||
|
||||
return .
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
switch(controller)
|
||||
if("Master")
|
||||
Recreate_MC()
|
||||
feedback_add_details("admin_verb","RMaster")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Restart MC")
|
||||
if("Failsafe")
|
||||
new /datum/controller/failsafe()
|
||||
feedback_add_details("admin_verb","RFailsafe")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Restart Failsafe")
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
|
||||
@@ -29,15 +29,15 @@
|
||||
switch(controller)
|
||||
if("Configuration")
|
||||
debug_variables(config)
|
||||
feedback_add_details("admin_verb","DConf")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Debug Config")
|
||||
if("pAI")
|
||||
debug_variables(GLOB.paiController)
|
||||
feedback_add_details("admin_verb","DpAI")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Debug pAI")
|
||||
if("Cameras")
|
||||
debug_variables(GLOB.cameranet)
|
||||
feedback_add_details("admin_verb","DCameras")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Debug Cameras")
|
||||
if("Space Manager")
|
||||
debug_variables(GLOB.space_manager)
|
||||
feedback_add_details("admin_verb","DSpace")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Debug Space")
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
|
||||
|
||||
Reference in New Issue
Block a user