Controllers

This commit is contained in:
Poojawa
2018-09-11 02:04:10 -05:00
parent 07cb9572bd
commit 09512a6001
37 changed files with 522 additions and 447 deletions

View File

@@ -1,6 +1,9 @@
#define LIST_MODE_NUM 0
#define LIST_MODE_TEXT 1
#define LIST_MODE_FLAG 2
#define VALUE_MODE_NUM 0
#define VALUE_MODE_TEXT 1
#define VALUE_MODE_FLAG 2
#define KEY_MODE_TEXT 0
#define KEY_MODE_TYPE 1
/datum/config_entry
var/name //read-only, this is determined by the last portion of the derived entry type
@@ -15,6 +18,8 @@
var/protection = NONE
var/abstract_type = /datum/config_entry //do not instantiate if type matches this
var/vv_VAS = TRUE //Force validate and set on VV. VAS proccall guard will run regardless.
var/dupes_allowed = FALSE
/datum/config_entry/New()
@@ -37,20 +42,23 @@
. &= !(protection & CONFIG_ENTRY_HIDDEN)
/datum/config_entry/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list(NAMEOF(src, name), NAMEOF(src, default), NAMEOF(src, resident_file), NAMEOF(src, protection), NAMEOF(src, abstract_type), NAMEOF(src, modified), NAMEOF(src, dupes_allowed))
var/static/list/banned_edits = list(NAMEOF(src, name), NAMEOF(src, vv_VAS), NAMEOF(src, default), NAMEOF(src, resident_file), NAMEOF(src, protection), NAMEOF(src, abstract_type), NAMEOF(src, modified), NAMEOF(src, dupes_allowed))
if(var_name == NAMEOF(src, config_entry_value))
if(protection & CONFIG_ENTRY_LOCKED)
return FALSE
. = ValidateAndSet("[var_value]")
if(.)
datum_flags |= DF_VAR_EDITED
return
if(vv_VAS)
. = ValidateAndSet("[var_value]")
if(.)
datum_flags |= DF_VAR_EDITED
return
else
return ..()
if(var_name in banned_edits)
return FALSE
return ..()
/datum/config_entry/proc/VASProcCallGuard(str_val)
. = !(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "ValidateAndSet" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
. = !((protection & CONFIG_ENTRY_LOCKED) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "ValidateAndSet" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
if(!.)
log_admin_private("Config set of [type] to [str_val] attempted by [key_name(usr)]")
@@ -58,32 +66,6 @@
VASProcCallGuard(str_val)
CRASH("Invalid config entry type!")
/datum/config_entry/proc/ValidateKeyedList(str_val, list_mode, splitter)
str_val = trim(str_val)
var/key_pos = findtext(str_val, splitter)
var/key_name = null
var/key_value = null
if(key_pos || list_mode == LIST_MODE_FLAG)
key_name = lowertext(copytext(str_val, 1, key_pos))
key_value = copytext(str_val, key_pos + 1)
var/temp
var/continue_check
switch(list_mode)
if(LIST_MODE_FLAG)
temp = TRUE
continue_check = TRUE
if(LIST_MODE_NUM)
temp = text2num(key_value)
continue_check = !isnull(temp)
if(LIST_MODE_TEXT)
temp = key_value
continue_check = temp
if(continue_check && ValidateListEntry(key_name, temp))
config_entry_value[key_name] = temp
return TRUE
return FALSE
/datum/config_entry/proc/ValidateListEntry(key_name, key_value)
return TRUE
@@ -156,44 +138,59 @@
config_entry_value = new_list
return TRUE
/datum/config_entry/keyed_flag_list
abstract_type = /datum/config_entry/keyed_flag_list
config_entry_value = list()
dupes_allowed = TRUE
/datum/config_entry/keyed_flag_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
return ValidateKeyedList(str_val, LIST_MODE_FLAG, " ")
/datum/config_entry/keyed_number_list
abstract_type = /datum/config_entry/keyed_number_list
/datum/config_entry/keyed_list
abstract_type = /datum/config_entry/keyed_list
config_entry_value = list()
dupes_allowed = TRUE
vv_VAS = FALSE //VAS will not allow things like deleting from lists, it'll just bug horribly.
var/key_mode
var/value_mode
var/splitter = " "
/datum/config_entry/keyed_number_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
/datum/config_entry/keyed_list/New()
. = ..()
if(isnull(key_mode) || isnull(value_mode))
CRASH("Keyed list of type [type] created with null key or value mode!")
/datum/config_entry/keyed_number_list/ValidateAndSet(str_val)
/datum/config_entry/keyed_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
return ValidateKeyedList(str_val, LIST_MODE_NUM, splitter)
/datum/config_entry/keyed_string_list
abstract_type = /datum/config_entry/keyed_string_list
config_entry_value = list()
dupes_allowed = TRUE
var/splitter = " "
str_val = trim(str_val)
var/key_pos = findtext(str_val, splitter)
var/key_name = null
var/key_value = null
/datum/config_entry/keyed_string_list/vv_edit_var(var_name, var_value)
if(key_pos || value_mode == VALUE_MODE_FLAG)
key_name = lowertext(copytext(str_val, 1, key_pos))
key_value = copytext(str_val, key_pos + 1)
var/new_key
var/new_value
var/continue_check_value
var/continue_check_key
switch(key_mode)
if(KEY_MODE_TEXT)
new_key = key_name
continue_check_key = new_key
if(KEY_MODE_TYPE)
new_key = key_name
if(!ispath(new_key))
new_key = text2path(new_key)
continue_check_key = ispath(new_key)
switch(value_mode)
if(VALUE_MODE_FLAG)
new_value = TRUE
continue_check_value = TRUE
if(VALUE_MODE_NUM)
new_value = text2num(key_value)
continue_check_value = !isnull(new_value)
if(VALUE_MODE_TEXT)
new_value = key_value
continue_check_value = new_value
if(continue_check_value && continue_check_key && ValidateListEntry(new_key, new_value))
config_entry_value[new_key] = new_value
return TRUE
return FALSE
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
/datum/config_entry/keyed_string_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
return ValidateKeyedList(str_val, LIST_MODE_TEXT, splitter)
#undef LIST_MODE_NUM
#undef LIST_MODE_TEXT
#undef LIST_MODE_FLAG

View File

@@ -20,7 +20,19 @@
var/motd
/datum/controller/configuration/proc/Load()
/datum/controller/configuration/proc/admin_reload()
if(IsAdminAdvancedProcCall())
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/Load(_directory)
if(IsAdminAdvancedProcCall()) //If admin proccall is detected down the line it will horribly break everything.
return
if(_directory)
directory = _directory
if(entries)
CRASH("[THIS_PROC_TYPE_WEIRD] called more than once!")
InitEntries()
@@ -36,12 +48,18 @@
loadmaplist(CONFIG_MAPS_FILE)
LoadMOTD()
/datum/controller/configuration/Destroy()
/datum/controller/configuration/proc/full_wipe()
if(IsAdminAdvancedProcCall())
return
entries_by_type.Cut()
QDEL_LIST_ASSOC_VAL(entries)
entries = null
QDEL_LIST_ASSOC_VAL(maplist)
maplist = null
QDEL_NULL(defaultmap)
/datum/controller/configuration/Destroy()
full_wipe()
config = null
return ..()
@@ -84,9 +102,10 @@
var/list/lines = world.file2list("[directory]/[filename]")
var/list/_entries = entries
for(var/L in lines)
L = trim(L)
if(!L)
continue
var/firstchar = copytext(L, 1, 2)
if(firstchar == "#")
continue
@@ -107,7 +126,7 @@
if(!entry)
continue
if(entry == "$include")
if(!value)
log_config("Warning: Invalid $include directive: [value]")
@@ -115,7 +134,7 @@
LoadEntries(value, stack)
++.
continue
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("Unknown setting in configuration: '[entry]'")
@@ -137,19 +156,19 @@
E = new_ver
else
warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()")
var/validated = E.ValidateAndSet(value)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else
else
if(E.modified && !E.dupes_allowed)
log_config("Duplicate setting for [entry] ([value], [E.resident_file]) detected! Using latest.")
E.resident_file = filename
if(validated)
E.modified = TRUE
++.
/datum/controller/configuration/can_vv_get(var_name)
@@ -165,9 +184,6 @@
stat("[name]:", statclick)
/datum/controller/configuration/proc/Get(entry_type)
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
@@ -175,12 +191,12 @@
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
return E.config_entry_value
/datum/controller/configuration/proc/Set(entry_type, new_val)
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]")
return
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
@@ -188,6 +204,9 @@
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
if((E.protection & CONFIG_ENTRY_LOCKED) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]")
return
return E.ValidateAndSet("[new_val]")
/datum/controller/configuration/proc/LoadModes()
@@ -197,7 +216,7 @@
mode_reports = list()
mode_false_report_weight = list()
votable_modes = list()
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
for(var/T in gamemode_cache)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
@@ -293,9 +312,9 @@
/datum/controller/configuration/proc/get_runnable_modes()
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_list/max_pop)
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
for(var/T in gamemode_cache)
var/datum/game_mode/M = new T()
@@ -323,9 +342,9 @@
/datum/controller/configuration/proc/get_runnable_midround_modes(crew)
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_list/max_pop)
for(var/T in (gamemode_cache - SSticker.mode.type))
var/datum/game_mode/M = new T()
if(!(M.config_tag in modes))

View File

@@ -4,10 +4,12 @@
/datum/config_entry/string/comms_key/ValidateAndSet(str_val)
return str_val != "default_pwd" && length(str_val) > 6 && ..()
/datum/config_entry/keyed_string_list/cross_server
/datum/config_entry/keyed_list/cross_server
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_TEXT
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/keyed_string_list/cross_server/ValidateAndSet(str_val)
/datum/config_entry/keyed_list/cross_server/ValidateAndSet(str_val)
. = ..()
if(.)
var/list/newv = list()
@@ -15,7 +17,7 @@
newv[replacetext(I, "+", " ")] = config_entry_value[I]
config_entry_value = newv
/datum/config_entry/keyed_string_list/cross_server/ValidateListEntry(key_name, key_value)
/datum/config_entry/keyed_list/cross_server/ValidateListEntry(key_name, key_value)
return key_value != "byond:\\address:port" && ..()
/datum/config_entry/string/cross_comms_name

View File

@@ -1,31 +1,43 @@
/datum/config_entry/number_list/repeated_mode_adjust
/datum/config_entry/keyed_number_list/probability
/datum/config_entry/keyed_list/probability
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
/datum/config_entry/keyed_number_list/probability/ValidateListEntry(key_name)
/datum/config_entry/keyed_list/probability/ValidateListEntry(key_name)
return key_name in config.modes
/datum/config_entry/keyed_number_list/max_pop
/datum/config_entry/keyed_list/max_pop
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
/datum/config_entry/keyed_number_list/max_pop/ValidateListEntry(key_name)
/datum/config_entry/keyed_list/max_pop/ValidateListEntry(key_name)
return key_name in config.modes
/datum/config_entry/keyed_number_list/min_pop
/datum/config_entry/keyed_list/min_pop
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
/datum/config_entry/keyed_number_list/min_pop/ValidateListEntry(key_name, key_value)
/datum/config_entry/keyed_list/min_pop/ValidateListEntry(key_name, key_value)
return key_name in config.modes
/datum/config_entry/keyed_flag_list/continuous // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_list/continuous // which roundtypes continue if all antagonists die
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
/datum/config_entry/keyed_flag_list/continuous/ValidateListEntry(key_name, key_value)
/datum/config_entry/keyed_list/continuous/ValidateListEntry(key_name, key_value)
return key_name in config.modes
/datum/config_entry/keyed_flag_list/midround_antag // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_list/midround_antag // which roundtypes use the midround antagonist system
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
/datum/config_entry/keyed_flag_list/midround_antag/ValidateListEntry(key_name, key_value)
/datum/config_entry/keyed_list/midround_antag/ValidateListEntry(key_name, key_value)
return key_name in config.modes
/datum/config_entry/keyed_string_list/policy
/datum/config_entry/keyed_list/policy
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_TEXT
/datum/config_entry/number/damage_multiplier
config_entry_value = 1
@@ -124,7 +136,9 @@
/datum/config_entry/flag/show_game_type_odds //if set this allows players to see the odds of each roundtype on the get revision screen
/datum/config_entry/keyed_flag_list/roundstart_races //races you can play as from the get go.
/datum/config_entry/keyed_list/roundstart_races //races you can play as from the get go.
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
/datum/config_entry/flag/join_with_mutant_humans //players can pick mutant bodyparts for humans before joining the game
@@ -174,28 +188,67 @@
/datum/config_entry/flag/emojis
/datum/config_entry/number/run_delay //Used for modifying movement speed for mobs.
var/static/value_cache = 0
/datum/config_entry/keyed_list/multiplicative_movespeed
key_mode = KEY_MODE_TYPE
value_mode = VALUE_MODE_NUM
config_entry_value = list( //DEFAULTS
/mob/living/simple_animal = 1,
/mob/living/silicon/pai = 1,
/mob/living/carbon/alien/humanoid/hunter = -1,
/mob/living/carbon/alien/humanoid/royal/praetorian = 1,
/mob/living/carbon/alien/humanoid/royal/queen = 3
)
/datum/config_entry/number/run_delay/ValidateAndSet()
/datum/config_entry/keyed_list/multiplicative_movespeed/ValidateAndSet()
. = ..()
if(.)
value_cache = config_entry_value
update_config_movespeed_type_lookup(TRUE)
/datum/config_entry/number/walk_delay
var/static/value_cache = 0
/datum/config_entry/keyed_list/multiplicative_movespeed/vv_edit_var(var_name, var_value)
. = ..()
if(. && (var_name == NAMEOF(src, config_entry_value)))
update_config_movespeed_type_lookup(TRUE)
/datum/config_entry/number/walk_delay/ValidateAndSet()
/datum/config_entry/number/movedelay //Used for modifying movement speed for mobs.
abstract_type = /datum/config_entry/number/movedelay
/datum/config_entry/number/movedelay/ValidateAndSet()
. = ..()
if(.)
value_cache = config_entry_value
update_mob_config_movespeeds()
/datum/config_entry/number/human_delay //Mob specific modifiers. NOTE: These will affect different mob types in different ways
/datum/config_entry/number/robot_delay
/datum/config_entry/number/monkey_delay
/datum/config_entry/number/alien_delay
/datum/config_entry/number/slime_delay
/datum/config_entry/number/animal_delay
/datum/config_entry/number/movedelay/vv_edit_var(var_name, var_value)
. = ..()
if(. && (var_name == NAMEOF(src, config_entry_value)))
update_mob_config_movespeeds()
/datum/config_entry/number/movedelay/run_delay
/datum/config_entry/number/movedelay/walk_delay
/////////////////////////////////////////////////Outdated move delay
/datum/config_entry/number/outdated_movedelay
deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed
abstract_type = /datum/config_entry/number/outdated_movedelay
var/movedelay_type
/datum/config_entry/number/outdated_movedelay/DeprecationUpdate(value)
return "[movedelay_type] [value]"
/datum/config_entry/number/outdated_movedelay/human_delay
movedelay_type = /mob/living/carbon/human
/datum/config_entry/number/outdated_movedelay/robot_delay
movedelay_type = /mob/living/silicon/robot
/datum/config_entry/number/outdated_movedelay/monkey_delay
movedelay_type = /mob/living/carbon/monkey
/datum/config_entry/number/outdated_movedelay/alien_delay
movedelay_type = /mob/living/carbon/alien
/datum/config_entry/number/outdated_movedelay/slime_delay
movedelay_type = /mob/living/simple_animal/slime
/datum/config_entry/number/outdated_movedelay/animal_delay
movedelay_type = /mob/living/simple_animal
/////////////////////////////////////////////////
/datum/config_entry/flag/roundstart_away //Will random away mission be loaded.
@@ -219,9 +272,13 @@
config_entry_value = 12
min_val = 0
/datum/config_entry/keyed_flag_list/random_laws
/datum/config_entry/keyed_list/random_laws
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
/datum/config_entry/keyed_number_list/law_weight
/datum/config_entry/keyed_list/law_weight
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
splitter = ","
/datum/config_entry/number/overflow_cap
@@ -286,25 +343,10 @@
/datum/config_entry/flag/shift_time_realtime
/datum/config_entry/keyed_number_list/antag_rep
/datum/config_entry/keyed_list/antag_rep
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
/datum/config_entry/number/monkeycap
config_entry_value = 64
min_val = 0
//Cit changes - Adds config options for crew objectives and miscreants
/datum/config_entry/flag/allow_crew_objectives
/datum/config_entry/flag/allow_miscreants
/datum/config_entry/flag/allow_extended_miscreants
/datum/config_entry/flag/nightshift_enabled
/datum/config_entry/number/nightshift_start
config_entry_value = 20
/datum/config_entry/number/nightshift_finish
config_entry_value = 6
//End of Cit changes

View File

@@ -49,6 +49,8 @@
/datum/config_entry/flag/log_pda // log pda messages
/datum/config_entry/flag/log_telecomms // log telecomms messages
/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
/datum/config_entry/flag/log_world_topic // log all world.Topic() calls
@@ -324,8 +326,6 @@
/datum/config_entry/flag/allow_map_voting
/datum/config_entry/flag/generate_minimaps
/datum/config_entry/number/client_warn_version
config_entry_value = null
min_val = 500

View File

@@ -30,11 +30,6 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
stat("Globals:", statclick.update("Edit"))
/datum/controller/global_vars/can_vv_get(var_name)
if(gvars_datum_protected_varlist[var_name])
return FALSE
return ..()
/datum/controller/global_vars/vv_edit_var(var_name, var_value)
if(gvars_datum_protected_varlist[var_name])
return FALSE

View File

@@ -71,7 +71,7 @@ SUBSYSTEM_DEF(air)
setup_atmos_machinery()
setup_pipenets()
gas_reactions = init_gas_reactions()
..()
return ..()
/datum/controller/subsystem/air/fire(resumed = 0)
@@ -300,9 +300,12 @@ SUBSYSTEM_DEF(air)
var/list/active_turfs = src.active_turfs
var/times_fired = ++src.times_fired
// Clear active turfs - faster than removing every single turf in the world
// one-by-one, and Initalize_Atmos only ever adds `src` back in.
active_turfs.Cut()
for(var/thing in turfs_to_init)
var/turf/T = thing
active_turfs -= T
if (T.blocks_air)
continue
T.Initalize_Atmos(times_fired)

View File

@@ -11,7 +11,6 @@ SUBSYSTEM_DEF(atoms)
var/old_initialized
var/list/late_loaders
var/list/created_atoms
var/list/BadInitializeCalls = list()
@@ -33,13 +32,11 @@ SUBSYSTEM_DEF(atoms)
var/count
var/list/mapload_arg = list(TRUE)
if(atoms)
created_atoms = list()
count = atoms.len
for(var/I in atoms)
var/atom/A = I
if(!(A.flags_1 & INITIALIZED_1))
if(InitAtom(I, mapload_arg))
atoms -= I
InitAtom(I, mapload_arg)
CHECK_TICK
else
count = 0
@@ -61,10 +58,6 @@ SUBSYSTEM_DEF(atoms)
testing("Late initialized [late_loaders.len] atoms")
late_loaders.Cut()
if(atoms)
. = created_atoms + atoms
created_atoms = null
/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments)
var/the_type = A.type
if(QDELING(A))

View File

@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(blackbox)
var/sealed = FALSE //time to stop tracking stats?
var/list/versions = list("antagonists" = 3,
"admin_secrets_fun_used" = 2,
"explosion" = 2,
"time_dilation_current" = 3,
"science_techweb_unlock" = 2,
"round_end_stats" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
@@ -67,8 +68,8 @@ SUBSYSTEM_DEF(blackbox)
return FALSE
return ..()
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
//Recorded on subsystem shutdown
/datum/controller/subsystem/blackbox/proc/FinalFeedback()
record_feedback("tally", "ahelp_stats", GLOB.ahelp_tickets.active_tickets.len, "unresolved")
for (var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
if (MS.pda_msgs.len)
@@ -76,6 +77,14 @@ SUBSYSTEM_DEF(blackbox)
if (MS.rc_msgs.len)
record_feedback("tally", "radio_usage", MS.rc_msgs.len, "request console")
for(var/player_key in GLOB.player_details)
var/datum/player_details/PD = GLOB.player_details[player_key]
record_feedback("tally", "client_byond_version", 1, PD.byond_version)
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
FinalFeedback()
if (!SSdbcore.Connect())
return
@@ -321,5 +330,6 @@ Versioning
suicide = sanitizeSQL(suicide)
map = sanitizeSQL(map)
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, last_words, suicide) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[last_words]', [suicide])")
query_report_death.Execute()
qdel(query_report_death)
if(query_report_death)
query_report_death.Execute(async = TRUE)
qdel(query_report_death)

View File

@@ -25,7 +25,7 @@ SUBSYSTEM_DEF(communications)
else
priority_announce(html_decode(user.treat_message(input)), null, 'sound/misc/announce.ogg', "Captain")
nonsilicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN
log_talk(user,"[key_name(user)] has made a priority announcement: [input]",LOGSAY)
user.log_talk(input, LOG_SAY, tag="priority announcement")
message_admins("[ADMIN_LOOKUPFLW(user)] has made a priority announcement.")
/datum/controller/subsystem/communications/proc/send_message(datum/comm_message/sending,print = TRUE,unique = FALSE)

View File

@@ -17,7 +17,7 @@ SUBSYSTEM_DEF(disease)
for(var/common_disease_type in all_common_diseases)
var/datum/disease/prototype = new common_disease_type()
archive_diseases[prototype.GetDiseaseID()] = prototype
..()
return ..()
/datum/controller/subsystem/disease/stat_entry(msg)
..("P:[active_diseases.len]")

View File

@@ -22,7 +22,7 @@ SUBSYSTEM_DEF(events)
control += E //add it to the list of all events (controls)
reschedule()
getHoliday()
..()
return ..()
/datum/controller/subsystem/events/fire(resumed = 0)

View File

@@ -85,41 +85,21 @@ SUBSYSTEM_DEF(garbage)
/datum/controller/subsystem/garbage/fire()
//the fact that this resets its processing each fire (rather then resume where it left off) is intentional.
var/queue = GC_QUEUE_PREQUEUE
var/queue = GC_QUEUE_CHECK
while (state == SS_RUNNING)
switch (queue)
if (GC_QUEUE_PREQUEUE)
HandlePreQueue()
queue = GC_QUEUE_PREQUEUE+1
if (GC_QUEUE_CHECK)
HandleQueue(GC_QUEUE_CHECK)
queue = GC_QUEUE_CHECK+1
if (GC_QUEUE_HARDDELETE)
HandleQueue(GC_QUEUE_HARDDELETE)
if (state == SS_PAUSED) //make us wait again before the next run.
state = SS_RUNNING
break
if (state == SS_PAUSED) //make us wait again before the next run.
state = SS_RUNNING
//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond.
//Don't attempt to optimize, not worth the effort.
/datum/controller/subsystem/garbage/proc/HandlePreQueue()
var/list/tobequeued = queues[GC_QUEUE_PREQUEUE]
var/static/count = 0
if (count)
var/c = count
count = 0 //so if we runtime on the Cut, we don't try again.
tobequeued.Cut(1,c+1)
for (var/ref in tobequeued)
count++
Queue(ref, GC_QUEUE_PREQUEUE+1)
if (MC_TICK_CHECK)
break
if (count)
tobequeued.Cut(1,count+1)
count = 0
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
if (level == GC_QUEUE_CHECK)
@@ -141,7 +121,7 @@ SUBSYSTEM_DEF(garbage)
if (!refID)
count++
if (MC_TICK_CHECK)
break
return
continue
var/GCd_at_time = queue[refID]
@@ -160,7 +140,7 @@ SUBSYSTEM_DEF(garbage)
reference_find_on_fail -= refID //It's deleted we don't care anymore.
#endif
if (MC_TICK_CHECK)
break
return
continue
// Something's still referring to the qdel'd object.
@@ -183,27 +163,20 @@ SUBSYSTEM_DEF(garbage)
if (GC_QUEUE_HARDDELETE)
HardDelete(D)
if (MC_TICK_CHECK)
break
return
continue
Queue(D, level+1)
if (MC_TICK_CHECK)
break
return
if (count)
queue.Cut(1,count+1)
count = 0
/datum/controller/subsystem/garbage/proc/PreQueue(datum/D)
if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
queues[GC_QUEUE_PREQUEUE] += D
D.gc_destroyed = GC_QUEUED_FOR_QUEUING
/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK)
if (isnull(D))
return
if (D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL)
level = GC_QUEUE_HARDDELETE
if (level > GC_QUEUE_COUNT)
HardDelete(D)
return
@@ -249,11 +222,6 @@ SUBSYSTEM_DEF(garbage)
message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).")
postpone(time)
/datum/controller/subsystem/garbage/proc/HardQueue(datum/D)
if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
queues[GC_QUEUE_PREQUEUE] += D
D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
/datum/controller/subsystem/garbage/Recover()
if (istype(SSgarbage.queues))
for (var/i in 1 to SSgarbage.queues.len)
@@ -308,7 +276,7 @@ SUBSYSTEM_DEF(garbage)
return
switch(hint)
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
if (QDEL_HINT_IWILLGC)
D.gc_destroyed = world.time
return
@@ -328,18 +296,18 @@ SUBSYSTEM_DEF(garbage)
#endif
I.no_respect_force++
SSgarbage.PreQueue(D)
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate()
SSgarbage.HardQueue(D)
SSgarbage.Queue(D)
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete
SSgarbage.Queue(D, GC_QUEUE_HARDDELETE)
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
SSgarbage.HardDelete(D)
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
#ifdef TESTING
D.find_references()
#endif
if (QDEL_HINT_IFFAIL_FINDREFERENCE)
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
#ifdef TESTING
SSgarbage.reference_find_on_fail[REF(D)] = TRUE
#endif
@@ -349,7 +317,7 @@ SUBSYSTEM_DEF(garbage)
testing("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
#endif
I.no_hint++
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")

View File

@@ -39,4 +39,4 @@ SUBSYSTEM_DEF(icon_smooth)
smooth_icon(A)
CHECK_TICK
..()
return ..()

View File

@@ -21,7 +21,7 @@ SUBSYSTEM_DEF(job)
LoadJobs()
generate_selectable_species()
set_overflow_role(CONFIG_GET(string/overflow_job))
..()
return ..()
/datum/controller/subsystem/job/proc/set_overflow_role(new_overflow_role)
var/datum/job/new_overflow = GetJob(new_overflow_role)
@@ -583,7 +583,7 @@ SUBSYSTEM_DEF(job)
return
//pick an open spot on arrivals and dump em
var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival))
var/list/arrivals_turfs = shuffle(GLOB.areas_by_type[/area/shuttle/arrival]))
if(arrivals_turfs.len)
for(var/turf/T in arrivals_turfs)
if(!is_blocked_turf(T, TRUE))

View File

@@ -22,10 +22,10 @@ SUBSYSTEM_DEF(lighting)
create_all_lighting_objects()
initialized = TRUE
fire(FALSE, TRUE)
..()
return ..()
/datum/controller/subsystem/lighting/fire(resumed, init_tick_checks)
MC_SPLIT_TICK_INIT(3)

View File

@@ -9,7 +9,7 @@ SUBSYSTEM_DEF(machines)
/datum/controller/subsystem/machines/Initialize()
makepowernets()
fire()
..()
return ..()
/datum/controller/subsystem/machines/proc/makepowernets()
for(var/datum/powernet/PN in powernets)

View File

@@ -33,7 +33,6 @@ SUBSYSTEM_DEF(mapping)
var/list/z_list
var/datum/space_level/transit
var/datum/space_level/empty_space
var/dmm_suite/loader
/datum/controller/subsystem/mapping/PreInit()
if(!config)
@@ -54,7 +53,6 @@ SUBSYSTEM_DEF(mapping)
if(!config || config.defaulted)
to_chat(world, "<span class='boldannounce'>Unable to load next or default map config, defaulting to Box Station</span>")
config = old_config
loader = new
loadWorld()
repopulate_sorted_areas()
process_teleport_locs() //Sets up the wizard teleport locations
@@ -94,9 +92,8 @@ SUBSYSTEM_DEF(mapping)
// Set up Z-level transitions.
setup_map_transitions()
generate_station_area_list()
QDEL_NULL(loader)
initialize_reserved_level()
..()
return ..()
/* Nuke threats, for making the blue tiles on the station go RED
Used by the AI doomsday and the self destruct nuke.
@@ -170,6 +167,7 @@ SUBSYSTEM_DEF(mapping)
#define INIT_ANNOUNCE(X) to_chat(world, "<span class='boldannounce'>[X]</span>"); log_world(X)
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE)
. = list()
var/start_time = REALTIMEOFDAY
if (!islist(files)) // handle single-level maps
@@ -177,10 +175,15 @@ SUBSYSTEM_DEF(mapping)
// check that the total z count of all maps matches the list of traits
var/total_z = 0
var/list/parsed_maps = list()
for (var/file in files)
var/full_path = "_maps/[path]/[file]"
var/bounds = loader.load_map(file(full_path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE)
files[file] = total_z // save the start Z of this file
var/datum/parsed_map/pm = new(file(full_path))
var/bounds = pm?.bounds
if (!bounds)
errorList |= full_path
continue
parsed_maps[pm] = total_z // save the start Z of this file
total_z += bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1
if (!length(traits)) // null or empty - default
@@ -201,12 +204,13 @@ SUBSYSTEM_DEF(mapping)
++i
// load the maps
for (var/file in files)
var/full_path = "_maps/[path]/[file]"
if(!loader.load_map(file(full_path), 0, 0, start_z + files[file], no_changeturf = TRUE))
errorList |= full_path
for (var/P in parsed_maps)
var/datum/parsed_map/pm = P
if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE))
errorList |= pm.original_path
if(!silent)
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
return parsed_maps
/datum/controller/subsystem/mapping/proc/loadWorld()
//if any of these fail, something has gone horribly, HORRIBLY, wrong
@@ -456,7 +460,13 @@ GLOBAL_LIST_EMPTY(the_station_areas)
for(var/i in levels_by_trait(ZTRAIT_RESERVED))
var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,i))
var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,i))
reserve_turfs(block(A, B))
var/block = block(A, B)
for(var/t in block)
// No need to empty() these, because it's world init and they're
// already /turf/open/space/basic.
var/turf/T = t
T.flags_1 |= UNUSED_RESERVATION_TURF_1
unused_turfs["[i]"] = block
clearing_reserved_turfs = FALSE
/datum/controller/subsystem/mapping/proc/reserve_turfs(list/turfs)

View File

@@ -6,7 +6,7 @@ SUBSYSTEM_DEF(medals)
/datum/controller/subsystem/medals/Initialize(timeofday)
if(CONFIG_GET(string/medal_hub_address) && CONFIG_GET(string/medal_hub_password))
hub_enabled = TRUE
..()
return ..()
/datum/controller/subsystem/medals/proc/UnlockMedal(medal, client/player)
set waitfor = FALSE
@@ -84,4 +84,4 @@ SUBSYSTEM_DEF(medals)
/datum/controller/subsystem/medals/proc/ClearScore(client/player)
if(isnull(world.SetScores(player.ckey, "", CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))))
log_game("MEDAL ERROR: Could not contact hub to clear scores for [player.key]!")
message_admins("Error! Failed to contact hub to clear scores for [player.key]!")
message_admins("Error! Failed to contact hub to clear scores for [player.key]!")

View File

@@ -6,6 +6,7 @@ SUBSYSTEM_DEF(mobs)
var/list/currentrun = list()
var/static/list/clients_by_zlevel[][]
var/static/list/dead_players_by_zlevel[][] = list(list()) // Needs to support zlevel 1 here, MaxZChanged only happens when z2 is created and new_players can login before that.
var/static/list/cubemonkeys = list()
/datum/controller/subsystem/mobs/stat_entry()
@@ -14,9 +15,12 @@ SUBSYSTEM_DEF(mobs)
/datum/controller/subsystem/mobs/proc/MaxZChanged()
if (!islist(clients_by_zlevel))
clients_by_zlevel = new /list(world.maxz,0)
dead_players_by_zlevel = new /list(world.maxz,0)
while (clients_by_zlevel.len < world.maxz)
clients_by_zlevel.len++
clients_by_zlevel[clients_by_zlevel.len] = list()
dead_players_by_zlevel.len++
dead_players_by_zlevel[dead_players_by_zlevel.len] = list()
/datum/controller/subsystem/mobs/fire(resumed = 0)
var/seconds = wait * 0.1

View File

@@ -19,7 +19,7 @@ SUBSYSTEM_DEF(overlays)
/datum/controller/subsystem/overlays/Initialize()
initialized = TRUE
fire(mc_check = FALSE)
..()
return ..()
/datum/controller/subsystem/overlays/stat_entry()

View File

@@ -28,7 +28,7 @@ SUBSYSTEM_DEF(persistence)
LoadPhotoPersistence()
if(CONFIG_GET(flag/use_antag_rep))
LoadAntagReputation()
..()
return ..()
/datum/controller/subsystem/persistence/proc/LoadSatchels()
var/placed_satchel = 0
@@ -207,6 +207,16 @@ SUBSYSTEM_DEF(persistence)
if(CONFIG_GET(flag/use_antag_rep))
CollectAntagReputation()
/datum/controller/subsystem/persistence/proc/GetPhotoAlbums()
var/album_path = file("data/photo_albums.json")
if(fexists(album_path))
return json_decode(file2text(album_path))
/datum/controller/subsystem/persistence/proc/GetPhotoFrames()
var/frame_path = file("data/photo_frames.json")
if(fexists(frame_path))
return json_decode(file2text(frame_path))
/datum/controller/subsystem/persistence/proc/LoadPhotoPersistence()
var/album_path = file("data/photo_albums.json")
var/frame_path = file("data/photo_frames.json")

View File

@@ -50,6 +50,11 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
/obj/item/electronic_assembly/simple,
/obj/item/electronic_assembly/hook,
/obj/item/electronic_assembly/pda,
/obj/item/electronic_assembly/small/default,
/obj/item/electronic_assembly/small/cylinder,
/obj/item/electronic_assembly/small/scanner,
/obj/item/electronic_assembly/small/hook,
/obj/item/electronic_assembly/small/box,
/obj/item/electronic_assembly/medium/default,
/obj/item/electronic_assembly/medium/box,
/obj/item/electronic_assembly/medium/clam,
@@ -68,6 +73,7 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
/obj/item/electronic_assembly/drone/medbot,
/obj/item/electronic_assembly/drone/genbot,
/obj/item/electronic_assembly/drone/android,
/obj/item/electronic_assembly/wallmount/tiny,
/obj/item/electronic_assembly/wallmount/light,
/obj/item/electronic_assembly/wallmount,
/obj/item/electronic_assembly/wallmount/heavy
@@ -83,3 +89,4 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
/obj/item/card/data/full_color,
/obj/item/card/data/disk
)

View File

@@ -1,29 +1,5 @@
SUBSYSTEM_DEF(obj)
PROCESSING_SUBSYSTEM_DEF(obj)
name = "Objects"
priority = FIRE_PRIORITY_OBJ
flags = SS_NO_INIT
var/list/processing = list()
var/list/currentrun = list()
/datum/controller/subsystem/obj/stat_entry()
..("P:[processing.len]")
/datum/controller/subsystem/obj/fire(resumed = 0)
if (!resumed)
src.currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/datum/thing = currentrun[currentrun.len]
currentrun.len--
if(thing)
thing.process(wait)
else
SSobj.processing -= thing
if (MC_TICK_CHECK)
return
/datum/controller/subsystem/obj/Recover()
processing = SSobj.processing
wait = 20

View File

@@ -22,12 +22,14 @@ SUBSYSTEM_DEF(processing)
while(current_run.len)
var/datum/thing = current_run[current_run.len]
current_run.len--
if(QDELETED(thing) || thing.process(wait) == PROCESS_KILL)
if(QDELETED(thing))
processing -= thing
else if(thing.process(wait) == PROCESS_KILL)
// fully stop so that a future START_PROCESSING will work
STOP_PROCESSING(src, thing)
if (MC_TICK_CHECK)
return
/datum/proc/process()
set waitfor = 0
STOP_PROCESSING(SSobj, src)
return 0
return PROCESS_KILL

View File

@@ -15,7 +15,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
/datum/controller/subsystem/processing/quirks/Initialize(timeofday)
if(!quirks.len)
SetupQuirks()
..()
return ..()
/datum/controller/subsystem/processing/quirks/proc/SetupQuirks()
for(var/V in subtypesof(/datum/quirk))

View File

@@ -1,37 +0,0 @@
//Used to process and handle roundstart trait datums
//Trait datums are separate from trait strings:
// - Trait strings are used for faster checking in code
// - Trait datums are stored and hold different effects, as well as being a vector for applying trait string
PROCESSING_SUBSYSTEM_DEF(traits)
name = "Traits"
init_order = INIT_ORDER_TRAITS
flags = SS_BACKGROUND
wait = 10
runlevels = RUNLEVEL_GAME
var/list/traits = list() //Assoc. list of all roundstart trait datum types; "name" = /path/
var/list/trait_points = list() //Assoc. list of trait names and their "point cost"; positive numbers are good traits, and negative ones are bad
var/list/trait_objects = list() //A list of all trait objects in the game, since some may process
/datum/controller/subsystem/processing/traits/Initialize(timeofday)
if(!traits.len)
SetupTraits()
..()
/datum/controller/subsystem/processing/traits/proc/SetupTraits()
for(var/V in subtypesof(/datum/trait))
var/datum/trait/T = V
traits[initial(T.name)] = T
trait_points[initial(T.name)] = initial(T.value)
/datum/controller/subsystem/processing/traits/proc/AssignTraits(mob/living/user, client/cli, spawn_effects)
GenerateTraits(cli)
if(user && cli && cli.prefs.character_traits)
for(var/V in cli.prefs.character_traits)
user.add_trait_datum(V, spawn_effects)
/datum/controller/subsystem/processing/traits/proc/GenerateTraits(client/user)
if(user && user.prefs && user.prefs.character_traits)
if(user.prefs.character_traits.len)
return
user.prefs.character_traits = user.prefs.all_traits

View File

@@ -17,9 +17,9 @@ SUBSYSTEM_DEF(research)
var/list/techweb_boost_items = list() //associative double-layer path = list(id = list(point_type = point_discount))
var/list/techweb_nodes_hidden = list() //Nodes that should be hidden by default.
var/list/techweb_point_items = list( //path = list(point type = value)
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 2500),
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 2500),
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 5000), // Cit three more anomalys anomalys
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 7500),
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 7500),
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000),
/obj/item/slime_extract/grey = list(TECHWEB_POINT_TYPE_GENERIC = 500), // Adds in slime core deconing
/obj/item/slime_extract/metal = list(TECHWEB_POINT_TYPE_GENERIC = 750),
@@ -40,14 +40,18 @@ SUBSYSTEM_DEF(research)
/obj/item/slime_extract/adamantine =list (TECHWEB_POINT_TYPE_GENERIC = 1500),
/obj/item/slime_extract/oil = list(TECHWEB_POINT_TYPE_GENERIC = 1500),
/obj/item/slime_extract/lightpink = list(TECHWEB_POINT_TYPE_GENERIC = 1500),
/obj/item/slime_extract/rainbow = list(TECHWEB_POINT_TYPE_GENERIC = 2500) // End of Cit changes
)
/obj/item/slime_extract/rainbow = list(TECHWEB_POINT_TYPE_GENERIC = 2500) // End of Cit changes
var/list/errored_datums = list()
var/list/point_types = list() //typecache style type = TRUE list
//----------------------------------------------
var/list/single_server_income = list(TECHWEB_POINT_TYPE_GENERIC = 25) //citadel edit - techwebs nerf
var/list/single_server_income = list(TECHWEB_POINT_TYPE_GENERIC = 25) //citadel edit - techwebs nerf
var/multiserver_calculation = FALSE
var/last_income = 0
var/last_income
//^^^^^^^^ ALL OF THESE ARE PER SECOND! ^^^^^^^^
//Aiming for 1.5 hours to max R&D
//[88nodes * 5000points/node] / [1.5hr * 90min/hr * 60s/min]
//Around 450000 points max???
/datum/controller/subsystem/research/Initialize()
point_types = TECHWEB_POINT_TYPE_LIST_ASSOCIATIVE_NAMES
@@ -59,9 +63,6 @@ SUBSYSTEM_DEF(research)
return ..()
/datum/controller/subsystem/research/fire()
handle_research_income()
/datum/controller/subsystem/research/proc/handle_research_income()
var/list/bitcoins = list()
if(multiserver_calculation)
var/eff = calculate_server_coefficient()
@@ -75,11 +76,12 @@ SUBSYSTEM_DEF(research)
if(miner.working)
bitcoins = single_server_income.Copy()
break //Just need one to work.
var/income_time_difference = world.time - last_income
science_tech.last_bitcoins = bitcoins // Doesn't take tick drift into account
for(var/i in bitcoins)
bitcoins[i] *= income_time_difference / 10
science_tech.add_point_list(bitcoins)
if (!isnull(last_income))
var/income_time_difference = world.time - last_income
science_tech.last_bitcoins = bitcoins // Doesn't take tick drift into account
for(var/i in bitcoins)
bitcoins[i] *= income_time_difference / 10
science_tech.add_point_list(bitcoins)
last_income = world.time
/datum/controller/subsystem/research/proc/calculate_server_coefficient() //Diminishing returns.

View File

@@ -12,7 +12,7 @@ SUBSYSTEM_DEF(server_maint)
/datum/controller/subsystem/server_maint/Initialize(timeofday)
if (CONFIG_GET(flag/hub))
world.update_hub_visibility(TRUE)
..()
return ..()
/datum/controller/subsystem/server_maint/fire(resumed = FALSE)
if(!resumed)

View File

@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(shuttle)
var/lockdown = FALSE //disallow transit after nuke goes off
var/auto_call = 72000 //CIT CHANGE - time before in deciseconds in which the shuttle is auto called. Default is 2<EFBFBD> hours plus 15 for the shuttle. So total is 3.
var/auto_call = 72000 //CIT CHANGE - time before in deciseconds in which the shuttle is auto called. Default is 2ish hours plus 15 for the shuttle. So total is 3.
/datum/controller/subsystem/shuttle/Initialize(timeofday)
ordernum = rand(1, 9000)
@@ -74,7 +74,7 @@ SUBSYSTEM_DEF(shuttle)
WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!")
if(!supply)
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
..()
return ..()
/datum/controller/subsystem/shuttle/proc/initial_load()
if(!istype(manipulator))
@@ -220,6 +220,14 @@ SUBSYSTEM_DEF(shuttle)
else
emergency.request(null, signal_origin, html_decode(emergency_reason), 0)
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
if(!frequency)
return
var/datum/signal/status_signal = new(list("command" = "update")) // Start processing shuttle-mode displays to display the timer
frequency.post_signal(src, status_signal)
var/area/A = get_area(user)
log_game("[key_name(user)] has called the shuttle.")

View File

@@ -11,7 +11,7 @@ SUBSYSTEM_DEF(tgui)
var/basehtml // The HTML base used for all UIs.
/datum/controller/subsystem/tgui/PreInit()
basehtml = file2text("tgui/tgui.html")
basehtml = file2text('tgui/tgui.html')
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()

View File

@@ -126,6 +126,7 @@ SUBSYSTEM_DEF(throwing)
//done throwing, either because it hit something or it finished moving
if(!thrownthing)
return
thrownthing.throwing = null
if (!hit)
for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on.
var/atom/A = thing

View File

@@ -67,12 +67,6 @@ SUBSYSTEM_DEF(ticker)
var/end_state = "undefined"
var/modevoted = FALSE //Have we sent a vote for the gamemode?
var/tumpedbuckets = FALSE //Have we tumped over buckets?
//Crew Objective/Miscreant stuff
var/list/crewobjlist = list()
var/list/crewobjjobs = list()
var/list/miscreantobjlist = list()
/datum/controller/subsystem/ticker/Initialize(timeofday)
load_mode()
@@ -129,26 +123,19 @@ SUBSYSTEM_DEF(ticker)
login_music = pick(music)
else
login_music = "[global.config.directory]/title_music/sounds/[pick(music)]"
/*
crewobjlist = typesof(/datum/objective/crew)
miscreantobjlist = (typesof(/datum/objective/miscreant) - /datum/objective/miscreant)
for(var/hoorayhackyshit in crewobjlist) //taken from old Hippie's "job2obj" proc with adjustments.
var/datum/objective/crew/obj = hoorayhackyshit //dm is not a sane language in any way, shape, or form.
var/list/availableto = splittext(initial(obj.jobs),",")
for(var/job in availableto)
crewobjjobs["[job]"] += list(obj) */
if(!GLOB.syndicate_code_phrase)
GLOB.syndicate_code_phrase = generate_code_phrase()
if(!GLOB.syndicate_code_response)
GLOB.syndicate_code_response = generate_code_phrase()
..()
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
if(CONFIG_GET(flag/randomize_shift_time))
gametime_offset = rand(0, 23) HOURS
else if(CONFIG_GET(flag/shift_time_realtime))
gametime_offset = world.timeofday
return ..()
/datum/controller/subsystem/ticker/fire()
switch(current_state)
@@ -166,10 +153,6 @@ SUBSYSTEM_DEF(ticker)
fire()
if(GAME_STATE_PREGAME)
//lobby stats for statpanels
if(!tumpedbuckets)
SStimer.tump_buckets()
if(!modevoted)
send_gamemode_vote()
if(isnull(timeLeft))
timeLeft = max(0,start_at - world.time)
totalPlayers = 0
@@ -182,6 +165,8 @@ SUBSYSTEM_DEF(ticker)
if(start_immediately)
timeLeft = 0
if(!modevoted)
send_gamemode_vote()
//countdown
if(timeLeft < 0)
return
@@ -326,13 +311,6 @@ SUBSYSTEM_DEF(ticker)
GLOB.start_state = new /datum/station_state()
GLOB.start_state.count()
/* //assign crew objectives and generate miscreants
if(CONFIG_GET(flag/allow_extended_miscreants) && GLOB.master_mode == "extended")
GLOB.miscreants_allowed = TRUE
if(CONFIG_GET(flag/allow_miscreants) && GLOB.master_mode != "extended")
GLOB.miscreants_allowed = TRUE
generate_crew_objectives() */
var/list/adm = get_admin_counts()
var/list/allmins = adm["present"]
send2irc("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
@@ -662,6 +640,7 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/Shutdown()
gather_newscaster() //called here so we ensure the log is created even upon admin reboot
save_admin_data()
update_everything_flag_in_db()
if(!round_end_sound)
round_end_sound = pick(\
'sound/roundend/newroundsexy.ogg',
@@ -670,7 +649,8 @@ SUBSYSTEM_DEF(ticker)
'sound/roundend/leavingtg.ogg',
'sound/roundend/its_only_game.ogg',
'sound/roundend/yeehaw.ogg',
'sound/roundend/disappointed.ogg'\
'sound/roundend/disappointed.ogg',
'sound/roundend/gondolabridge.ogg'\
)
SEND_SOUND(world, sound(round_end_sound))

View File

@@ -71,6 +71,7 @@ SUBSYSTEM_DEF(timer)
for(var/I in second_queue)
log_world(get_timer_debug_string(I))
var/cut_start_index = 1
var/next_clienttime_timer_index = 0
var/len = length(clienttime_timers)
@@ -90,11 +91,17 @@ SUBSYSTEM_DEF(timer)
ctime_timer.spent = REALTIMEOFDAY
callBack.InvokeAsync()
qdel(ctime_timer)
if(ctime_timer.flags & TIMER_LOOP)
ctime_timer.spent = 0
clienttime_timers.Insert(ctime_timer, 1)
cut_start_index++
else
qdel(ctime_timer)
if (next_clienttime_timer_index)
clienttime_timers.Cut(1,next_clienttime_timer_index+1)
clienttime_timers.Cut(cut_start_index,next_clienttime_timer_index+1)
if (MC_TICK_CHECK)
return
@@ -197,8 +204,22 @@ SUBSYSTEM_DEF(timer)
bucket_count -= length(spent)
for (var/spent_timer in spent)
qdel(spent_timer)
for (var/i in spent)
var/datum/timedevent/qtimer = i
if(QDELETED(qtimer))
bucket_count++
continue
if(!(qtimer.flags & TIMER_LOOP))
qdel(qtimer)
else
bucket_count++
qtimer.spent = 0
qtimer.bucketEject()
if(qtimer.flags & TIMER_CLIENT_TIME)
qtimer.timeToRun = REALTIMEOFDAY + qtimer.wait
else
qtimer.timeToRun = world.time + qtimer.wait
qtimer.bucketJoin()
spent.len = 0
@@ -294,6 +315,7 @@ SUBSYSTEM_DEF(timer)
var/id
var/datum/callback/callBack
var/timeToRun
var/wait
var/hash
var/list/flags
var/spent = 0 //time we ran the timer.
@@ -302,14 +324,19 @@ SUBSYSTEM_DEF(timer)
var/datum/timedevent/next
var/datum/timedevent/prev
/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash)
/datum/timedevent/New(datum/callback/callBack, wait, flags, hash)
var/static/nextid = 1
id = TIMER_ID_NULL
src.callBack = callBack
src.timeToRun = timeToRun
src.wait = wait
src.flags = flags
src.hash = hash
if (flags & TIMER_CLIENT_TIME)
timeToRun = REALTIMEOFDAY + wait
else
timeToRun = world.time + wait
if (flags & TIMER_UNIQUE)
SStimer.hashes[hash] = src
@@ -321,7 +348,7 @@ SUBSYSTEM_DEF(timer)
nextid++
SStimer.timer_id_dict[id] = src
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]")
@@ -329,60 +356,7 @@ SUBSYSTEM_DEF(timer)
if (callBack.object != GLOBAL_PROC && !QDESTROYING(callBack.object))
LAZYADD(callBack.object.active_timers, src)
var/list/L
if (flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if (timeToRun >= TIMER_MAX)
L = SStimer.second_queue
if (L)
//binary search sorted insert
var/cttl = length(L)
if(cttl)
var/left = 1
var/right = cttl
var/mid = (left+right) >> 1 //rounded divide by two for hedgehogs
var/datum/timedevent/item
while (left < right)
item = L[mid]
if (item.timeToRun <= timeToRun)
left = mid+1
else
right = mid
mid = (left+right) >> 1
item = L[mid]
mid = item.timeToRun > timeToRun ? mid : mid+1
L.Insert(mid, src)
else
L += src
return
//get the list of buckets
var/list/bucket_list = SStimer.bucket_list
//calculate our place in the bucket list
var/bucket_pos = BUCKET_POS(src)
//get the bucket for our tick
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
//empty bucket, we will just add ourselves
if (!bucket_head)
bucket_list[bucket_pos] = src
return
//other wise, lets do a simplified linked list add.
if (!bucket_head.prev)
bucket_head.prev = bucket_head
next = bucket_head
prev = bucket_head.prev
next.prev = src
prev.next = src
bucketJoin()
/datum/timedevent/Destroy()
..()
@@ -406,31 +380,7 @@ SUBSYSTEM_DEF(timer)
if (!spent)
spent = world.time
var/bucketpos = BUCKET_POS(src)
var/datum/timedevent/buckethead
var/list/bucket_list = SStimer.bucket_list
if (bucketpos > 0)
buckethead = bucket_list[bucketpos]
if (buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if (timeToRun < TIMER_MAX || next || prev)
SStimer.bucket_count--
else
var/l = length(SStimer.second_queue)
SStimer.second_queue -= src
if (l == length(SStimer.second_queue))
SStimer.bucket_count--
if (prev == next && next)
next.prev = null
prev.next = null
else
if (prev)
prev.next = next
if (next)
next.prev = prev
bucketEject()
else
if (prev && prev.next == src)
prev.next = next
@@ -440,6 +390,64 @@ SUBSYSTEM_DEF(timer)
prev = null
return QDEL_HINT_IWILLGC
/datum/timedevent/proc/bucketEject()
var/bucketpos = BUCKET_POS(src)
var/list/bucket_list = SStimer.bucket_list
var/list/second_queue = SStimer.second_queue
var/datum/timedevent/buckethead
if(bucketpos > 0)
buckethead = bucket_list[bucketpos]
if(buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if(timeToRun < TIMER_MAX || next || prev)
SStimer.bucket_count--
else
var/l = length(second_queue)
second_queue -= src
if(l == length(second_queue))
SStimer.bucket_count--
if(prev != next)
prev.next = next
next.prev = prev
else
prev?.next = null
next?.prev = null
prev = next = null
/datum/timedevent/proc/bucketJoin()
var/list/L
if (flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if (timeToRun >= TIMER_MAX)
L = SStimer.second_queue
if(L)
BINARY_INSERT(src, L, datum/timedevent, timeToRun)
return
//get the list of buckets
var/list/bucket_list = SStimer.bucket_list
//calculate our place in the bucket list
var/bucket_pos = BUCKET_POS(src)
//get the bucket for our tick
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
//empty bucket, we will just add ourselves
if (!bucket_head)
bucket_list[bucket_pos] = src
return
//other wise, lets do a simplified linked list add.
if (!bucket_head.prev)
bucket_head.prev = bucket_head
next = bucket_head
prev = bucket_head.prev
next.prev = src
prev.next = src
/datum/timedevent/proc/getcallingtype()
. = "ERROR"
if (callBack.object == GLOBAL_PROC)
@@ -488,12 +496,7 @@ SUBSYSTEM_DEF(timer)
else if(flags & TIMER_OVERRIDE)
stack_trace("TIMER_OVERRIDE used without TIMER_UNIQUE")
var/timeToRun = world.time + wait
if (flags & TIMER_CLIENT_TIME)
timeToRun = REALTIMEOFDAY + wait
var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
var/datum/timedevent/timer = new(callback, wait, flags, hash)
return timer.id
/proc/deltimer(id)
@@ -512,9 +515,6 @@ SUBSYSTEM_DEF(timer)
return TRUE
return FALSE
/datum/controller/subsystem/timer/proc/tump_buckets()
reset_buckets()
SSticker.tumpedbuckets = TRUE
#undef BUCKET_LEN
#undef BUCKET_POS

View File

@@ -14,7 +14,7 @@ SUBSYSTEM_DEF(traumas)
//phobia types is to pull from randomly for brain traumas, e.g. conspiracies is for special assignment only
phobia_types = list("spiders", "space", "security", "clowns", "greytide", "lizards",
"skeletons", "snakes", "robots", "doctors", "authority", "the supernatural",
"aliens", "strangers", "birds", "falling")
"aliens", "strangers", "birds", "falling", "anime")
phobia_words = list("spiders" = strings(PHOBIA_FILE, "spiders"),
"space" = strings(PHOBIA_FILE, "space"),
@@ -32,7 +32,8 @@ SUBSYSTEM_DEF(traumas)
"strangers" = strings(PHOBIA_FILE, "strangers"),
"conspiracies" = strings(PHOBIA_FILE, "conspiracies"),
"birds" = strings(PHOBIA_FILE, "birds"),
"falling" = strings(PHOBIA_FILE, "falling")
"falling" = strings(PHOBIA_FILE, "falling"),
"anime" = strings(PHOBIA_FILE, "anime")
)
phobia_mobs = list("spiders" = typecacheof(list(/mob/living/simple_animal/hostile/poison/giant_spider)),
@@ -50,7 +51,8 @@ SUBSYSTEM_DEF(traumas)
"conspiracies" = typecacheof(list(/mob/living/simple_animal/bot/secbot, /mob/living/simple_animal/bot/ed209, /mob/living/simple_animal/drone,
/mob/living/simple_animal/pet/penguin)),
"birds" = typecacheof(list(/mob/living/simple_animal/parrot, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken,
/mob/living/simple_animal/pet/penguin))
/mob/living/simple_animal/pet/penguin)),
"anime" = typecacheof(list(/mob/living/simple_animal/hostile/guardian))
)
phobia_objs = list("snakes" = typecacheof(list(/obj/item/rod_of_asclepius)),
@@ -135,9 +137,14 @@ SUBSYSTEM_DEF(traumas)
/obj/item/clothing/suit/chickensuit, /obj/item/clothing/head/chicken,
/obj/item/clothing/suit/toggle/owlwings, /obj/item/clothing/under/owl, /obj/item/clothing/mask/gas/owl_mask,
/obj/item/clothing/under/griffin, /obj/item/clothing/shoes/griffin, /obj/item/clothing/head/griffin,
/obj/item/clothing/head/helmet/space/freedom, /obj/item/clothing/suit/space/freedom))
)
/obj/item/clothing/head/helmet/space/freedom, /obj/item/clothing/suit/space/freedom)),
"anime" = typecacheof(list(/obj/item/clothing/under/schoolgirl, /obj/item/katana, /obj/item/reagent_containers/food/snacks/sashimi, /obj/item/reagent_containers/food/snacks/chawanmushi,
/obj/item/reagent_containers/food/drinks/bottle/sake, /obj/item/throwing_star, /obj/item/clothing/head/kitty/genuine, /obj/item/clothing/suit/space/space_ninja,
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/twohanded/vibro_weapon,
/obj/item/nullrod/scythe/vibro, /obj/item/energy_katana, /obj/item/toy/katana, /obj/item/nullrod/claymore/katana, /obj/structure/window/paperframe, /obj/structure/mineral_door/paperframe))
)
phobia_turfs = list("space" = typecacheof(list(/turf/open/space, /turf/open/floor/holofloor/space, /turf/open/floor/fakespace)),
"the supernatural" = typecacheof(list(/turf/open/floor/clockwork, /turf/closed/wall/clockwork,
/turf/open/floor/plasteel/cult, /turf/closed/wall/mineral/cult)),
@@ -146,14 +153,15 @@ SUBSYSTEM_DEF(traumas)
"falling" = typecacheof(list(/turf/open/chasm, /turf/open/floor/fakepit))
)
phobia_species = list("lizards" = typecacheof(list(/datum/species/lizard)),
phobia_species = list("lizards" = typecacheof(list(/datum/species/lizard)),
"skeletons" = typecacheof(list(/datum/species/skeleton, /datum/species/plasmaman)),
"conspiracies" = typecacheof(list(/datum/species/abductor, /datum/species/lizard, /datum/species/synth)),
"robots" = typecacheof(list(/datum/species/android)),
"robots" = typecacheof(list(/datum/species/android)),
"the supernatural" = typecacheof(list(/datum/species/golem/clockwork, /datum/species/golem/runic)),
"aliens" = typecacheof(list(/datum/species/abductor, /datum/species/jelly, /datum/species/pod,
/datum/species/shadow))
)
/datum/species/shadow)),
"anime" = typecacheof(list(/datum/species/human/felinid))
)
return ..()

View File

@@ -0,0 +1,75 @@
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
var/datum/callback/rotate_cb
/datum/controller/subsystem/vis_overlays/Initialize()
vis_overlay_cache = list()
rotate_cb = CALLBACK(src, .proc/rotate_vis_overlay)
return ..()
/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
if(!resumed)
currentrun = vis_overlay_cache.Copy()
var/list/current_run = currentrun
while(current_run.len)
var/key = current_run[current_run.len]
var/obj/effect/overlay/vis/overlay = current_run[key]
current_run.len--
if(!overlay.unused && !length(overlay.vis_locs))
overlay.unused = world.time
else if(overlay.unused && overlay.unused + overlay.cache_expiration < world.time)
vis_overlay_cache -= key
qdel(overlay)
if(MC_TICK_CHECK)
return
//the "thing" var can be anything with vis_contents which includes images
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha=255)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]"
var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
if(!overlay)
overlay = new
overlay.icon = icon
overlay.icon_state = iconstate
overlay.layer = layer
overlay.plane = plane
overlay.dir = dir
overlay.alpha = alpha
vis_overlay_cache[.] = overlay
else
overlay.unused = 0
thing.vis_contents += overlay
if(!isatom(thing)) // Automatic rotation is not supported on non atoms
return
if(!thing.managed_vis_overlays)
thing.managed_vis_overlays = list(overlay)
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, rotate_cb)
else
thing.managed_vis_overlays += overlay
/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays)
thing.vis_contents -= overlays
if(!isatom(thing))
return
thing.managed_vis_overlays -= overlays
if(!length(thing.managed_vis_overlays))
thing.managed_vis_overlays = null
UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE)
/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir)
var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
var/list/overlays_to_remove = list()
for(var/i in thing.managed_vis_overlays)
var/obj/effect/overlay/vis/overlay = i
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation))
overlays_to_remove += overlay
remove_vis_overlay(thing, overlays_to_remove)

View File

@@ -45,7 +45,7 @@ SUBSYSTEM_DEF(weather)
for(var/z in SSmapping.levels_by_trait(target_trait))
LAZYINITLIST(eligible_zlevels["[z]"])
eligible_zlevels["[z]"][W] = probability
..()
return ..()
/datum/controller/subsystem/weather/proc/run_weather(datum/weather/weather_datum_type, z_levels)
if (istext(weather_datum_type))