Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into upstream-merge-26492

This commit is contained in:
LetterJay
2017-05-17 09:58:53 -05:00
808 changed files with 31788 additions and 17401 deletions
+2 -2
View File
@@ -45,9 +45,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
switch(controller)
if("Master")
Recreate_MC()
feedback_add_details("admin_verb","Restart Master Controller")
SSblackbox.add_details("admin_verb","Restart Master Controller")
if("Failsafe")
new /datum/controller/failsafe()
feedback_add_details("admin_verb","Restart Failsafe Controller")
SSblackbox.add_details("admin_verb","Restart Failsafe Controller")
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
+29 -36
View File
@@ -43,10 +43,8 @@
var/log_attack = 0 // log attack messages
var/log_adminchat = 0 // log admin chat messages
var/log_pda = 0 // log pda messages
var/log_hrefs = 0 // log all links clicked in-game. Could be used for debugging and tracking down exploits
var/log_twitter = 0 // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
var/log_world_topic = 0 // log all world.Topic() calls
var/log_runtimes = FALSE // log runtimes into a file
var/sql_enabled = 0 // for sql switching
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
var/allow_vote_restart = 0 // allow votes to restart
@@ -66,9 +64,9 @@
var/respawn = 1
var/guest_jobban = 1
var/usewhitelist = 0
var/inactivity_period = 3000 //time in ds until a player is considered inactive
var/afk_period = 6000 //time in ds until a player is considered afk and kickable
var/kick_inactive = FALSE //force disconnect for inactive players
var/inactivity_period = 3000 //time in ds until a player is considered inactive
var/afk_period = 6000 //time in ds until a player is considered afk and kickable
var/kick_inactive = FALSE //force disconnect for inactive players
var/load_jobs_from_txt = 0
var/automute_on = 0 //enables automuting/spam prevention
var/minimal_access_threshold = 0 //If the number of players is larger than this threshold, minimal access will be turned on.
@@ -129,6 +127,7 @@
var/forbid_peaceborg = 0
var/panic_bunker = 0 // prevents new people it hasn't seen before from connecting
var/notify_new_player_age = 0 // how long do we notify admins of a new player
var/notify_new_player_account_age = 0 // how long do we notify admins of a new byond account
var/irc_first_connection_alert = 0 // do we notify the irc channel when somebody is connecting for the first time?
var/traitor_scaling_coeff = 6 //how much does the amount of players get divided by to determine traitors
@@ -269,7 +268,7 @@
if(M.config_tag)
if(!(M.config_tag in modes)) // ensure each mode is added only once
GLOB.diary << "Adding game mode [M.name] ([M.config_tag]) to configuration."
GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration."
modes += M.config_tag
mode_names[M.config_tag] = M.name
probabilities[M.config_tag] = M.probability
@@ -291,7 +290,7 @@
GLOB.abandon_allowed = respawn
/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist
var/list/Lines = world.file2list(filename)
var/list/Lines = world.file2list(filename)
for(var/t in Lines)
if(!t)
@@ -358,8 +357,6 @@
log_adminchat = 1
if("log_pda")
log_pda = 1
if("log_hrefs")
log_hrefs = 1
if("log_twitter")
log_twitter = 1
if("log_world_topic")
@@ -410,12 +407,12 @@
usewhitelist = TRUE
if("allow_metadata")
allow_Metadata = 1
if("inactivity_period")
inactivity_period = text2num(value) * 10 //documented as seconds in config.txt
if("afk_period")
afk_period = text2num(value) * 10 // ^^^
if("inactivity_period")
inactivity_period = text2num(value) * 10 //documented as seconds in config.txt
if("afk_period")
afk_period = text2num(value) * 10 // ^^^
if("kick_inactive")
kick_inactive = TRUE
kick_inactive = TRUE
if("load_jobs_from_txt")
load_jobs_from_txt = 1
if("forbid_singulo_possession")
@@ -476,6 +473,8 @@
panic_bunker = 1
if("notify_new_player_age")
notify_new_player_age = text2num(value)
if("notify_new_player_account_age")
notify_new_player_account_age = text2num(value)
if("irc_first_connection_alert")
irc_first_connection_alert = 1
if("check_randomizer")
@@ -493,12 +492,6 @@
ipintel_save_bad = text2num(value)
if("aggressive_changelog")
aggressive_changelog = 1
if("log_runtimes")
log_runtimes = TRUE
var/newlog = file("data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log")
if(GLOB.runtime_diary != newlog)
world.log << "Now logging runtimes to data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log"
GLOB.runtime_diary = newlog
if("autoconvert_notes")
autoconvert_notes = 1
if("allow_webclient")
@@ -542,7 +535,7 @@
if("error_msg_delay")
error_msg_delay = text2num(value)
else
GLOB.diary << "Unknown setting in configuration: '[name]'"
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
else if(type == "game_options")
switch(name)
@@ -605,13 +598,13 @@
if(mode_name in modes)
continuous[mode_name] = 1
else
GLOB.diary << "Unknown continuous configuration definition: [mode_name]."
GLOB.config_error_log << "Unknown continuous configuration definition: [mode_name]."
if("midround_antag")
var/mode_name = lowertext(value)
if(mode_name in modes)
midround_antag[mode_name] = 1
else
GLOB.diary << "Unknown midround antagonist configuration definition: [mode_name]."
GLOB.config_error_log << "Unknown midround antagonist configuration definition: [mode_name]."
if("midround_antag_time_check")
midround_antag_time_check = text2num(value)
if("midround_antag_life_check")
@@ -627,9 +620,9 @@
if(mode_name in modes)
min_pop[mode_name] = text2num(mode_value)
else
GLOB.diary << "Unknown minimum population configuration definition: [mode_name]."
GLOB.config_error_log << "Unknown minimum population configuration definition: [mode_name]."
else
GLOB.diary << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
GLOB.config_error_log << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
if("max_pop")
var/pop_pos = findtext(value, " ")
var/mode_name = null
@@ -641,9 +634,9 @@
if(mode_name in modes)
max_pop[mode_name] = text2num(mode_value)
else
GLOB.diary << "Unknown maximum population configuration definition: [mode_name]."
GLOB.config_error_log << "Unknown maximum population configuration definition: [mode_name]."
else
GLOB.diary << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
GLOB.config_error_log << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
if("shuttle_refuel_delay")
shuttle_refuel_delay = text2num(value)
if("show_game_type_odds")
@@ -671,9 +664,9 @@
if(prob_name in modes)
probabilities[prob_name] = text2num(prob_value)
else
GLOB.diary << "Unknown game mode probability configuration definition: [prob_name]."
GLOB.config_error_log << "Unknown game mode probability configuration definition: [prob_name]."
else
GLOB.diary << "Incorrect probability configuration definition: [prob_name] [prob_value]."
GLOB.config_error_log << "Incorrect probability configuration definition: [prob_name] [prob_value]."
if("protect_roles_from_antagonist")
protect_roles_from_antagonist = 1
@@ -720,7 +713,7 @@
// Value is in the form "LAWID,NUMBER"
var/list/L = splittext(value, ",")
if(L.len != 2)
GLOB.diary << "Invalid LAW_WEIGHT: " + t
GLOB.config_error_log << "Invalid LAW_WEIGHT: " + t
continue
var/lawid = L[1]
var/weight = text2num(L[2])
@@ -776,8 +769,8 @@
mentors_mobname_only = 1
if ("mentor_legacy_system")
mentor_legacy_system = 1
else
GLOB.diary << "Unknown setting in configuration: '[name]'"
// else
// GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration."
fps = round(fps)
if(fps <= 0)
@@ -785,7 +778,7 @@
/datum/configuration/proc/loadmaplist(filename)
var/list/Lines = world.file2list(filename)
var/list/Lines = world.file2list(filename)
var/datum/map_config/currentmap = null
for(var/t in Lines)
@@ -831,11 +824,11 @@
maplist[currentmap.map_name] = currentmap
currentmap = null
else
GLOB.diary << "Unknown command in map vote config: '[command]'"
GLOB.config_error_log << "Unknown command in map vote config: '[command]'"
/datum/configuration/proc/loadsql(filename)
var/list/Lines = world.file2list(filename)
var/list/Lines = world.file2list(filename)
for(var/t in Lines)
if(!t)
continue
@@ -875,7 +868,7 @@
if("feedback_tableprefix")
global.sqlfdbktableprefix = value
else
GLOB.diary << "Unknown setting in configuration: '[name]'"
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
/datum/configuration/proc/pick_mode(mode_name)
// I wish I didn't have to instance the game modes in order to look up
+6
View File
@@ -52,6 +52,12 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
/datum/controller/global_vars/Initialize()
gvars_datum_init_order = list()
gvars_datum_protected_varlist = list("gvars_datum_protected_varlist")
//See https://github.com/tgstation/tgstation/issues/26954
for(var/I in typesof(/datum/controller/global_vars/proc))
var/CLEANBOT_RETURNS = "[I]"
pass(CLEANBOT_RETURNS)
for(var/I in vars - gvars_datum_in_built_vars)
var/start_tick = world.time
call(src, "InitGlobal[I]")()
+18 -13
View File
@@ -48,7 +48,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
// Has round started? (So we know what subsystems to run)
var/round_started = 0
var/local_round_started = FALSE //Don't read this var, use SSticker.HasRoundStarted() instead
// The type of the last subsystem to be process()'d.
var/last_type_processed
@@ -189,7 +189,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// Notify the MC that the round has started.
/datum/controller/master/proc/RoundStart()
round_started = 1
local_round_started = TRUE
var/timer = world.time
for (var/datum/controller/subsystem/SS in subsystems)
if (SS.flags & SS_FIRE_IN_LOBBY || SS.flags & SS_TICKER)
@@ -222,7 +222,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// local vars rock
// Schedule the first run of the Subsystems.
round_started = world.has_round_started()
local_round_started = world.has_round_started()
//all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed)
var/list/tickersubsystems = list()
var/list/normalsubsystems = list()
@@ -245,7 +245,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
lobbysubsystems += SS
timer += world.tick_lag * rand(1, 5)
SS.next_fire = timer
else if (round_started)
else if (local_round_started)
timer += world.tick_lag * rand(1, 5)
SS.next_fire = timer
normalsubsystems += SS
@@ -280,7 +280,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
if (world.tick_usage > TICK_LIMIT_MC)
sleep_delta += 2
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5)
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5
sleep(world.tick_lag * (processing + sleep_delta))
continue
@@ -296,7 +296,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time))
new/datum/controller/failsafe() // (re)Start the failsafe.
if (!queue_head || !(iteration % 3))
if (round_started)
if (local_round_started)
subsystems_to_check = normalsubsystems
else
subsystems_to_check = lobbysubsystems
@@ -421,26 +421,31 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
else
tick_precentage = tick_remaining
GLOB.CURRENT_TICKLIMIT = world.tick_usage + tick_precentage
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
GLOB.CURRENT_TICKLIMIT = round(world.tick_usage + tick_precentage)
if (!(queue_node_flags & SS_TICKER))
ran_non_ticker = TRUE
ran = TRUE
tick_usage = world.tick_usage
queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING)
last_type_processed = queue_node
queue_node.state = SS_RUNNING
tick_usage = world.tick_usage
var/state = queue_node.ignite(queue_node_paused)
tick_usage = world.tick_usage - tick_usage
if (state == SS_RUNNING)
state = SS_IDLE
current_tick_budget -= queue_node_priority
tick_usage = world.tick_usage - tick_usage
if (tick_usage < 0)
tick_usage = 0
queue_node.tick_overrun = max(0, MC_AVG_FAST_UP_SLOW_DOWN(queue_node.tick_overrun, tick_usage-tick_precentage))
queue_node.state = state
if (state == SS_PAUSED)
@@ -467,13 +472,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
queue_node.times_fired++
if (queue_node_flags & SS_TICKER)
queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait)
queue_node.next_fire = world.time + (world.tick_lag * (queue_node.wait + (queue_node.tick_overrun/100)))
else if (queue_node_flags & SS_POST_FIRE_TIMING)
queue_node.next_fire = world.time + queue_node.wait
queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
else if (queue_node_flags & SS_KEEP_TIMING)
queue_node.next_fire += queue_node.wait
else
queue_node.next_fire = queue_node.queued_time + queue_node.wait
queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
queue_node.queued_time = 0
+2 -1
View File
@@ -17,6 +17,7 @@
var/next_fire = 0 //scheduled world.time for next fire()
var/cost = 0 //average time to execute
var/tick_usage = 0 //average tick usage
var/tick_overrun = 0 //average tick overrun
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
var/paused_ticks = 0 //ticks this ss is taking to run right now.
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
@@ -168,7 +169,7 @@
if(can_fire && !(SS_NO_FIRE in flags))
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
else
msg = "OFFLINE\t[msg]"
-9
View File
@@ -1,9 +0,0 @@
diff a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm (rejected hunks)
@@ -12,6 +12,7 @@ SUBSYSTEM_DEF(atoms)
var/old_initialized
var/list/late_loaders
+ var/list/created_atoms
var/list/BadInitializeCalls = list()
+246
View File
@@ -0,0 +1,246 @@
SUBSYSTEM_DEF(blackbox)
name = "Blackbox"
wait = 6000
flags = SS_NO_TICK_CHECK
var/list/msg_common = list()
var/list/msg_science = list()
var/list/msg_command = list()
var/list/msg_medical = list()
var/list/msg_engineering = list()
var/list/msg_security = list()
var/list/msg_deathsquad = list()
var/list/msg_syndicate = list()
var/list/msg_service = list()
var/list/msg_cargo = list()
var/list/msg_other = list()
var/list/feedback = list() //list of datum/feedback_variable
//poll population
/datum/controller/subsystem/blackbox/fire()
if(!SSdbcore.Connect())
return
var/playercount = 0
for(var/mob/M in GLOB.player_list)
if(M.client)
playercount += 1
var/admincount = GLOB.admins.len
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON('[world.internet_address]'), '[world.port]')")
query_record_playercount.Execute()
/datum/controller/subsystem/blackbox/Recover()
msg_common = SSblackbox.msg_common
msg_science = SSblackbox.msg_science
msg_command = SSblackbox.msg_command
msg_medical = SSblackbox.msg_medical
msg_engineering = SSblackbox.msg_engineering
msg_security = SSblackbox.msg_security
msg_deathsquad = SSblackbox.msg_deathsquad
msg_syndicate = SSblackbox.msg_syndicate
msg_service = SSblackbox.msg_service
msg_cargo = SSblackbox.msg_cargo
msg_other = SSblackbox.msg_other
feedback = SSblackbox.feedback
//no touchie
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
if(var_name == "feedback")
return FALSE
return ..()
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
return FALSE
/datum/controller/subsystem/blackbox/Shutdown()
var/pda_msg_amt = 0
var/rc_msg_amt = 0
for (var/obj/machinery/message_server/MS in GLOB.message_servers)
if (MS.pda_msgs.len > pda_msg_amt)
pda_msg_amt = MS.pda_msgs.len
if (MS.rc_msgs.len > rc_msg_amt)
rc_msg_amt = MS.rc_msgs.len
set_details("radio_usage","")
add_details("radio_usage","COM-[msg_common.len]")
add_details("radio_usage","SCI-[msg_science.len]")
add_details("radio_usage","HEA-[msg_command.len]")
add_details("radio_usage","MED-[msg_medical.len]")
add_details("radio_usage","ENG-[msg_engineering.len]")
add_details("radio_usage","SEC-[msg_security.len]")
add_details("radio_usage","DTH-[msg_deathsquad.len]")
add_details("radio_usage","SYN-[msg_syndicate.len]")
add_details("radio_usage","SRV-[msg_service.len]")
add_details("radio_usage","CAR-[msg_cargo.len]")
add_details("radio_usage","OTH-[msg_other.len]")
add_details("radio_usage","PDA-[pda_msg_amt]")
add_details("radio_usage","RC-[rc_msg_amt]")
set_details("round_end","[time2text(world.realtime)]") //This one MUST be the last one that gets set.
if (!SSdbcore.Connect())
return
var/sqlrowlist = ""
for (var/datum/feedback_variable/FV in feedback)
if (sqlrowlist != "")
sqlrowlist += ", " //a comma (,) at the start of the first row to insert will trigger a SQL error
sqlrowlist += "(null, Now(), [GLOB.round_id], \"[sanitizeSQL(FV.get_variable())]\", [FV.get_value()], \"[sanitizeSQL(FV.get_details())]\")"
if (sqlrowlist == "")
return
var/datum/DBQuery/query_feedback_save = SSdbcore.NewQuery("INSERT DELAYED IGNORE INTO [format_table_name("feedback")] VALUES " + sqlrowlist)
query_feedback_save.Execute()
/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
switch(freq)
if(1459)
msg_common += blackbox_msg
if(1351)
msg_science += blackbox_msg
if(1353)
msg_command += blackbox_msg
if(1355)
msg_medical += blackbox_msg
if(1357)
msg_engineering += blackbox_msg
if(1359)
msg_security += blackbox_msg
if(1441)
msg_deathsquad += blackbox_msg
if(1213)
msg_syndicate += blackbox_msg
if(1349)
msg_service += blackbox_msg
if(1347)
msg_cargo += blackbox_msg
else
msg_other += blackbox_msg
/datum/controller/subsystem/blackbox/proc/find_feedback_datum(variable)
for(var/datum/feedback_variable/FV in feedback)
if(FV.get_variable() == variable)
return FV
var/datum/feedback_variable/FV = new(variable)
feedback += FV
return FV
/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_value(value)
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.inc(value)
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.dec(value)
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_details(details)
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.add_details(details)
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
if(!SSdbcore.Connect())
return
if(!L || !L.key || !L.mind)
return
var/turf/T = get_turf(L)
var/area/placeofdeath = get_area(T.loc)
var/sqlname = sanitizeSQL(L.real_name)
var/sqlkey = sanitizeSQL(L.ckey)
var/sqljob = sanitizeSQL(L.mind.assigned_role)
var/sqlspecial = sanitizeSQL(L.mind.special_role)
var/sqlpod = sanitizeSQL(placeofdeath.name)
var/laname
var/lakey
if(L.lastattacker && ismob(L.lastattacker))
var/mob/LA = L.lastattacker
laname = sanitizeSQL(LA.real_name)
lakey = sanitizeSQL(LA.key)
var/sqlgender = sanitizeSQL(L.gender)
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
var/sqlfire = sanitizeSQL(L.getFireLoss())
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
var/sqloxy = sanitizeSQL(L.getOxyLoss())
var/sqltox = sanitizeSQL(L.getStaminaLoss())
var/sqlclone = sanitizeSQL(L.getStaminaLoss())
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
var/coord = sanitizeSQL("[L.x], [L.y], [L.z]")
var/map = sanitizeSQL(SSmapping.config.map_name)
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, coord, mapname, server_ip, server_port) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[SQLtime()]', '[laname]', '[lakey]', '[sqlgender]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[coord]', '[map]', INET_ATON('[world.internet_address]'), '[world.port]')")
query_report_death.Execute()
//feedback variable datum, for storing all kinds of data
/datum/feedback_variable
var/variable
var/value
var/details
/datum/feedback_variable/New(param_variable, param_value = 0)
variable = param_variable
value = param_value
/datum/feedback_variable/proc/inc(num = 1)
if (isnum(value))
value += num
else
value = text2num(value)
if (isnum(value))
value += num
else
value = num
/datum/feedback_variable/proc/dec(num = 1)
if (isnum(value))
value -= num
else
value = text2num(value)
if (isnum(value))
value -= num
else
value = -num
/datum/feedback_variable/proc/set_value(num)
if (isnum(num))
value = num
/datum/feedback_variable/proc/get_value()
if (!isnum(value))
return 0
return value
/datum/feedback_variable/proc/get_variable()
return variable
/datum/feedback_variable/proc/set_details(text)
if (istext(text))
details = text
/datum/feedback_variable/proc/add_details(text)
if (istext(text))
text = replacetext(text, " ", "_")
if (!details)
details = text
else
details += " [text]"
/datum/feedback_variable/proc/get_details()
return details
/datum/feedback_variable/proc/get_parsed()
return list(variable,value,details)
+2 -2
View File
@@ -308,7 +308,6 @@ SUBSYSTEM_DEF(job)
Debug("DO non-human failed, Player: [player], Job:[job.title]")
continue
// If the player wants that job on this level, then try give it to him.
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
@@ -319,6 +318,7 @@ SUBSYSTEM_DEF(job)
unassigned -= player
break
// Hand out random jobs to the people who didn't get any in the last check
// Also makes sure that they got their preference correct
for(var/mob/dead/new_player/player in unassigned)
@@ -483,7 +483,7 @@ SUBSYSTEM_DEF(job)
else level4++ //not selected
tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-"
feedback_add_details("job_preferences",tmp_str)
SSblackbox.add_details("job_preferences",tmp_str)
/datum/controller/subsystem/job/proc/PopcapReached()
if(config.hard_popcap || config.extreme_popcap)
+18
View File
@@ -0,0 +1,18 @@
SUBSYSTEM_DEF(language)
name = "Language"
init_order = INIT_ORDER_LANGUAGE
flags = SS_NO_FIRE
/datum/controller/subsystem/language/Initialize(timeofday)
for(var/L in subtypesof(/datum/language))
var/datum/language/language = L
if(!initial(language.key))
continue
GLOB.all_languages += language
var/datum/language/instance = new language
GLOB.language_datum_instances[language] = instance
return ..()
+2 -10
View File
@@ -36,18 +36,10 @@ SUBSYSTEM_DEF(lighting)
for (i in 1 to GLOB.lighting_update_lights.len)
var/datum/light_source/L = GLOB.lighting_update_lights[i]
if (L.check() || QDELETED(L) || L.force_update)
L.remove_lum()
if (!QDELETED(L))
L.apply_lum()
L.update_corners()
else if (L.vis_update) //We smartly update only tiles that became (in) visible to use.
L.smart_vis_update()
L.needs_update = LIGHTING_NO_UPDATE
L.vis_update = FALSE
L.force_update = FALSE
L.needs_update = FALSE
if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
+1 -1
View File
@@ -119,7 +119,7 @@ SUBSYSTEM_DEF(mapping)
INIT_ANNOUNCE("Loading [config.map_name]...")
TryLoadZ(config.GetFullMapPath(), FailedZs, ZLEVEL_STATION)
INIT_ANNOUNCE("Loaded station in [(REALTIMEOFDAY - start_time)/10]s!")
feedback_add_details("map_name", config.map_name)
SSblackbox.add_details("map_name", config.map_name)
if(config.minetype != "lavaland")
INIT_ANNOUNCE("WARNING: A map without lavaland set as it's minetype was loaded! This is being ignored! Update the maploader code!")
+1 -1
View File
@@ -150,7 +150,7 @@ SUBSYSTEM_DEF(pai)
if(!(ROLE_PAI in G.client.prefs.be_special))
continue
//G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
to_chat(G, "<span class='ghostalert'>Someone is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
to_chat(G, "<span class='ghostalert'>[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
var/list/available = list()
for(var/datum/paiCandidate/c in SSpai.candidates)
+69 -8
View File
@@ -9,12 +9,15 @@ SUBSYSTEM_DEF(persistence)
var/list/obj/structure/chisel_message/chisel_messages = list()
var/list/saved_messages = list()
var/savefile/chisel_messages_sav
var/savefile/trophy_sav
var/list/saved_trophies = list()
/datum/controller/subsystem/persistence/Initialize()
LoadSatchels()
LoadPoly()
LoadChiselMessages()
LoadTrophies()
..()
/datum/controller/subsystem/persistence/proc/LoadSatchels()
@@ -71,14 +74,14 @@ SUBSYSTEM_DEF(persistence)
break //Who's been duping the bird?!
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
var/saved_json
chisel_messages_sav[SSmapping.config.map_name] >> saved_json
if(!saved_json)
return
var/saved_messages = json_decode(saved_json)
var/list/saved_messages = json_decode(saved_json)
for(var/item in saved_messages)
if(!islist(item))
@@ -100,15 +103,57 @@ SUBSYSTEM_DEF(persistence)
var/obj/structure/chisel_message/M = new(T)
M.unpack(item)
if(!M.loc)
M.persists = FALSE
qdel(M)
if(!QDELETED(M))
M.unpack(item)
log_world("Loaded [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
/datum/controller/subsystem/persistence/proc/LoadTrophies()
trophy_sav = new /savefile("data/npc_saves/TrophyItems.sav")
var/saved_json
trophy_sav >> saved_json
if(!saved_json)
return
var/decoded_json = json_decode(saved_json)
if(!islist(decoded_json))
return
saved_trophies = decoded_json
SetUpTrophies(saved_trophies.Copy())
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
for(var/A in GLOB.trophy_cases)
var/obj/structure/displaycase/trophy/T = A
T.added_roundstart = TRUE
var/trophy_data = pick_n_take(trophy_items)
if(!islist(trophy_data))
continue
var/list/chosen_trophy = trophy_data
if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
continue
var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
if(!path)
continue
T.showpiece = new /obj/item/showpiece_dummy(T, path)
T.trophy_message = chosen_trophy["message"]
T.placer_key = chosen_trophy["placer_key"]
T.update_icon()
/datum/controller/subsystem/persistence/proc/CollectData()
CollectChiselMessages()
CollectSecretSatchels()
CollectTrophies()
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
for(var/A in new_secret_satchels)
@@ -129,10 +174,26 @@ SUBSYSTEM_DEF(persistence)
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
for(var/obj/structure/chisel_message/M in chisel_messages)
saved_messages += list(M.pack())
log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages)
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
saved_messages += list(M.pack()) // dm eats one list.
saved_messages += list(M.pack()) // dm eats one list
/datum/controller/subsystem/persistence/proc/CollectTrophies()
trophy_sav << json_encode(saved_trophies)
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
if(!T.added_roundstart && T.showpiece)
var/list/data = list()
data["path"] = T.showpiece.type
data["message"] = T.trophy_message
data["placer_key"] = T.placer_key
saved_trophies += list(data)
+15 -1
View File
@@ -3,14 +3,20 @@
SUBSYSTEM_DEF(ping)
name = "Ping"
wait = 6
flags = SS_NO_INIT|SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
priority = 10
var/list/currentrun
/datum/controller/subsystem/ping/Initialize()
if (config.hub)
world.visibility = 1
..()
/datum/controller/subsystem/ping/fire(resumed = FALSE)
if (!resumed)
src.currentrun = GLOB.clients.Copy()
var/round_started = Master.round_started
var/list/currentrun = src.currentrun
while (length(currentrun))
var/client/C = currentrun[currentrun.len]
@@ -19,7 +25,15 @@ SUBSYSTEM_DEF(ping)
if (MC_TICK_CHECK)
return
continue
if(round_started && C.is_afk(INACTIVITY_KICK))
if(!istype(C.mob, /mob/dead))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than 10 minutes and have been disconnected.</span>")
qdel(C)
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
return
@@ -5,7 +5,7 @@ PROCESSING_SUBSYSTEM_DEF(flightpacks)
stat_tag = "FM"
flags = SS_NO_INIT|SS_TICKER|SS_KEEP_TIMING
var/flightsuit_processing = FLIGHTSUIT_PROCESSING_FULL
var/flightsuit_processing = FLIGHTSUIT_PROCESSING_NONE
/datum/controller/subsystem/processing/flightpacks/Initialize()
sync_flightsuit_processing()
+24 -8
View File
@@ -1,17 +1,28 @@
#define PING_BUFFER_TIME 25
SUBSYSTEM_DEF(server_maint)
name = "Server Tasks"
wait = 6000
flags = SS_NO_TICK_CHECK
wait = 6
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
priority = 10
var/list/currentrun
/datum/controller/subsystem/server_maint/Initialize(timeofday)
if (config.hub)
world.visibility = 1
..()
/datum/controller/subsystem/server_maint/fire()
//handle kicking inactive players
if(config.kick_inactive)
for(var/client/C in GLOB.clients)
/datum/controller/subsystem/server_maint/fire(resumed = FALSE)
if(!resumed)
src.currentrun = GLOB.clients.Copy()
var/list/currentrun = src.currentrun
var/round_started = SSticker.HasRoundStarted()
for(var/I in currentrun)
var/client/C = I
//handle kicking inactive players
if(round_started && config.kick_inactive)
if(C.is_afk(config.afk_period))
var/cmob = C.mob
if(!(istype(cmob, /mob/dead/observer) || (istype(cmob, /mob/dead) && C.holder)))
@@ -19,5 +30,10 @@ SUBSYSTEM_DEF(server_maint)
to_chat(C, "<span class='danger'>You have been inactive for more than [config.afk_period / 600] minutes and have been disconnected.</span>")
qdel(C)
if(config.sql_enabled)
sql_poll_population()
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
return
#undef PING_BUFFER_TIME
+9 -8
View File
@@ -243,7 +243,7 @@ SUBSYSTEM_DEF(ticker)
send2irc("Server", "Round of [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)
if(current_state < GAME_STATE_PLAYING)
if(!HasRoundStarted())
LAZYADD(round_start_events, cb)
else
cb.InvokeAsync()
@@ -625,8 +625,8 @@ SUBSYSTEM_DEF(ticker)
if(selected_tip)
m = selected_tip
else
var/list/randomtips = world.file2list("config/tips.txt")
var/list/memetips = world.file2list("config/sillytips.txt")
var/list/randomtips = world.file2list("strings/tips.txt")
var/list/memetips = world.file2list("strings/sillytips.txt")
if(randomtips.len && prob(95))
m = pick(randomtips)
else if(memetips.len)
@@ -672,15 +672,16 @@ SUBSYSTEM_DEF(ticker)
return
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/.proc/maprotate)
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
return current_state >= GAME_STATE_PLAYING
/datum/controller/subsystem/ticker/proc/IsRoundInProgress()
return current_state == GAME_STATE_PLAYING
/proc/send_gamemode_vote()
SSticker.modevoted = TRUE
SSvote.initiate_vote("roundtype","server")
/world/proc/has_round_started()
if (SSticker && SSticker.current_state >= GAME_STATE_PLAYING)
return TRUE
return FALSE
/datum/controller/subsystem/ticker/Recover()
current_state = SSticker.current_state
force_ending = SSticker.force_ending
+1 -1
View File
@@ -124,7 +124,7 @@ SUBSYSTEM_DEF(vote)
if("gamemode")
if(GLOB.master_mode != .)
world.save_mode(.)
if(SSticker && SSticker.mode)
if(SSticker.HasRoundStarted())
restart = 1
else
GLOB.master_mode = .