12/21 modernizations from TG live (#103)
* sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
//Used by jobs_have_maint_access
|
||||
#define ASSISTANTS_HAVE_MAINT_ACCESS 1
|
||||
@@ -18,6 +18,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/server_suffix = 0 // generate numeric suffix based on server port
|
||||
var/lobby_countdown = 120 // In between round countdown.
|
||||
var/round_end_countdown = 25 // Post round murder death kill countdown
|
||||
var/hub = 0
|
||||
|
||||
var/log_ooc = 0 // log OOC channel
|
||||
var/log_access = 0 // log login/logout
|
||||
@@ -33,6 +34,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
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/sql_enabled = 0 // for sql switching
|
||||
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
|
||||
@@ -70,6 +72,11 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/forbid_singulo_possession = 0
|
||||
var/useircbot = 0
|
||||
|
||||
var/check_randomizer = 0
|
||||
|
||||
var/allow_panic_bunker_bounce = 0 //Send new players somewhere else
|
||||
var/panic_server_name = "somewhere else"
|
||||
|
||||
//IP Intel vars
|
||||
var/ipintel_email
|
||||
var/ipintel_rating_bad = 1
|
||||
@@ -80,6 +87,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
|
||||
var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
|
||||
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
|
||||
var/use_account_age_for_jobs = 0 //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
|
||||
var/see_own_notes = 0 //Can players see their own admin notes (read-only)? Config option in config.txt
|
||||
|
||||
//Population cap vars
|
||||
@@ -96,6 +104,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/list/modes = list() // allowed modes
|
||||
var/list/votable_modes = list() // votable modes
|
||||
var/list/probabilities = list() // relative probability of each mode
|
||||
var/list/min_pop = list() // overrides for acceptible player counts in a mode
|
||||
var/list/max_pop = list()
|
||||
|
||||
var/humans_need_surnames = 0
|
||||
var/allow_ai = 0 // allow ai job
|
||||
@@ -137,9 +147,6 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/alert_desc_red_downto = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
|
||||
var/alert_desc_delta = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
|
||||
|
||||
var/health_threshold_crit = 0
|
||||
var/health_threshold_dead = -100
|
||||
|
||||
var/revival_pod_plants = 1
|
||||
var/revival_cloning = 1
|
||||
var/revival_brain_life = -1
|
||||
@@ -167,6 +174,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/silent_ai = 0
|
||||
var/silent_borg = 0
|
||||
|
||||
var/damage_multiplier = 1 //Modifier for damage to all mobs. Impacts healing as well.
|
||||
|
||||
var/allowwebclient = 0
|
||||
var/webclientmembersonly = 0
|
||||
|
||||
@@ -174,6 +183,9 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
var/default_laws = 0 //Controls what laws the AI spawns with.
|
||||
var/silicon_max_law_amount = 12
|
||||
var/list/lawids = list()
|
||||
|
||||
var/list/law_weights = list()
|
||||
|
||||
var/assistant_cap = -1
|
||||
|
||||
@@ -182,6 +194,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/grey_assistants = 0
|
||||
|
||||
var/lavaland_budget = 60
|
||||
var/space_budget = 16
|
||||
|
||||
var/aggressive_changelog = 0
|
||||
|
||||
@@ -213,6 +226,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/client_error_message = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
|
||||
|
||||
var/cross_name = "Other server"
|
||||
var/showircname = 0
|
||||
|
||||
/datum/configuration/New()
|
||||
var/list/L = subtypesof(/datum/game_mode)
|
||||
@@ -260,12 +274,16 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
if(type == "config")
|
||||
switch(name)
|
||||
if("hub")
|
||||
config.hub = 1
|
||||
if("admin_legacy_system")
|
||||
config.admin_legacy_system = 1
|
||||
if("ban_legacy_system")
|
||||
config.ban_legacy_system = 1
|
||||
if("use_age_restriction_for_jobs")
|
||||
config.use_age_restriction_for_jobs = 1
|
||||
if("use_account_age_for_jobs")
|
||||
config.use_account_age_for_jobs = 1
|
||||
if("lobby_countdown")
|
||||
config.lobby_countdown = text2num(value)
|
||||
if("round_end_countdown")
|
||||
@@ -298,6 +316,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.log_pda = 1
|
||||
if("log_hrefs")
|
||||
config.log_hrefs = 1
|
||||
if("log_twitter")
|
||||
config.log_twitter = 1
|
||||
if("log_world_topic")
|
||||
config.log_world_topic = 1
|
||||
if("allow_admin_ooccolor")
|
||||
@@ -341,7 +361,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
if("guest_ban")
|
||||
guests_allowed = 0
|
||||
if("usewhitelist")
|
||||
config.usewhitelist = 1
|
||||
config.usewhitelist = TRUE
|
||||
if("allow_metadata")
|
||||
config.allow_Metadata = 1
|
||||
if("kick_inactive")
|
||||
@@ -376,6 +396,18 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
global.cross_allowed = 1
|
||||
if("cross_comms_name")
|
||||
cross_name = value
|
||||
if("panic_server_name")
|
||||
panic_server_name = value
|
||||
if("panic_server_address")
|
||||
global.panic_address = value
|
||||
if(value != "byond:\\address:port")
|
||||
allow_panic_bunker_bounce = 1
|
||||
if("medal_hub_address")
|
||||
global.medal_hub = value
|
||||
if("medal_hub_password")
|
||||
global.medal_pass = value
|
||||
if("show_irc_name")
|
||||
config.showircname = 1
|
||||
if("see_own_notes")
|
||||
config.see_own_notes = 1
|
||||
if("soft_popcap")
|
||||
@@ -396,6 +428,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.notify_new_player_age = text2num(value)
|
||||
if("irc_first_connection_alert")
|
||||
config.irc_first_connection_alert = 1
|
||||
if("check_randomizer")
|
||||
config.check_randomizer = 1
|
||||
if("ipintel_email")
|
||||
if (value != "ch@nge.me")
|
||||
config.ipintel_email = value
|
||||
@@ -448,10 +482,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
else if(type == "game_options")
|
||||
switch(name)
|
||||
if("health_threshold_crit")
|
||||
config.health_threshold_crit = text2num(value)
|
||||
if("health_threshold_dead")
|
||||
config.health_threshold_dead = text2num(value)
|
||||
if("damage_multiplier")
|
||||
config.damage_multiplier = text2num(value)
|
||||
if("revival_pod_plants")
|
||||
config.revival_pod_plants = text2num(value)
|
||||
if("revival_cloning")
|
||||
@@ -520,6 +552,34 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.midround_antag_time_check = text2num(value)
|
||||
if("midround_antag_life_check")
|
||||
config.midround_antag_life_check = text2num(value)
|
||||
if("min_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
var/mode_value = null
|
||||
|
||||
if(pop_pos)
|
||||
mode_name = lowertext(copytext(value, 1, pop_pos))
|
||||
mode_value = copytext(value, pop_pos + 1)
|
||||
if(mode_name in config.modes)
|
||||
config.min_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
diary << "Unknown minimum population configuration definition: [mode_name]."
|
||||
else
|
||||
diary << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
|
||||
if("max_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
var/mode_value = null
|
||||
|
||||
if(pop_pos)
|
||||
mode_name = lowertext(copytext(value, 1, pop_pos))
|
||||
mode_value = copytext(value, pop_pos + 1)
|
||||
if(mode_name in config.modes)
|
||||
config.max_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
diary << "Unknown maximum population configuration definition: [mode_name]."
|
||||
else
|
||||
diary << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
|
||||
if("shuttle_refuel_delay")
|
||||
config.shuttle_refuel_delay = text2num(value)
|
||||
if("show_game_type_odds")
|
||||
@@ -589,6 +649,19 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.sandbox_autoclose = 1
|
||||
if("default_laws")
|
||||
config.default_laws = text2num(value)
|
||||
if("random_laws")
|
||||
var/law_id = lowertext(value)
|
||||
lawids += law_id
|
||||
if("law_weight")
|
||||
// Value is in the form "LAWID,NUMBER"
|
||||
var/list/L = splittext(value, ",")
|
||||
if(L.len != 2)
|
||||
diary << "Invalid LAW_WEIGHT: " + t
|
||||
continue
|
||||
var/lawid = L[1]
|
||||
var/weight = text2num(L[2])
|
||||
law_weights[lawid] = weight
|
||||
|
||||
if("silicon_max_law_amount")
|
||||
config.silicon_max_law_amount = text2num(value)
|
||||
if("join_with_mutant_race")
|
||||
@@ -609,6 +682,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.grey_assistants = 1
|
||||
if("lavaland_budget")
|
||||
config.lavaland_budget = text2num(value)
|
||||
if("space_budget")
|
||||
config.space_budget = text2num(value)
|
||||
if("no_summon_guns")
|
||||
config.no_summon_guns = 1
|
||||
if("no_summon_magic")
|
||||
@@ -753,6 +828,10 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
M.maximum_players = max_pop[M.config_tag]
|
||||
if(M.can_start())
|
||||
runnable_modes[M] = probabilities[M.config_tag]
|
||||
//world << "DEBUG: runnable_mode\[[runnable_modes.len]\] = [M.config_tag]"
|
||||
@@ -768,7 +847,13 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
M.maximum_players = max_pop[M.config_tag]
|
||||
if(M.required_players <= crew)
|
||||
if(M.maximum_players >= 0 && M.maximum_players < crew)
|
||||
continue
|
||||
runnable_modes[M] = probabilities[M.config_tag]
|
||||
return runnable_modes
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
var/init_time
|
||||
var/tickdrift = 0
|
||||
|
||||
var/sleep_delta
|
||||
|
||||
var/make_runtime = 0
|
||||
|
||||
// Has round started? (So we know what subsystems to run)
|
||||
@@ -65,6 +67,11 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
// Tell qdel() to Del() this object.
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
/datum/controller/master/proc/Shutdown()
|
||||
processing = FALSE
|
||||
for(var/datum/subsystem/ss in subsystems)
|
||||
ss.Shutdown()
|
||||
|
||||
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
/proc/Recreate_MC()
|
||||
@@ -165,8 +172,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
message_admins("MC crashed or runtimed, restarting")
|
||||
var/rtn2 = Recreate_MC()
|
||||
if (rtn2 <= 0)
|
||||
log_game("Failed to recreate MC (Error code: [rtn2]), its up to the failsafe now")
|
||||
message_admins("Failed to recreate MC (Error code: [rtn2]), its up to the failsafe now")
|
||||
log_game("Failed to recreate MC (Error code: [rtn2]), it's up to the failsafe now")
|
||||
message_admins("Failed to recreate MC (Error code: [rtn2]), it's up to the failsafe now")
|
||||
Failsafe.defcon = 2
|
||||
|
||||
// Main loop.
|
||||
@@ -280,6 +287,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
|
||||
iteration++
|
||||
last_run = world.time
|
||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
// Used to initialize the subsystem BEFORE the map has loaded
|
||||
/datum/subsystem/New()
|
||||
|
||||
//cleanup actions
|
||||
/datum/subsystem/proc/Shutdown()
|
||||
return
|
||||
|
||||
//previously, this would have been named 'process()' but that name is used everywhere for different things!
|
||||
//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds.
|
||||
//fire(), and the procs it calls, SHOULD NOT HAVE ANY SLEEP OPERATIONS in them!
|
||||
@@ -140,7 +144,7 @@
|
||||
statclick = new/obj/effect/statclick/debug("Initializing...", src)
|
||||
|
||||
if(can_fire)
|
||||
msg = "[round(cost*ticks,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
|
||||
else
|
||||
msg = "OFFLINE\t[msg]"
|
||||
|
||||
@@ -157,7 +161,12 @@
|
||||
/datum/subsystem/proc/Recover()
|
||||
|
||||
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
|
||||
/datum/subsystem/on_varedit(edited_var)
|
||||
if (edited_var == "can_fire" && can_fire)
|
||||
next_fire = world.time + wait
|
||||
..()
|
||||
/datum/subsystem/vv_edit_var(var_name, var_value)
|
||||
switch (var_name)
|
||||
if ("can_fire")
|
||||
if (var_value)
|
||||
next_fire = world.time + wait
|
||||
if ("queued_priority") //editing this breaks things.
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
var/datum/subsystem/acid/SSacid
|
||||
|
||||
/datum/subsystem/acid
|
||||
name = "Acid"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/subsystem/acid/New()
|
||||
NEW_SS_GLOBAL(SSacid)
|
||||
|
||||
|
||||
/datum/subsystem/acid/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/acid/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/obj/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!O || qdeleted(O))
|
||||
processing -= O
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
if(O.acid_level && O.acid_processing())
|
||||
else
|
||||
O.overlays -= acid_overlay
|
||||
O.priority_overlays -= acid_overlay
|
||||
processing -= O
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -0,0 +1,84 @@
|
||||
var/datum/subsystem/augury/SSaugury
|
||||
|
||||
/datum/subsystem/augury
|
||||
name = "Augury"
|
||||
flags = SS_NO_INIT
|
||||
|
||||
var/list/watchers = list()
|
||||
var/list/doombringers = list()
|
||||
|
||||
var/list/observers_given_action = list()
|
||||
|
||||
/datum/subsystem/augury/New()
|
||||
NEW_SS_GLOBAL(SSaugury)
|
||||
|
||||
/datum/subsystem/augury/stat_entry(msg)
|
||||
..("W:[watchers.len]|D:[doombringers.len]")
|
||||
|
||||
/datum/subsystem/augury/proc/register_doom(atom/A, severity)
|
||||
doombringers[A] = severity
|
||||
|
||||
/datum/subsystem/augury/fire()
|
||||
var/biggest_doom = null
|
||||
var/biggest_threat = null
|
||||
|
||||
for(var/d in doombringers)
|
||||
if(!d || qdeleted(d))
|
||||
doombringers -= d
|
||||
continue
|
||||
var/threat = doombringers[d]
|
||||
if((biggest_threat == null) || (biggest_threat < threat))
|
||||
biggest_doom = d
|
||||
biggest_threat = threat
|
||||
|
||||
if(doombringers.len)
|
||||
for(var/i in player_list)
|
||||
if(isobserver(i) && (!(observers_given_action[i])))
|
||||
var/datum/action/innate/augury/A = new
|
||||
A.Grant(i)
|
||||
observers_given_action[i] = TRUE
|
||||
else
|
||||
for(var/i in observers_given_action)
|
||||
if(observers_given_action[i] && isobserver(i))
|
||||
var/mob/dead/observer/O = i
|
||||
for(var/datum/action/innate/augury/A in O.actions)
|
||||
qdel(A)
|
||||
observers_given_action -= i
|
||||
|
||||
for(var/w in watchers)
|
||||
if(!w)
|
||||
watchers -= w
|
||||
continue
|
||||
var/mob/dead/observer/O = w
|
||||
if(biggest_doom && (!O.orbiting || O.orbiting.orbiting != biggest_doom))
|
||||
O.ManualFollow(biggest_doom)
|
||||
|
||||
/datum/action/innate/augury
|
||||
name = "Auto Follow Debris"
|
||||
icon_icon = 'icons/obj/meteor.dmi'
|
||||
button_icon_state = "flaming"
|
||||
background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
|
||||
|
||||
/datum/action/innate/augury/Destroy()
|
||||
if(owner)
|
||||
SSaugury.watchers -= owner
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/augury/Activate()
|
||||
SSaugury.watchers += owner
|
||||
owner << "<span class='notice'>You are now auto-following debris.</span>"
|
||||
active = TRUE
|
||||
UpdateButtonIcon()
|
||||
|
||||
/datum/action/innate/augury/Deactivate()
|
||||
SSaugury.watchers -= owner
|
||||
owner << "<span class='notice'>You are no longer auto-following debris.</span>"
|
||||
active = FALSE
|
||||
UpdateButtonIcon()
|
||||
|
||||
/datum/action/innate/augury/UpdateButtonIcon()
|
||||
..()
|
||||
if(active)
|
||||
button.icon_state = "template_active"
|
||||
else
|
||||
button.icon_state = "template"
|
||||
@@ -110,8 +110,8 @@ var/datum/subsystem/events/SSevent
|
||||
|
||||
/datum/round_event/proc/findEventArea() //Here's a nice proc to use to find an area for your event to land in!
|
||||
var/list/safe_areas = list(
|
||||
/area/turret_protected/ai,
|
||||
/area/turret_protected/ai_upload,
|
||||
/area/ai_monitored/turret_protected/ai,
|
||||
/area/ai_monitored/turret_protected/ai_upload,
|
||||
/area/engine,
|
||||
/area/solar,
|
||||
/area/holodeck,
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
var/datum/subsystem/fastprocess/SSfastprocess
|
||||
|
||||
/datum/subsystem/fastprocess
|
||||
name = "Fast Process"
|
||||
priority = 25
|
||||
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
|
||||
wait = 2
|
||||
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
/datum/subsystem/fastprocess/New()
|
||||
NEW_SS_GLOBAL(SSfastprocess)
|
||||
|
||||
/datum/subsystem/fastprocess/stat_entry()
|
||||
..("FP:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/fastprocess/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
|
||||
SSfastprocess.processing -= thing
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -0,0 +1,42 @@
|
||||
var/datum/subsystem/fire_burning/SSfire_burning
|
||||
|
||||
/datum/subsystem/fire_burning
|
||||
name = "Fire Burning"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/subsystem/fire_burning/New()
|
||||
NEW_SS_GLOBAL(SSfire_burning)
|
||||
|
||||
|
||||
/datum/subsystem/fire_burning/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/fire_burning/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/obj/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!O || qdeleted(O))
|
||||
processing -= O
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
if(O.resistance_flags & ON_FIRE)
|
||||
O.take_damage(20, BURN, "fire", 0)
|
||||
else
|
||||
processing -= O
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
@@ -70,7 +70,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
Queue(ref)
|
||||
tobequeued.Cut(1, 2)
|
||||
|
||||
/datum/subsystem/garbage_collector/proc/HandleQueue(time_to_stop)
|
||||
/datum/subsystem/garbage_collector/proc/HandleQueue()
|
||||
delslasttick = 0
|
||||
gcedlasttick = 0
|
||||
var/time_to_kill = world.time - collection_timeout // Anything qdel() but not GC'd BEFORE this time needs to be manually del()
|
||||
@@ -121,7 +121,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
++totalgcs
|
||||
|
||||
/datum/subsystem/garbage_collector/proc/QueueForQueuing(datum/A)
|
||||
if (istype(A) && isnull(A.gc_destroyed))
|
||||
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
tobequeued += A
|
||||
A.gc_destroyed = GC_QUEUED_FOR_QUEUING
|
||||
|
||||
@@ -142,7 +142,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
queue[refid] = gctime
|
||||
|
||||
/datum/subsystem/garbage_collector/proc/HardQueue(datum/A)
|
||||
if (istype(A) && isnull(A.gc_destroyed))
|
||||
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
tobequeued += A
|
||||
A.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
|
||||
|
||||
@@ -158,11 +158,12 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
if(!D)
|
||||
return
|
||||
#ifdef TESTING
|
||||
SSgarbage.qdel_list += "[A.type]"
|
||||
SSgarbage.qdel_list += "[D.type]"
|
||||
#endif
|
||||
if(!istype(D))
|
||||
del(D)
|
||||
else if(isnull(D.gc_destroyed))
|
||||
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
|
||||
var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up.
|
||||
if(!D)
|
||||
return
|
||||
@@ -171,6 +172,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
SSgarbage.QueueForQueuing(D)
|
||||
if (QDEL_HINT_LETMELIVE, QDEL_HINT_IWILLGC) //qdel should let the object live after calling destory.
|
||||
if(!force)
|
||||
D.gc_destroyed = null //clear the gc variable (important!)
|
||||
return
|
||||
// Returning LETMELIVE after being told to force destroy
|
||||
// indicates the objects Destroy() does not respect force
|
||||
@@ -191,13 +193,15 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
|
||||
SSgarbage.QueueForQueuing(D)
|
||||
#ifdef TESTING
|
||||
A.find_references()
|
||||
D.find_references()
|
||||
#endif
|
||||
else
|
||||
if(!SSgarbage.noqdelhint["[D.type]"])
|
||||
SSgarbage.noqdelhint["[D.type]"] = "[D.type]"
|
||||
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.")
|
||||
SSgarbage.QueueForQueuing(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")
|
||||
|
||||
// Returns 1 if the object has been queued for deletion.
|
||||
/proc/qdeleted(datum/D)
|
||||
@@ -207,6 +211,14 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Returns true if the object's destroy has been called (set just before it is called)
|
||||
/proc/qdestroying(datum/D)
|
||||
if(!istype(D))
|
||||
return FALSE
|
||||
if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Default implementation of clean-up code.
|
||||
// This should be overridden to remove all references pointing to the object being destroyed.
|
||||
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
|
||||
@@ -217,15 +229,18 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
/datum/var/gc_destroyed //Time when this object was destroyed.
|
||||
|
||||
#ifdef TESTING
|
||||
/client/var/running_find_references
|
||||
/datum/var/running_find_references
|
||||
|
||||
/datum/verb/find_references()
|
||||
/datum/verb/find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set background = 1
|
||||
set src in world
|
||||
|
||||
find_references(FALSE)
|
||||
|
||||
/datum/proc/find_references(skip_alert)
|
||||
set background = 1
|
||||
running_find_references = type
|
||||
if(usr && usr.client)
|
||||
if(usr.client.running_find_references)
|
||||
@@ -237,9 +252,10 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
return
|
||||
|
||||
if(alert("Running this will create a lot of lag until it finishes. You can cancel it by running it again. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||
running_find_references = null
|
||||
return
|
||||
if(!skip_alert)
|
||||
if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||
running_find_references = null
|
||||
return
|
||||
|
||||
//this keeps the garbage collector from failing to collect objects being searched for in here
|
||||
SSgarbage.can_fire = 0
|
||||
@@ -248,13 +264,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
usr.client.running_find_references = type
|
||||
|
||||
testing("Beginning search for references to a [type].")
|
||||
var/list/things = list()
|
||||
for(var/client/thing)
|
||||
things |= thing
|
||||
for(var/datum/thing)
|
||||
things |= thing
|
||||
testing("Collected list of things in search for references to a [type]. ([things.len] Thing\s)")
|
||||
for(var/datum/thing in things)
|
||||
for(var/datum/thing in world)
|
||||
if(usr && usr.client && !usr.client.running_find_references) return
|
||||
for(var/varname in thing.vars)
|
||||
var/variable = thing.vars[varname]
|
||||
@@ -290,7 +300,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
|
||||
qdel(src)
|
||||
if(!running_find_references)
|
||||
find_references()
|
||||
find_references(TRUE)
|
||||
|
||||
/client/verb/show_qdeleted()
|
||||
set category = "Debug"
|
||||
|
||||
@@ -16,7 +16,7 @@ var/datum/subsystem/icon_smooth/SSicon_smooth
|
||||
while(smooth_queue.len)
|
||||
var/atom/A = smooth_queue[smooth_queue.len]
|
||||
smooth_queue.len--
|
||||
ss_smooth_icon(A)
|
||||
smooth_icon(A)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
if (!smooth_queue.len)
|
||||
@@ -25,8 +25,12 @@ var/datum/subsystem/icon_smooth/SSicon_smooth
|
||||
/datum/subsystem/icon_smooth/Initialize()
|
||||
smooth_zlevel(1,TRUE)
|
||||
smooth_zlevel(2,TRUE)
|
||||
for(var/V in smooth_queue)
|
||||
var/queue = smooth_queue
|
||||
smooth_queue = list()
|
||||
for(var/V in queue)
|
||||
var/atom/A = V
|
||||
if(A.z == 1 || A.z == 2)
|
||||
smooth_queue -= A
|
||||
if(!A || A.z <= 2)
|
||||
continue
|
||||
smooth_icon(A)
|
||||
|
||||
..()
|
||||
@@ -328,7 +328,7 @@ var/datum/subsystem/job/SSjob
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(PopcapReached())
|
||||
RejectPlayer(player)
|
||||
else if(player.client.prefs.userandomjob)
|
||||
else if(player.client.prefs.joblessrole == BERANDOMJOB)
|
||||
GiveRandomJob(player)
|
||||
|
||||
Debug("DO, Standard Check end")
|
||||
@@ -339,8 +339,15 @@ var/datum/subsystem/job/SSjob
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(PopcapReached())
|
||||
RejectPlayer(player)
|
||||
Debug("AC2 Assistant located, Player: [player]")
|
||||
AssignRole(player, "Assistant")
|
||||
if(player.client.prefs.joblessrole == BEASSISTANT)
|
||||
Debug("AC2 Assistant located, Player: [player]")
|
||||
AssignRole(player, "Assistant")
|
||||
else // For those who don't want to play if their preference were filled, back you go.
|
||||
RejectPlayer(player)
|
||||
|
||||
for(var/mob/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?)
|
||||
GiveRandomJob(player)
|
||||
|
||||
return 1
|
||||
|
||||
//Gives the player the stuff he should have with his rank
|
||||
@@ -375,7 +382,7 @@ var/datum/subsystem/job/SSjob
|
||||
if(clear)
|
||||
S = T
|
||||
continue
|
||||
if(istype(S, /obj/effect/landmark) && istype(S.loc, /turf))
|
||||
if(istype(S, /obj/effect/landmark) && isturf(S.loc))
|
||||
H.loc = S.loc
|
||||
|
||||
if(H.mind)
|
||||
@@ -394,7 +401,7 @@ var/datum/subsystem/job/SSjob
|
||||
H << "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>"
|
||||
if(config.minimal_access_threshold)
|
||||
H << "<FONT color='blue'><B>As this station was initially staffed with a [config.jobs_have_minimal_access ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>"
|
||||
return 1
|
||||
return H
|
||||
|
||||
|
||||
/datum/subsystem/job/proc/setup_officer_positions()
|
||||
@@ -470,7 +477,8 @@ var/datum/subsystem/job/SSjob
|
||||
/datum/subsystem/job/proc/RejectPlayer(mob/new_player/player)
|
||||
if(player.mind && player.mind.special_role)
|
||||
return
|
||||
Debug("Popcap overflow Check observer located, Player: [player]")
|
||||
if(PopcapReached())
|
||||
Debug("Popcap overflow Check observer located, Player: [player]")
|
||||
player << "<b>You have failed to qualify for any job you desired.</b>"
|
||||
unassigned -= player
|
||||
player.ready = 0
|
||||
|
||||
@@ -1,65 +1,116 @@
|
||||
|
||||
var/datum/subsystem/lighting/SSlighting
|
||||
|
||||
/var/list/lighting_update_lights = list() // List of lighting sources queued for update.
|
||||
/var/list/lighting_update_corners = list() // List of lighting corners queued for update.
|
||||
/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update.
|
||||
|
||||
/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated.
|
||||
/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated.
|
||||
/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated.
|
||||
#define SSLIGHTING_LIGHTS 1
|
||||
#define SSLIGHTING_TURFS 2
|
||||
|
||||
/datum/subsystem/lighting
|
||||
name = "lighting"
|
||||
name = "Lighting"
|
||||
init_order = 1
|
||||
wait = 2
|
||||
display_order = 5
|
||||
priority = 40
|
||||
wait = 1
|
||||
flags = SS_POST_FIRE_TIMING
|
||||
priority = 40
|
||||
display_order = 5
|
||||
|
||||
var/list/changed_lights = list() //list of all datum/light_source that need updating
|
||||
var/changed_lights_workload = 0 //stats on the largest number of lights (max changed_lights.len)
|
||||
var/list/changed_turfs = list() //list of all turfs which may have a different light level
|
||||
var/changed_turfs_workload = 0 //stats on the largest number of turfs changed (max changed_turfs.len)
|
||||
|
||||
|
||||
/datum/subsystem/lighting/New()
|
||||
NEW_SS_GLOBAL(SSlighting)
|
||||
return ..()
|
||||
|
||||
/datum/subsystem/lighting/Initialize()
|
||||
|
||||
/datum/subsystem/lighting/stat_entry()
|
||||
..("L:[round(changed_lights_workload,1)]|T:[round(changed_turfs_workload,1)]")
|
||||
|
||||
|
||||
//Workhorse of lighting. It cycles through each light that needs updating. It updates their
|
||||
//effects and then processes every turf in the queue, updating their lighting object's appearance
|
||||
//Any light that returns 1 in check() deletes itself
|
||||
//By using queues we are ensuring we don't perform more updates than are necessary
|
||||
/datum/subsystem/lighting/fire(resumed = 0)
|
||||
var/ticklimit = CURRENT_TICKLIMIT
|
||||
//split our tick allotment in half so we don't spend it all on lightshift checks
|
||||
CURRENT_TICKLIMIT = world.tick_usage + ((ticklimit-world.tick_usage)/2)
|
||||
|
||||
var/list/changed_lights = src.changed_lights
|
||||
if (!resumed)
|
||||
changed_lights_workload = MC_AVERAGE(changed_lights_workload, changed_lights.len)
|
||||
var/i = 1
|
||||
while (i <= changed_lights.len)
|
||||
var/datum/light_source/LS = changed_lights[i++]
|
||||
LS.check()
|
||||
if (MC_TICK_CHECK)
|
||||
break
|
||||
if (i > 1)
|
||||
changed_lights.Cut(1,i)
|
||||
|
||||
CURRENT_TICKLIMIT = ticklimit
|
||||
var/list/changed_turfs = src.changed_turfs
|
||||
if (!resumed)
|
||||
changed_turfs_workload = MC_AVERAGE(changed_turfs_workload, changed_turfs.len)
|
||||
i = 1
|
||||
while (i <= changed_turfs.len)
|
||||
var/turf/T = changed_turfs[i++]
|
||||
if(T.lighting_changed)
|
||||
T.redraw_lighting()
|
||||
if (MC_TICK_CHECK)
|
||||
break
|
||||
if (i > 1)
|
||||
changed_turfs.Cut(1,i)
|
||||
|
||||
//same as above except it attempts to shift ALL turfs in the world regardless of lighting_changed status
|
||||
/datum/subsystem/lighting/Initialize(timeofday)
|
||||
var/list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))
|
||||
if (config.starlight)
|
||||
for(var/area/A in world)
|
||||
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
if (A.lighting_use_dynamic == DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
A.luminosity = 0
|
||||
|
||||
create_all_lighting_overlays()
|
||||
for(var/thing in changed_lights)
|
||||
var/datum/light_source/LS = thing
|
||||
LS.check()
|
||||
changed_lights.Cut()
|
||||
|
||||
/datum/subsystem/lighting/fire()
|
||||
for(var/thing in turfs_to_init)
|
||||
var/turf/T = thing
|
||||
T.init_lighting()
|
||||
changed_turfs.Cut()
|
||||
|
||||
lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated.
|
||||
lighting_update_lights = list()
|
||||
for(var/datum/light_source/L in lighting_update_lights_old)
|
||||
..()
|
||||
|
||||
if(L.check() || L.destroyed || L.force_update)
|
||||
L.remove_lum()
|
||||
if(!L.destroyed)
|
||||
L.apply_lum()
|
||||
//Used to strip valid information from an existing instance and transfer it to the replacement. i.e. when a crash occurs
|
||||
//It works by using spawn(-1) to transfer the data, if there is a runtime the data does not get transfered but the loop
|
||||
//does not crash
|
||||
/datum/subsystem/lighting/Recover()
|
||||
if(!istype(SSlighting.changed_turfs))
|
||||
SSlighting.changed_turfs = list()
|
||||
if(!istype(SSlighting.changed_lights))
|
||||
SSlighting.changed_lights = list()
|
||||
|
||||
else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
|
||||
L.smart_vis_update()
|
||||
for(var/thing in SSlighting.changed_lights)
|
||||
var/datum/light_source/LS = thing
|
||||
spawn(-1) //so we don't crash the loop (inefficient)
|
||||
LS.check()
|
||||
|
||||
L.vis_update = FALSE
|
||||
L.force_update = FALSE
|
||||
L.needs_update = FALSE
|
||||
for(var/thing in changed_turfs)
|
||||
var/turf/T = thing
|
||||
if(T.lighting_changed)
|
||||
spawn(-1)
|
||||
T.redraw_lighting()
|
||||
|
||||
lighting_update_corners_old = lighting_update_corners //Same as above.
|
||||
lighting_update_corners = list()
|
||||
for(var/A in lighting_update_corners_old)
|
||||
var/datum/lighting_corner/C = A
|
||||
|
||||
C.update_overlays()
|
||||
|
||||
C.needs_update = FALSE
|
||||
|
||||
lighting_update_overlays_old = lighting_update_overlays //Same as above.
|
||||
lighting_update_overlays = list()
|
||||
|
||||
for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old)
|
||||
O.update_overlay()
|
||||
O.needs_update = 0
|
||||
var/msg = "## DEBUG: [time2text(world.timeofday)] [name] subsystem restarted. Reports:\n"
|
||||
for(var/varname in SSlighting.vars)
|
||||
switch(varname)
|
||||
if("tag","bestF","type","parent_type","vars")
|
||||
continue
|
||||
else
|
||||
var/varval1 = SSlighting.vars[varname]
|
||||
var/varval2 = vars[varname]
|
||||
if(istype(varval1,/list))
|
||||
varval1 = "/list([length(varval1)])"
|
||||
varval2 = "/list([length(varval2)])"
|
||||
msg += "\t [varname] = [varval1] -> [varval2]\n"
|
||||
world.log << msg
|
||||
|
||||
@@ -34,7 +34,7 @@ var/datum/subsystem/mapping/SSmapping
|
||||
else
|
||||
space_zlevels += i
|
||||
|
||||
seedRuins(space_zlevels, rand(8,16), /area/space, space_ruins_templates)
|
||||
seedRuins(space_zlevels, config.space_budget, /area/space, space_ruins_templates)
|
||||
|
||||
// Set up Z-level transistions.
|
||||
setup_map_transitions()
|
||||
|
||||
@@ -13,25 +13,55 @@ var/datum/subsystem/minimap/SSminimap
|
||||
NEW_SS_GLOBAL(SSminimap)
|
||||
|
||||
/datum/subsystem/minimap/Initialize(timeofday)
|
||||
if(!config.generate_minimaps)
|
||||
world << "Minimap generation disabled... Skipping"
|
||||
return
|
||||
var/hash = md5(file2text("_maps/[MAP_PATH]/[MAP_FILE]"))
|
||||
if(hash == trim(file2text(hash_path())))
|
||||
return ..()
|
||||
|
||||
for(var/z in z_levels)
|
||||
generate(z)
|
||||
register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
|
||||
fdel(hash_path())
|
||||
text2file(hash, hash_path())
|
||||
if(config.generate_minimaps)
|
||||
if(hash == trim(file2text(hash_path())))
|
||||
for(var/z in z_levels) //We have these files cached, let's register them
|
||||
register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
|
||||
return ..()
|
||||
for(var/z in z_levels)
|
||||
generate(z)
|
||||
register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
|
||||
fdel(hash_path())
|
||||
text2file(hash, hash_path())
|
||||
else
|
||||
world << "<span class='boldannounce'>Minimap generation disabled. Loading from cache...</span>"
|
||||
var/fileloc = 0
|
||||
if(check_files(0)) //Let's first check if we have maps cached in the data folder. NOTE: This will override the backup files even if this map is older.
|
||||
world.log << "cache"
|
||||
if(hash != trim(file2text(hash_path())))
|
||||
world << "<span class='boldannounce'>Loaded cached minimap is outdated. There may be minor discrepancies in layout.</span>" //Disclaimer against players saying map is wrong.
|
||||
fileloc = 0
|
||||
else
|
||||
if(!check_files(1))
|
||||
world << "<span class='boldannounce'>Failed to load backup minimap file. Aborting.</span>" //We couldn't find something. Bail to prevent issues with null files
|
||||
return
|
||||
fileloc = 1 //No map image cached with the current map, and we have a backup. Let's fall back to it.
|
||||
world << "<span class='boldannounce'>No cached minimaps detected. Backup files loaded.</span>"
|
||||
for(var/z in z_levels)
|
||||
register_asset("minimap_[z].png", fcopy_rsc(map_path(z,fileloc)))
|
||||
..()
|
||||
|
||||
/datum/subsystem/minimap/proc/hash_path()
|
||||
return "data/minimaps/[MAP_NAME].md5"
|
||||
/datum/subsystem/minimap/proc/check_files(backup) // If the backup argument is true, looks in the icons folder. If false looks in the data folder.
|
||||
for(var/z in z_levels)
|
||||
if(!fexists(file(map_path(z,backup)))) //Let's make sure we have a file for this map
|
||||
if(backup)
|
||||
world.log << "Failed to find backup file for map [MAP_NAME] on zlevel [z]."
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/subsystem/minimap/proc/map_path(z)
|
||||
return "data/minimaps/[MAP_NAME]_[z].png"
|
||||
|
||||
/datum/subsystem/minimap/proc/hash_path(backup)
|
||||
if(backup)
|
||||
return "icons/minimaps/[MAP_NAME].md5"
|
||||
else
|
||||
return "data/minimaps/[MAP_NAME].md5"
|
||||
|
||||
/datum/subsystem/minimap/proc/map_path(z,backup)
|
||||
if(backup)
|
||||
return "icons/minimaps/[MAP_NAME]_[z].png"
|
||||
else
|
||||
return "data/minimaps/[MAP_NAME]_[z].png"
|
||||
|
||||
/datum/subsystem/minimap/proc/send(client/client)
|
||||
for(var/z in z_levels)
|
||||
@@ -43,24 +73,10 @@ var/datum/subsystem/minimap/SSminimap
|
||||
// Scale it up to our target size.
|
||||
minimap.Scale(MINIMAP_SIZE, MINIMAP_SIZE)
|
||||
|
||||
var/counter = 512
|
||||
// Loop over turfs and generate icons.
|
||||
for(var/T in block(locate(x1, y1, z), locate(x2, y2, z)))
|
||||
generate_tile(T, minimap)
|
||||
|
||||
//byond bug, this fixes OOM crashes by flattening and reseting the minimap icon holder every so and so tiles
|
||||
counter--
|
||||
if(counter <= 0)
|
||||
counter = 512
|
||||
var/icon/flatten = new /icon()
|
||||
flatten.Insert(minimap, "", SOUTH, 1, 0)
|
||||
del(minimap)
|
||||
minimap = flatten
|
||||
stoplag() //we have to sleep in order to get byond to clear out the proc's garbage bin
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
|
||||
// Create a new icon and insert the generated minimap, so that BYOND doesn't generate different directions.
|
||||
var/icon/final = new /icon()
|
||||
final.Insert(minimap, "", SOUTH, 1, 0)
|
||||
@@ -69,9 +85,9 @@ var/datum/subsystem/minimap/SSminimap
|
||||
/datum/subsystem/minimap/proc/generate_tile(turf/tile, icon/minimap)
|
||||
var/icon/tile_icon
|
||||
var/obj/obj
|
||||
var/list/obj_icons = list()
|
||||
var/list/obj_icons
|
||||
// Don't use icons for space, just add objects in space if they exist.
|
||||
if(istype(tile, /turf/open/space))
|
||||
if(isspaceturf(tile))
|
||||
obj = locate(/obj/structure/lattice/catwalk) in tile
|
||||
if(obj)
|
||||
tile_icon = new /icon('icons/obj/smooth_structures/catwalk.dmi', "catwalk", SOUTH)
|
||||
@@ -86,18 +102,20 @@ var/datum/subsystem/minimap/SSminimap
|
||||
tile_icon = new /icon('icons/obj/atmospherics/pipes/transit_tube.dmi', obj.icon_state, obj.dir)
|
||||
else
|
||||
tile_icon = new /icon(tile.icon, tile.icon_state, tile.dir)
|
||||
obj_icons.Cut()
|
||||
obj_icons = list()
|
||||
|
||||
obj = locate(/obj/structure) in tile
|
||||
if(obj)
|
||||
obj_icons += getFlatIcon(obj)
|
||||
obj_icons += new /icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
|
||||
obj = locate(/obj/machinery) in tile
|
||||
if(obj)
|
||||
obj_icons += new /icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
|
||||
obj = locate(/obj/structure/window) in tile
|
||||
if(obj)
|
||||
obj_icons += new /icon('icons/obj/smooth_structures/window.dmi', "window", SOUTH)
|
||||
|
||||
obj = locate(/obj/structure/table) in tile
|
||||
if(obj)
|
||||
obj_icons += new /icon('icons/obj/smooth_structures/table.dmi', "table", SOUTH)
|
||||
for(var/I in obj_icons)
|
||||
var/icon/obj_icon = I
|
||||
tile_icon.Blend(obj_icon, ICON_OVERLAY)
|
||||
@@ -107,4 +125,3 @@ var/datum/subsystem/minimap/SSminimap
|
||||
tile_icon.Scale(TILE_SIZE, TILE_SIZE)
|
||||
// Add the tile to the minimap.
|
||||
minimap.Blend(tile_icon, ICON_OVERLAY, ((tile.x - 1) * TILE_SIZE), ((tile.y - 1) * TILE_SIZE))
|
||||
del(tile_icon)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
var/datum/subsystem/orbit/SSorbit
|
||||
|
||||
/datum/subsystem/orbit
|
||||
name = "Orbits"
|
||||
priority = 35
|
||||
wait = 2
|
||||
flags = SS_NO_INIT|SS_TICKER
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/subsystem/orbit/New()
|
||||
NEW_SS_GLOBAL(SSorbit)
|
||||
|
||||
|
||||
/datum/subsystem/orbit/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/orbit/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/orbit/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!O)
|
||||
processing -= O
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
if (!O.orbiter)
|
||||
qdel(O)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
if (O.lastprocess >= world.time) //we already checked recently
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
var/targetloc = get_turf(O.orbiting)
|
||||
if (targetloc != O.lastloc || O.orbiter.loc != targetloc)
|
||||
O.Check(targetloc)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
var/datum/subsystem/pai/SSpai
|
||||
var/list/obj/item/device/paicard/pai_card_list = list()
|
||||
|
||||
/datum/subsystem/pai
|
||||
name = "pAI"
|
||||
init_order = 20
|
||||
flags = SS_NO_FIRE|SS_NO_INIT
|
||||
|
||||
var/askDelay = 600
|
||||
var/const/NEVER_FOR_THIS_ROUND = -1
|
||||
flags = SS_NO_INIT|SS_NO_FIRE
|
||||
|
||||
var/list/candidates = list()
|
||||
var/list/asked = list()
|
||||
var/ghost_spam = FALSE
|
||||
var/spam_delay = 100
|
||||
|
||||
/datum/subsystem/pai/New()
|
||||
NEW_SS_GLOBAL(SSpai)
|
||||
@@ -29,7 +29,6 @@ var/datum/subsystem/pai/SSpai
|
||||
pai.key = candidate.key
|
||||
|
||||
card.setPersonality(pai)
|
||||
card.looking_for_personality = 0
|
||||
|
||||
ticker.mode.update_cult_icons_removed(card.pai.mind)
|
||||
ticker.mode.update_rev_icons_removed(card.pai.mind)
|
||||
@@ -76,8 +75,8 @@ var/datum/subsystem/pai/SSpai
|
||||
if("submit")
|
||||
if(candidate)
|
||||
candidate.ready = 1
|
||||
for(var/obj/item/device/paicard/p in world)
|
||||
if(p.looking_for_personality == 1)
|
||||
for(var/obj/item/device/paicard/p in pai_card_list)
|
||||
if(!p.pai)
|
||||
p.alertUpdate()
|
||||
usr << browse(null, "window=paiRecruit")
|
||||
return
|
||||
@@ -134,8 +133,20 @@ var/datum/subsystem/pai/SSpai
|
||||
|
||||
M << browse(dat, "window=paiRecruit")
|
||||
|
||||
/datum/subsystem/pai/proc/spam_again()
|
||||
ghost_spam = FALSE
|
||||
|
||||
/datum/subsystem/pai/proc/findPAI(obj/item/device/paicard/p, mob/user)
|
||||
requestRecruits()
|
||||
if(!ghost_spam)
|
||||
ghost_spam = TRUE
|
||||
for(var/mob/dead/observer/G in player_list)
|
||||
if(!G.key || !G.client)
|
||||
continue
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
|
||||
G << "<span class='ghostalert'>Someone is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>"
|
||||
addtimer(src, "spam_again", spam_delay)
|
||||
var/list/available = list()
|
||||
for(var/datum/paiCandidate/c in SSpai.candidates)
|
||||
if(c.ready)
|
||||
@@ -180,36 +191,6 @@ var/datum/subsystem/pai/SSpai
|
||||
|
||||
user << browse(dat, "window=findPai")
|
||||
|
||||
/datum/subsystem/pai/proc/requestRecruits()
|
||||
for(var/mob/dead/observer/O in player_list)
|
||||
if(jobban_isbanned(O, ROLE_PAI))
|
||||
continue
|
||||
if(asked[O.ckey])
|
||||
if(world.time < asked[O.ckey] + askDelay || asked[O.ckey] == NEVER_FOR_THIS_ROUND)
|
||||
continue
|
||||
else
|
||||
asked.Remove(O.ckey)
|
||||
if(O.client)
|
||||
var/hasSubmitted = 0
|
||||
for(var/datum/paiCandidate/c in SSpai.candidates)
|
||||
if(c.key == O.key)
|
||||
hasSubmitted = 1
|
||||
if(!hasSubmitted && (ROLE_PAI in O.client.prefs.be_special))
|
||||
question(O.client)
|
||||
|
||||
/datum/subsystem/pai/proc/question(client/C)
|
||||
set waitfor = 0
|
||||
if(!C)
|
||||
return
|
||||
asked[C.ckey] = world.time
|
||||
var/response = tgalert(C, "Someone is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", "Yes", "No", "Never for this round", StealFocus=0, Timeout=askDelay)
|
||||
if(!C)
|
||||
return //handle logouts that happen whilst the alert is waiting for a response.
|
||||
if(response == "Yes")
|
||||
recruitWindow(C.mob)
|
||||
else if (response == "Never for this round")
|
||||
asked[C.ckey] = NEVER_FOR_THIS_ROUND
|
||||
|
||||
/datum/paiCandidate
|
||||
var/name
|
||||
var/key
|
||||
|
||||
@@ -1,12 +1,42 @@
|
||||
var/datum/subsystem/parallax/SSparallax
|
||||
|
||||
/datum/subsystem/parallax
|
||||
name = "Space Parallax"
|
||||
init_order = 18
|
||||
flags = SS_NO_FIRE
|
||||
name = "parallax"
|
||||
wait = 2
|
||||
flags = SS_POST_FIRE_TIMING | SS_FIRE_IN_LOBBY | SS_BACKGROUND | SS_NO_INIT
|
||||
priority = 65
|
||||
var/list/currentrun
|
||||
|
||||
/datum/subsystem/parallax/New()
|
||||
NEW_SS_GLOBAL(SSparallax)
|
||||
NEW_SS_GLOBAL(SSparallax)
|
||||
return ..()
|
||||
|
||||
/datum/subsystem/parallax/Initialize()
|
||||
create_global_parallax_icons()
|
||||
/datum/subsystem/parallax/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = clients.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(length(currentrun))
|
||||
var/client/C = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!C || !C.eye)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
var/atom/movable/A = C.eye
|
||||
if(!A)
|
||||
return
|
||||
for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc);
|
||||
|
||||
if(A != C.movingmob)
|
||||
if(C.movingmob != null)
|
||||
C.movingmob.client_mobs_in_contents -= C.mob
|
||||
UNSETEMPTY(C.movingmob.client_mobs_in_contents)
|
||||
LAZYINITLIST(A.client_mobs_in_contents)
|
||||
A.client_mobs_in_contents += C.mob
|
||||
C.movingmob = A
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
currentrun = null
|
||||
@@ -0,0 +1,87 @@
|
||||
var/datum/subsystem/persistence/SSpersistence
|
||||
|
||||
/datum/subsystem/persistence
|
||||
name = "Persistence"
|
||||
init_order = -100
|
||||
flags = SS_NO_FIRE
|
||||
var/savefile/secret_satchels
|
||||
var/list/satchel_blacklist = list() //this is a typecache
|
||||
var/list/new_secret_satchels = list() //these are objects
|
||||
var/old_secret_satchels = ""
|
||||
|
||||
/datum/subsystem/persistence/New()
|
||||
NEW_SS_GLOBAL(SSpersistence)
|
||||
|
||||
/datum/subsystem/persistence/Initialize()
|
||||
secret_satchels = new /savefile("data/npc_saves/SecretSatchels.sav")
|
||||
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/weapon/crowbar))
|
||||
secret_satchels[MAP_NAME] >> old_secret_satchels
|
||||
|
||||
var/list/expanded_old_satchels = list()
|
||||
var/placed_satchels = 0
|
||||
|
||||
if(!isnull(old_secret_satchels))
|
||||
expanded_old_satchels = splittext(old_secret_satchels,"#")
|
||||
if(PlaceSecretSatchel(expanded_old_satchels))
|
||||
placed_satchels++
|
||||
else
|
||||
expanded_old_satchels.len = 0
|
||||
|
||||
var/list/free_satchels = list()
|
||||
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,ZLEVEL_STATION), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,ZLEVEL_STATION)))) //Nontrivially expensive but it's roundstart only
|
||||
if(isfloorturf(T) && !istype(T,/turf/open/floor/plating/))
|
||||
free_satchels += new /obj/item/weapon/storage/backpack/satchel/flat/secret(T)
|
||||
if(!isemptylist(free_satchels) && ((free_satchels.len + placed_satchels) >= (50 - expanded_old_satchels.len) * 0.1)) //up to six tiles, more than enough to kill anything that moves
|
||||
break
|
||||
for(var/mob/living/simple_animal/parrot/Poly/P in living_mob_list)
|
||||
twitterize(P.speech_buffer, "polytalk")
|
||||
break //Who's been duping the bird?!
|
||||
|
||||
..()
|
||||
|
||||
/datum/subsystem/persistence/proc/CollectData()
|
||||
CollectSecretSatchels()
|
||||
|
||||
/datum/subsystem/persistence/proc/PlaceSecretSatchel(list/expanded_old_satchels)
|
||||
var/satchel_string
|
||||
|
||||
if(expanded_old_satchels.len >= 20) //guards against low drop pools assuring that one player cannot reliably find his own gear.
|
||||
satchel_string = pick_n_take(expanded_old_satchels)
|
||||
|
||||
old_secret_satchels = jointext(expanded_old_satchels,"#")
|
||||
secret_satchels[MAP_NAME] << old_secret_satchels
|
||||
|
||||
var/list/chosen_satchel = splittext(satchel_string,"|")
|
||||
if(!chosen_satchel || isemptylist(chosen_satchel) || chosen_satchel.len != 3) //Malformed
|
||||
return 0
|
||||
|
||||
var/path = text2path(chosen_satchel[3]) //If the item no longer exist, this returns null
|
||||
if(!path)
|
||||
return 0
|
||||
|
||||
var/obj/item/weapon/storage/backpack/satchel/flat/F = new()
|
||||
F.x = text2num(chosen_satchel[1])
|
||||
F.y = text2num(chosen_satchel[2])
|
||||
F.z = ZLEVEL_STATION
|
||||
if(isfloorturf(F.loc) && !istype(F.loc,/turf/open/floor/plating/))
|
||||
F.hide(1)
|
||||
new path(F)
|
||||
return 1
|
||||
|
||||
/datum/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
for(var/A in new_secret_satchels)
|
||||
var/obj/item/weapon/storage/backpack/satchel/flat/F = A
|
||||
if(qdeleted(F) || F.z != ZLEVEL_STATION || F.invisibility != INVISIBILITY_MAXIMUM)
|
||||
continue
|
||||
var/list/savable_obj = list()
|
||||
for(var/obj/O in F)
|
||||
if(is_type_in_typecache(O, satchel_blacklist) || O.admin_spawned)
|
||||
continue
|
||||
if(O.persistence_replacement)
|
||||
savable_obj += O.persistence_replacement
|
||||
else
|
||||
savable_obj += O.type
|
||||
if(isemptylist(savable_obj))
|
||||
continue
|
||||
old_secret_satchels += "[F.x]|[F.y]|[pick(savable_obj)]#"
|
||||
secret_satchels[MAP_NAME] << old_secret_satchels
|
||||
@@ -0,0 +1,48 @@
|
||||
var/datum/subsystem/pool/SSpool
|
||||
|
||||
/datum/subsystem/pool
|
||||
name = "Pool"
|
||||
init_order = 20
|
||||
flags = SS_BACKGROUND | SS_FIRE_IN_LOBBY
|
||||
var/list/global_pool
|
||||
var/list/pool_levels = list()
|
||||
var/sum = 0
|
||||
|
||||
var/list/maintained_types = list(
|
||||
/obj/item/stack/tile/plasteel = 100
|
||||
)
|
||||
|
||||
var/list/stats_placed_in_pool = list()
|
||||
var/list/stats_pooled_or_newed = list()
|
||||
var/list/stats_reused = list()
|
||||
var/list/stats_created_new = list()
|
||||
|
||||
/datum/subsystem/pool/New()
|
||||
NEW_SS_GLOBAL(SSpool)
|
||||
|
||||
/datum/subsystem/pool/Initialize(timeofday)
|
||||
global_pool = GlobalPool
|
||||
|
||||
/datum/subsystem/pool/stat_entry(msg)
|
||||
if(global_pool)
|
||||
msg += "Types: [global_pool.len]|Total Pooled Objects: [sum]"
|
||||
else
|
||||
msg += "NULL POOL"
|
||||
..(msg)
|
||||
|
||||
/datum/subsystem/pool/fire()
|
||||
sum = 0
|
||||
for(var/type in global_pool + maintained_types)
|
||||
var/list/L = global_pool[type]
|
||||
var/required_number = maintained_types[type] || 0
|
||||
|
||||
// Update pool levels and tracker
|
||||
var/amount = 0
|
||||
if(L)
|
||||
amount = L.len
|
||||
sum += amount
|
||||
|
||||
// why yes, just inflate the pool at one item per tick
|
||||
if(amount < required_number)
|
||||
var/diver = new type
|
||||
qdel(diver)
|
||||
@@ -0,0 +1,10 @@
|
||||
//Fires five times every second.
|
||||
|
||||
var/datum/subsystem/processing/fastprocess/SSfastprocess
|
||||
/datum/subsystem/processing/fastprocess
|
||||
name = "Fast Processing"
|
||||
wait = 2
|
||||
stat_tag = "FP"
|
||||
|
||||
/datum/subsystem/processing/fastprocess/New()
|
||||
NEW_SS_GLOBAL(SSfastprocess)
|
||||
+1
-10
@@ -14,14 +14,13 @@ var/datum/subsystem/objects/SSobj
|
||||
var/list/atom_spawners = list()
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
var/list/burning = list()
|
||||
|
||||
/datum/subsystem/objects/New()
|
||||
NEW_SS_GLOBAL(SSobj)
|
||||
|
||||
/datum/subsystem/objects/Initialize(timeofdayl)
|
||||
trigger_atom_spawners()
|
||||
setupGenetics()
|
||||
setupGenetics() //to set the mutations' place in structural enzymes, so monkey.initialize() knows where to put the monkey mutation.
|
||||
for(var/thing in world)
|
||||
var/atom/A = thing
|
||||
A.initialize()
|
||||
@@ -55,12 +54,6 @@ var/datum/subsystem/objects/SSobj
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
for(var/obj/burningobj in SSobj.burning)
|
||||
if(burningobj && (burningobj.burn_state == ON_FIRE))
|
||||
if(burningobj.burn_world_time < world.time)
|
||||
burningobj.burn()
|
||||
else
|
||||
SSobj.burning.Remove(burningobj)
|
||||
|
||||
/datum/subsystem/objects/proc/setup_template_objects(list/objects)
|
||||
trigger_atom_spawners(0, ignore_z=TRUE)
|
||||
@@ -73,5 +66,3 @@ var/datum/subsystem/objects/SSobj
|
||||
atom_spawners = SSobj.atom_spawners
|
||||
if (istype(SSobj.processing))
|
||||
processing = SSobj.processing
|
||||
if (istype(SSobj.burning))
|
||||
burning = SSobj.burning
|
||||
@@ -0,0 +1,34 @@
|
||||
//Used to process objects. Fires once every second.
|
||||
|
||||
var/datum/subsystem/processing/SSprocessing
|
||||
/datum/subsystem/processing
|
||||
name = "Processing"
|
||||
priority = 25
|
||||
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
|
||||
wait = 10
|
||||
|
||||
var/stat_tag = "P" //Used for logging
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
/datum/subsystem/processing/New()
|
||||
NEW_SS_GLOBAL(SSprocessing)
|
||||
|
||||
/datum/subsystem/processing/stat_entry()
|
||||
..("[stat_tag]:[processing.len]")
|
||||
|
||||
/datum/subsystem/processing/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
currentrun = processing.Copy()
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/current_run = currentrun
|
||||
|
||||
while(current_run.len)
|
||||
var/datum/thing = current_run[current_run.len]
|
||||
current_run.len--
|
||||
if(thing)
|
||||
thing.process(wait)
|
||||
else
|
||||
processing -= thing
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -0,0 +1,17 @@
|
||||
var/datum/subsystem/religion/SSreligion
|
||||
|
||||
/datum/subsystem/religion
|
||||
name = "Religion"
|
||||
init_order = 19
|
||||
flags = SS_NO_FIRE|SS_NO_INIT
|
||||
|
||||
var/bible_deity_name
|
||||
var/Bible_icon_state
|
||||
var/Bible_item_state
|
||||
var/Bible_name
|
||||
var/Bible_deity_name
|
||||
|
||||
var/holy_weapon
|
||||
|
||||
/datum/subsystem/religion/New()
|
||||
NEW_SS_GLOBAL(SSreligion)
|
||||
@@ -3,12 +3,16 @@ var/datum/subsystem/server_maint/SSserver
|
||||
/datum/subsystem/server_maint
|
||||
name = "Server Tasks"
|
||||
wait = 6000
|
||||
init_order = 19
|
||||
flags = SS_NO_TICK_CHECK|SS_NO_INIT
|
||||
flags = SS_NO_TICK_CHECK
|
||||
|
||||
/datum/subsystem/server_maint/New()
|
||||
NEW_SS_GLOBAL(SSserver)
|
||||
|
||||
/datum/subsystem/server_maint/Initialize(timeofday)
|
||||
if (config.hub)
|
||||
world.visibility = 1
|
||||
..()
|
||||
|
||||
/datum/subsystem/server_maint/fire()
|
||||
//handle kicking inactive players
|
||||
if(config.kick_inactive > 0)
|
||||
@@ -17,7 +21,7 @@ var/datum/subsystem/server_maint/SSserver
|
||||
if(!istype(C.mob, /mob/dead))
|
||||
log_access("AFK: [key_name(C)]")
|
||||
C << "<span class='danger'>You have been inactive for more than 10 minutes and have been disconnected.</span>"
|
||||
del(C)
|
||||
qdel(C)
|
||||
|
||||
if(config.sql_enabled)
|
||||
sql_poll_players()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define HIGHLIGHT_DYNAMIC_TRANSIT 1
|
||||
|
||||
var/datum/subsystem/shuttle/SSshuttle
|
||||
|
||||
/datum/subsystem/shuttle
|
||||
@@ -10,6 +12,10 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
var/list/stationary = list()
|
||||
var/list/transit = list()
|
||||
|
||||
var/list/turf/transit_turfs = list()
|
||||
var/list/transit_requesters = list()
|
||||
var/clear_transit = FALSE
|
||||
|
||||
//emergency shuttle stuff
|
||||
var/obj/docking_port/mobile/emergency/emergency
|
||||
var/obj/docking_port/mobile/emergency/backup/backup_shuttle
|
||||
@@ -18,6 +24,7 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
var/emergencyEscapeTime = 1200 //time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
|
||||
var/area/emergencyLastCallLoc
|
||||
var/emergencyNoEscape
|
||||
var/list/hostileEnvironments = list()
|
||||
|
||||
//supply shuttle stuff
|
||||
var/obj/docking_port/mobile/supply/supply
|
||||
@@ -33,6 +40,9 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
|
||||
var/datum/round_event/shuttle_loan/shuttle_loan
|
||||
|
||||
var/shuttle_purchased = FALSE //If the station has purchased a replacement escape shuttle this round
|
||||
var/list/shuttle_purchase_requirements_met = list() //For keeping track of ingame events that would unlock new shuttles, such as defeating a boss or discovering a secret item
|
||||
|
||||
/datum/subsystem/shuttle/New()
|
||||
NEW_SS_GLOBAL(SSshuttle)
|
||||
|
||||
@@ -53,16 +63,87 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
supply_packs[P.type] = P
|
||||
|
||||
initial_move()
|
||||
..()
|
||||
setup_transit_zone()
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
color_space()
|
||||
#endif
|
||||
|
||||
/datum/subsystem/shuttle/proc/setup_transit_zone()
|
||||
if(transit_markers.len == 0)
|
||||
WARNING("No /obj/effect/landmark/transit placed on the map!")
|
||||
return
|
||||
// transit zone
|
||||
var/turf/A = get_turf(transit_markers[1])
|
||||
var/turf/B = get_turf(transit_markers[2])
|
||||
for(var/i in block(A, B))
|
||||
var/turf/T = i
|
||||
T.ChangeTurf(/turf/open/space)
|
||||
transit_turfs += T
|
||||
T.flags |= UNUSED_TRANSIT_TURF
|
||||
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
/datum/subsystem/shuttle/proc/color_space()
|
||||
if(transit_markers.len == 0)
|
||||
WARNING("No /obj/effect/landmark/transit placed on the map!")
|
||||
return
|
||||
var/turf/A = get_turf(transit_markers[1])
|
||||
var/turf/B = get_turf(transit_markers[2])
|
||||
for(var/i in block(A, B))
|
||||
var/turf/T = i
|
||||
// Only dying the "pure" space, not the transit tiles
|
||||
if(istype(T, /turf/open/space/transit) || !isspaceturf(T))
|
||||
continue
|
||||
if((T.x == A.x) || (T.x == B.x) || (T.y == A.y) || (T.y == B.y))
|
||||
T.color = "#ffff00"
|
||||
else
|
||||
T.color = "#00ffff"
|
||||
#endif
|
||||
|
||||
//world.log << "[transit_turfs.len] transit turfs registered"
|
||||
|
||||
/datum/subsystem/shuttle/fire()
|
||||
for(var/thing in mobile)
|
||||
if(thing)
|
||||
var/obj/docking_port/mobile/P = thing
|
||||
P.check()
|
||||
if(!thing)
|
||||
mobile.Remove(thing)
|
||||
continue
|
||||
mobile.Remove(thing)
|
||||
var/obj/docking_port/mobile/P = thing
|
||||
P.check()
|
||||
var/changed_transit = FALSE
|
||||
for(var/thing in transit)
|
||||
var/obj/docking_port/stationary/transit/T = thing
|
||||
if(!T.owner)
|
||||
qdel(T, force=TRUE)
|
||||
changed_transit = TRUE
|
||||
// This next one removes transit docks/zones that aren't
|
||||
// immediately being used. This will mean that the zone creation
|
||||
// code will be running a lot.
|
||||
var/obj/docking_port/mobile/owner = T.owner
|
||||
if(owner)
|
||||
var/idle = owner.mode == SHUTTLE_IDLE
|
||||
var/not_centcom_evac = owner.launch_status == NOLAUNCH
|
||||
var/not_in_use = (!T.get_docked())
|
||||
if(idle && not_centcom_evac && not_in_use)
|
||||
qdel(T, force=TRUE)
|
||||
changed_transit = TRUE
|
||||
if(clear_transit)
|
||||
transit_requesters.Cut()
|
||||
for(var/i in transit)
|
||||
qdel(i, force=TRUE)
|
||||
setup_transit_zone()
|
||||
clear_transit = FALSE
|
||||
changed_transit = TRUE
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
if(changed_transit)
|
||||
color_space()
|
||||
#endif
|
||||
|
||||
while(transit_requesters.len)
|
||||
var/requester = popleft(transit_requesters)
|
||||
var/success = generate_transit_dock(requester)
|
||||
if(!success) // BACK OF THE QUEUE
|
||||
transit_requesters += requester
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/subsystem/shuttle/proc/getShuttle(id)
|
||||
for(var/obj/docking_port/mobile/M in mobile)
|
||||
@@ -105,6 +186,9 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
if(SHUTTLE_DOCKED)
|
||||
user << "The emergency shuttle is already here."
|
||||
return
|
||||
if(SHUTTLE_IGNITING)
|
||||
user << "The emergency shuttle is firing its engines to leave."
|
||||
return
|
||||
if(SHUTTLE_ESCAPE)
|
||||
user << "The emergency shuttle is moving away to a safe distance."
|
||||
return
|
||||
@@ -114,22 +198,24 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
|
||||
call_reason = trim(html_encode(call_reason))
|
||||
|
||||
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH)
|
||||
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && seclevel2num(get_security_level()) > SEC_LEVEL_GREEN)
|
||||
user << "You must provide a reason."
|
||||
return
|
||||
|
||||
var/area/signal_origin = get_area(user)
|
||||
var/emergency_reason = "\nNature of emergency:\n\n[call_reason]"
|
||||
if(seclevel2num(get_security_level()) == SEC_LEVEL_RED) // There is a serious threat we gotta move no time to give them five minutes.
|
||||
emergency.request(null, 0.5, signal_origin, html_decode(emergency_reason), 1)
|
||||
else
|
||||
emergency.request(null, 1, signal_origin, html_decode(emergency_reason), 0)
|
||||
var/security_num = seclevel2num(get_security_level())
|
||||
switch(security_num)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
emergency.request(null, 2, signal_origin, html_decode(emergency_reason), 0)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
emergency.request(null, 1, signal_origin, html_decode(emergency_reason), 0)
|
||||
else
|
||||
emergency.request(null, 0.5, signal_origin, html_decode(emergency_reason), 1) // There is a serious threat we gotta move no time to give them five minutes.
|
||||
|
||||
log_game("[key_name(user)] has called the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has called the shuttle.")
|
||||
|
||||
return
|
||||
|
||||
// Called when an emergency shuttle mobile docking port is
|
||||
// destroyed, which will only happen with admin intervention
|
||||
/datum/subsystem/shuttle/proc/emergencyDeregister()
|
||||
@@ -149,19 +235,24 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
return
|
||||
if(ticker.mode.name == "meteor")
|
||||
return
|
||||
if(seclevel2num(get_security_level()) == SEC_LEVEL_RED)
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
|
||||
return
|
||||
else
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.5)
|
||||
return
|
||||
var/security_num = seclevel2num(get_security_level())
|
||||
switch(security_num)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
if(emergency.timeLeft(1) < emergencyCallTime)
|
||||
return
|
||||
if(SEC_LEVEL_BLUE)
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.5)
|
||||
return
|
||||
else
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
|
||||
return
|
||||
return 1
|
||||
|
||||
/datum/subsystem/shuttle/proc/autoEvac()
|
||||
var/callShuttle = 1
|
||||
|
||||
for(var/thing in shuttle_caller_list)
|
||||
if(istype(thing, /mob/living/silicon/ai))
|
||||
if(isAI(thing))
|
||||
var/mob/living/silicon/ai/AI = thing
|
||||
if(AI.stat || !AI.client)
|
||||
continue
|
||||
@@ -181,6 +272,34 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
log_game("There is no means of calling the shuttle anymore. Shuttle automatically called.")
|
||||
message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.")
|
||||
|
||||
/datum/subsystem/shuttle/proc/registerHostileEnvironment(datum/bad)
|
||||
hostileEnvironments[bad] = TRUE
|
||||
checkHostileEnvironment()
|
||||
|
||||
/datum/subsystem/shuttle/proc/clearHostileEnvironment(datum/bad)
|
||||
hostileEnvironments -= bad
|
||||
checkHostileEnvironment()
|
||||
|
||||
/datum/subsystem/shuttle/proc/checkHostileEnvironment()
|
||||
for(var/datum/d in hostileEnvironments)
|
||||
if(!istype(d) || qdeleted(d))
|
||||
hostileEnvironments -= d
|
||||
emergencyNoEscape = hostileEnvironments.len
|
||||
|
||||
if(emergencyNoEscape && (emergency.mode == SHUTTLE_IGNITING))
|
||||
emergency.mode = SHUTTLE_STRANDED
|
||||
emergency.timer = null
|
||||
emergency.sound_played = FALSE
|
||||
priority_announce("Hostile environment detected. \
|
||||
Departure has been postponed indefinitely pending \
|
||||
conflict resolution.", null, 'sound/misc/notice1.ogg', "Priority")
|
||||
if(!emergencyNoEscape && (emergency.mode == SHUTTLE_STRANDED))
|
||||
emergency.mode = SHUTTLE_DOCKED
|
||||
emergency.setTimer(emergencyDockTime)
|
||||
priority_announce("Hostile environment resolved. \
|
||||
You have 3 minutes to board the Emergency Shuttle.",
|
||||
null, 'sound/AI/shuttledock.ogg', "Priority")
|
||||
|
||||
//try to move/request to dockHome if possible, otherwise dockAway. Mainly used for admin buttons
|
||||
/datum/subsystem/shuttle/proc/toggleShuttle(shuttleId, dockHome, dockAway, timed)
|
||||
var/obj/docking_port/mobile/M = getShuttle(shuttleId)
|
||||
@@ -213,11 +332,149 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
return 2
|
||||
return 0 //dock successful
|
||||
|
||||
/datum/subsystem/shuttle/proc/request_transit_dock(obj/docking_port/mobile/M)
|
||||
if(!istype(M))
|
||||
throw EXCEPTION("[M] is not a mobile docking port")
|
||||
|
||||
if(M.assigned_transit)
|
||||
return
|
||||
else
|
||||
if(!(M in transit_requesters))
|
||||
transit_requesters += M
|
||||
|
||||
/datum/subsystem/shuttle/proc/generate_transit_dock(obj/docking_port/mobile/M)
|
||||
// First, determine the size of the needed zone
|
||||
// Because of shuttle rotation, the "width" of the shuttle is not
|
||||
// always x.
|
||||
var/travel_dir = M.preferred_direction
|
||||
// Remember, the direction is the direction we appear to be
|
||||
// coming from
|
||||
var/dock_angle = dir2angle(M.preferred_direction) + M.port_angle + 180
|
||||
var/dock_dir = angle2dir(dock_angle)
|
||||
|
||||
var/transit_width = SHUTTLE_TRANSIT_BORDER * 2
|
||||
var/transit_height = SHUTTLE_TRANSIT_BORDER * 2
|
||||
|
||||
// Shuttles travelling on their side have their dimensions swapped
|
||||
// from our perspective
|
||||
switch(dock_dir)
|
||||
if(NORTH, SOUTH)
|
||||
transit_width += M.width
|
||||
transit_height += M.height
|
||||
if(EAST, WEST)
|
||||
transit_width += M.height
|
||||
transit_height += M.width
|
||||
/*
|
||||
world << "The attempted transit dock will be [transit_width] width, and \
|
||||
[transit_height] in height. The travel dir is [travel_dir]."
|
||||
*/
|
||||
|
||||
// Then find a place to put the zone
|
||||
|
||||
var/list/proposed_zone
|
||||
|
||||
base:
|
||||
for(var/i in transit_turfs)
|
||||
CHECK_TICK
|
||||
var/turf/topleft = i
|
||||
if(!(topleft.flags & UNUSED_TRANSIT_TURF))
|
||||
continue
|
||||
var/turf/bottomright = locate(topleft.x + transit_width,
|
||||
topleft.y + transit_height, topleft.z)
|
||||
if(!bottomright)
|
||||
continue
|
||||
if(!(bottomright.flags & UNUSED_TRANSIT_TURF))
|
||||
continue
|
||||
|
||||
proposed_zone = block(topleft, bottomright)
|
||||
if(!proposed_zone)
|
||||
continue
|
||||
for(var/j in proposed_zone)
|
||||
var/turf/T = j
|
||||
if(!T)
|
||||
continue base
|
||||
if(!(T.flags & UNUSED_TRANSIT_TURF))
|
||||
continue base
|
||||
//world << "[COORD(topleft)] and [COORD(bottomright)]"
|
||||
break base
|
||||
|
||||
if((!proposed_zone) || (!proposed_zone.len))
|
||||
return FALSE
|
||||
|
||||
var/turf/topleft = proposed_zone[1]
|
||||
//world << "[COORD(topleft)] is TOPLEFT"
|
||||
// Then create a transit docking port in the middle
|
||||
var/coords = M.return_coords(0, 0, dock_dir)
|
||||
//world << json_encode(coords)
|
||||
/* 0------2
|
||||
| |
|
||||
| |
|
||||
| x |
|
||||
3------1
|
||||
*/
|
||||
|
||||
var/x0 = coords[1]
|
||||
var/y0 = coords[2]
|
||||
var/x1 = coords[3]
|
||||
var/y1 = coords[4]
|
||||
// Then we want the point closest to -infinity,-infinity
|
||||
var/x2 = min(x0, x1)
|
||||
var/y2 = min(y0, y1)
|
||||
/*
|
||||
var/lowx = topleft.x + SHUTTLE_TRANSIT_BORDER
|
||||
var/lowy = topleft.y + SHUTTLE_TRANSIT_BORDER
|
||||
|
||||
var/turf/low_point = locate(lowx, lowy, topleft.z)
|
||||
new /obj/effect/landmark/stationary(low_point)
|
||||
world << "Starting at the low point, we go [x2],[y2]"
|
||||
*/
|
||||
// Then invert the numbers
|
||||
var/transit_x = topleft.x + SHUTTLE_TRANSIT_BORDER + abs(x2)
|
||||
var/transit_y = topleft.y + SHUTTLE_TRANSIT_BORDER + abs(y2)
|
||||
|
||||
var/transit_path = /turf/open/space/transit
|
||||
switch(travel_dir)
|
||||
if(NORTH)
|
||||
transit_path = /turf/open/space/transit/north
|
||||
if(SOUTH)
|
||||
transit_path = /turf/open/space/transit/south
|
||||
if(EAST)
|
||||
transit_path = /turf/open/space/transit/east
|
||||
if(WEST)
|
||||
transit_path = /turf/open/space/transit/west
|
||||
|
||||
//world << "Docking port at [transit_x], [transit_y], [topleft.z]"
|
||||
var/turf/midpoint = locate(transit_x, transit_y, topleft.z)
|
||||
if(!midpoint)
|
||||
return FALSE
|
||||
//world << "Making transit dock at [COORD(midpoint)]"
|
||||
var/area/shuttle/transit/A = new()
|
||||
A.parallax_movedir = travel_dir
|
||||
var/obj/docking_port/stationary/transit/new_transit_dock = new(midpoint)
|
||||
new_transit_dock.assigned_turfs = proposed_zone
|
||||
new_transit_dock.name = "Transit for [M.id]/[M.name]"
|
||||
new_transit_dock.turf_type = transit_path
|
||||
new_transit_dock.owner = M
|
||||
new_transit_dock.assigned_area = A
|
||||
|
||||
|
||||
// Add 180, because ports point inwards, rather than outwards
|
||||
new_transit_dock.setDir(angle2dir(dock_angle))
|
||||
|
||||
for(var/i in new_transit_dock.assigned_turfs)
|
||||
var/turf/T = i
|
||||
T.ChangeTurf(transit_path)
|
||||
T.flags &= ~(UNUSED_TRANSIT_TURF)
|
||||
A.contents += T
|
||||
|
||||
M.assigned_transit = new_transit_dock
|
||||
return TRUE
|
||||
|
||||
/datum/subsystem/shuttle/proc/initial_move()
|
||||
for(var/obj/docking_port/mobile/M in mobile)
|
||||
if(!M.roundstart_move)
|
||||
continue
|
||||
moveShuttle(M.id, "[M.roundstart_move]", 0)
|
||||
M.dockRoundstart()
|
||||
CHECK_TICK
|
||||
|
||||
/datum/subsystem/shuttle/Recover()
|
||||
@@ -239,6 +496,8 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
backup_shuttle = SSshuttle.backup_shuttle
|
||||
if (istype(SSshuttle.supply))
|
||||
supply = SSshuttle.supply
|
||||
if (istype(SSshuttle.transit_turfs))
|
||||
transit_turfs = SSshuttle.transit_turfs
|
||||
|
||||
centcom_message = SSshuttle.centcom_message
|
||||
ordernum = SSshuttle.ordernum
|
||||
|
||||
@@ -2,9 +2,9 @@ var/datum/subsystem/spacedrift/SSspacedrift
|
||||
|
||||
/datum/subsystem/spacedrift
|
||||
name = "Space Drift"
|
||||
priority = 40
|
||||
priority = 30
|
||||
wait = 5
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
flags = SS_NO_INIT|SS_KEEP_TIMING
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
@@ -61,3 +61,4 @@ var/datum/subsystem/spacedrift/SSspacedrift
|
||||
AM.inertia_last_loc = AM.loc
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
var/datum/subsystem/squeak/SSsqueak
|
||||
|
||||
// The Squeak
|
||||
// because this is about placement of mice mobs, and nothing to do with
|
||||
// mice - the computer peripheral
|
||||
|
||||
/datum/subsystem/squeak
|
||||
name = "Squeak"
|
||||
priority = 40
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/exposed_wires = list()
|
||||
|
||||
/datum/subsystem/squeak/New()
|
||||
NEW_SS_GLOBAL(SSsqueak)
|
||||
|
||||
/datum/subsystem/squeak/Initialize(timeofday)
|
||||
trigger_migration()
|
||||
|
||||
/datum/subsystem/squeak/proc/trigger_migration(num_mice=10)
|
||||
find_exposed_wires()
|
||||
|
||||
var/mob/living/simple_animal/mouse/M
|
||||
var/turf/proposed_turf
|
||||
|
||||
while((num_mice > 0) && exposed_wires.len)
|
||||
proposed_turf = pick_n_take(exposed_wires)
|
||||
if(!M)
|
||||
M = new(proposed_turf)
|
||||
else
|
||||
M.forceMove(proposed_turf)
|
||||
if(M.environment_is_safe())
|
||||
num_mice -= 1
|
||||
M = null
|
||||
|
||||
/datum/subsystem/squeak/proc/find_exposed_wires()
|
||||
exposed_wires.Cut()
|
||||
|
||||
var/list/all_turfs = block(locate(1,1,1), locate(world.maxx,world.maxy,1))
|
||||
for(var/turf/open/floor/plating/T in all_turfs)
|
||||
if(is_blocked_turf(T))
|
||||
continue
|
||||
if(locate(/obj/structure/cable) in T)
|
||||
exposed_wires += T
|
||||
@@ -0,0 +1,37 @@
|
||||
var/datum/subsystem/stickyban/SSstickyban
|
||||
|
||||
/datum/subsystem/stickyban
|
||||
name = "Sticky Ban"
|
||||
init_order = -10
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/cache = list()
|
||||
|
||||
/datum/subsystem/stickyban/New()
|
||||
NEW_SS_GLOBAL(SSstickyban)
|
||||
|
||||
/datum/subsystem/stickyban/Initialize(timeofday)
|
||||
var/list/bannedkeys = world.GetConfig("ban")
|
||||
//sanitize the sticky ban list
|
||||
for (var/bannedkey in bannedkeys)
|
||||
var/ckey = ckey(bannedkey)
|
||||
var/list/ban = stickyban2list(world.GetConfig("ban", bannedkey))
|
||||
|
||||
//byond stores sticky bans by key, that can end up confusing things
|
||||
//i also remove it here so that if any stickybans cause a runtime, they just stop existing
|
||||
world.SetConfig("ban", bannedkey, null)
|
||||
|
||||
if (!ban["ckey"])
|
||||
ban["ckey"] = ckey
|
||||
|
||||
//storing these can break things and isn't needed for sticky ban tracking
|
||||
ban -= "IP"
|
||||
ban -= "computer_id"
|
||||
|
||||
ban["matches_this_round"] = list()
|
||||
ban["existing_user_matches_this_round"] = list()
|
||||
ban["admin_matches_this_round"] = list()
|
||||
cache[ckey] = ban
|
||||
|
||||
for (var/bannedckey in cache)
|
||||
world.SetConfig("ban", bannedckey, list2stickyban(cache[bannedckey]))
|
||||
@@ -18,6 +18,9 @@ var/datum/subsystem/tgui/SStgui
|
||||
|
||||
NEW_SS_GLOBAL(SStgui)
|
||||
|
||||
/datum/subsystem/tgui/Shutdown()
|
||||
close_all_uis()
|
||||
|
||||
/datum/subsystem/tgui/stat_entry()
|
||||
..("P:[processing_uis.len]")
|
||||
|
||||
|
||||
@@ -22,21 +22,19 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking.
|
||||
|
||||
//These bible variables should be a preference
|
||||
var/Bible_icon_state //icon_state the chaplain has chosen for his bible
|
||||
var/Bible_item_state //item_state the chaplain has chosen for his bible
|
||||
var/Bible_name //name of the bible
|
||||
var/Bible_deity_name //name of chaplin's deity
|
||||
|
||||
var/list/syndicate_coalition = list() //list of traitor-compatible factions
|
||||
var/list/factions = list() //list of all factions
|
||||
var/list/availablefactions = list() //list of factions with openings
|
||||
var/list/scripture_states = list(SCRIPTURE_DRIVER = TRUE, \
|
||||
SCRIPTURE_SCRIPT = FALSE, \
|
||||
SCRIPTURE_APPLICATION = FALSE, \
|
||||
SCRIPTURE_REVENANT = FALSE, \
|
||||
SCRIPTURE_JUDGEMENT = FALSE) //list of clockcult scripture states for announcements
|
||||
|
||||
var/delay_end = 0 //if set true, the round will not restart on it's own
|
||||
|
||||
var/triai = 0 //Global holder for Triumvirate
|
||||
var/tipped = 0 //Did we broadcast the tip of the day yet?
|
||||
var/modevoted = 0 //Have we sent a vote for the gamemode?
|
||||
var/selected_tip // What will be the tip of the day?
|
||||
|
||||
var/timeLeft = 1200 //pregame timer
|
||||
@@ -51,11 +49,12 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
var/maprotatechecked = 0
|
||||
|
||||
var/news_report
|
||||
|
||||
/datum/subsystem/ticker/New()
|
||||
NEW_SS_GLOBAL(ticker)
|
||||
|
||||
login_music = pickweight(list('sound/ambience/title1.ogg' = 30, 'sound/ambience/title2.ogg' = 30, 'sound/ambience/title3.ogg' = 30, 'sound/ambience/title4.ogg' = 30, 'sound/ambience/title5.ogg' = 30, 'sound/ambience/title6.ogg' = 30, 'sound/ambience/title7.ogg' = 30, 'sound/ambience/clown.ogg' = 3)) // choose title music!
|
||||
login_music = pickweight(list('sound/ambience/title2.ogg' = 15, 'sound/ambience/title1.ogg' =15, 'sound/ambience/title3.ogg' =14, 'sound/ambience/title4.ogg' =14, 'sound/misc/i_did_not_grief_them.ogg' =14, 'sound/ambience/clown.ogg' = 9)) // choose title music!
|
||||
if(SSevent.holidays && SSevent.holidays[APRIL_FOOLS])
|
||||
login_music = 'sound/ambience/clown.ogg'
|
||||
|
||||
@@ -64,15 +63,14 @@ var/datum/subsystem/ticker/ticker
|
||||
syndicate_code_phrase = generate_code_phrase()
|
||||
if(!syndicate_code_response)
|
||||
syndicate_code_response = generate_code_phrase()
|
||||
setupFactions()
|
||||
..()
|
||||
|
||||
/datum/subsystem/ticker/fire()
|
||||
switch(current_state)
|
||||
if(GAME_STATE_STARTUP)
|
||||
timeLeft = config.lobby_countdown * 10
|
||||
world << "<b><font color='blue'>Welcome to the pre-game lobby!</font></b>"
|
||||
world << "Please, setup your character and select ready. Game will start in [config.lobby_countdown] seconds"
|
||||
world << "<span class='boldnotice'>Welcome to [station_name()]!</span>"
|
||||
world << "Please set up your character and select \"Ready\". The game will start in [config.lobby_countdown] seconds."
|
||||
current_state = GAME_STATE_PREGAME
|
||||
|
||||
if(GAME_STATE_PREGAME)
|
||||
@@ -89,10 +87,6 @@ var/datum/subsystem/ticker/ticker
|
||||
return
|
||||
timeLeft -= wait
|
||||
|
||||
if(timeLeft <= 1200 && !modevoted) //Vote for the round type
|
||||
send_gamemode_vote()
|
||||
modevoted = TRUE
|
||||
|
||||
if(timeLeft <= 300 && !tipped)
|
||||
send_tip_of_the_round()
|
||||
tipped = TRUE
|
||||
@@ -109,6 +103,7 @@ var/datum/subsystem/ticker/ticker
|
||||
mode.process(wait * 0.1)
|
||||
check_queue()
|
||||
check_maprotate()
|
||||
scripture_states = scripture_unlock_alert(scripture_states)
|
||||
|
||||
if(!mode.explosion_in_progress && mode.check_finished() || force_ending)
|
||||
current_state = GAME_STATE_FINISHED
|
||||
@@ -159,19 +154,19 @@ var/datum/subsystem/ticker/ticker
|
||||
if(!can_continue)
|
||||
qdel(mode)
|
||||
mode = null
|
||||
world << "<B>Error setting up [master_mode]. It's likely that there are no available antagonists for the selected mode.</B> Reverting to pre-game lobby."
|
||||
world << "<B>Error setting up [master_mode].</B> Reverting to pre-game lobby."
|
||||
SSjob.ResetOccupations()
|
||||
return 0
|
||||
else
|
||||
world << "<span class='notice'>DEBUG: Bypassing prestart checks..."
|
||||
message_admins("<span class='notice'>DEBUG: Bypassing prestart checks...</span>")
|
||||
|
||||
if(hide_mode)
|
||||
var/list/modes = new
|
||||
for (var/datum/game_mode/M in runnable_modes)
|
||||
modes += M.name
|
||||
modes = sortList(modes)
|
||||
world << "<B>The current game mode is - Secret!</B>"
|
||||
world << "<B>Possibilities:</B> [english_list(modes)]"
|
||||
world << "<b>The gamemode is: secret!\n\
|
||||
Possibilities:</B> [english_list(modes)]"
|
||||
else
|
||||
mode.announce()
|
||||
|
||||
@@ -222,25 +217,25 @@ var/datum/subsystem/ticker/ticker
|
||||
//initialise our cinematic screen object
|
||||
cinematic = new /obj/screen{icon='icons/effects/station_explosion.dmi';icon_state="station_intact";layer=21;mouse_opacity=0;screen_loc="1,0";}(src)
|
||||
|
||||
var/obj/structure/bed/temp_buckle = new(src)
|
||||
if(station_missed)
|
||||
for(var/mob/M in mob_list)
|
||||
M.buckled = temp_buckle //buckles the mob so it can't do anything
|
||||
M.notransform = TRUE //stop everything moving
|
||||
if(M.client)
|
||||
M.client.screen += cinematic //show every client the cinematic
|
||||
else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived"
|
||||
for(var/mob/M in mob_list)
|
||||
M.buckled = temp_buckle
|
||||
if(M.client)
|
||||
M.client.screen += cinematic
|
||||
if(M.stat != DEAD)
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z==1)
|
||||
M.death(0) //no mercy
|
||||
else
|
||||
M.notransform=TRUE //no moving for you
|
||||
|
||||
//Now animate the cinematic
|
||||
switch(station_missed)
|
||||
if(1) //nuke was nearby but (mostly) missed
|
||||
if(NUKE_NEAR_MISS) //nuke was nearby but (mostly) missed
|
||||
if( mode && !override )
|
||||
override = mode.name
|
||||
switch( override )
|
||||
@@ -266,7 +261,7 @@ var/datum/subsystem/ticker/ticker
|
||||
//flick("end",cinematic)
|
||||
|
||||
|
||||
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
sleep(50)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
else //station was destroyed
|
||||
@@ -300,8 +295,8 @@ var/datum/subsystem/ticker/ticker
|
||||
if(cinematic)
|
||||
qdel(cinematic)
|
||||
cinematic = null
|
||||
if(temp_buckle)
|
||||
qdel(temp_buckle)
|
||||
for(var/mob/M in mob_list)
|
||||
M.notransform = FALSE
|
||||
return //Faster exit, since nothing happened
|
||||
else //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
@@ -314,8 +309,8 @@ var/datum/subsystem/ticker/ticker
|
||||
spawn(300)
|
||||
if(cinematic)
|
||||
qdel(cinematic) //end the cinematic
|
||||
if(temp_buckle)
|
||||
qdel(temp_buckle) //release everybody
|
||||
for(var/mob/M in mob_list)
|
||||
M.notransform = FALSE //gratz you survived
|
||||
return
|
||||
|
||||
|
||||
@@ -350,7 +345,7 @@ var/datum/subsystem/ticker/ticker
|
||||
SSjob.EquipRank(player, player.mind.assigned_role, 0)
|
||||
if(captainless)
|
||||
for(var/mob/M in player_list)
|
||||
if(!istype(M,/mob/new_player))
|
||||
if(!isnewplayer(M))
|
||||
M << "Captainship not forced on anyone."
|
||||
|
||||
|
||||
@@ -385,10 +380,15 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
world << "<BR>[TAB]Shift Duration: <B>[round(world.time / 36000)]:[add_zero("[world.time / 600 % 60]", 2)]:[world.time / 100 % 6][world.time / 100 % 10]</B>"
|
||||
world << "<BR>[TAB]Station Integrity: <B>[mode.station_was_nuked ? "<font color='red'>Destroyed</font>" : "[station_integrity]%"]</B>"
|
||||
if(mode.station_was_nuked)
|
||||
ticker.news_report = STATION_DESTROYED_NUKE
|
||||
if(joined_player_list.len)
|
||||
world << "<BR>[TAB]Total Population: <B>[joined_player_list.len]</B>"
|
||||
if(station_evacuated)
|
||||
world << "<BR>[TAB]Evacuation Rate: <B>[num_escapees] ([round((num_escapees/joined_player_list.len)*100, 0.1)]%)</B>"
|
||||
news_report = STATION_EVACUATED
|
||||
if(SSshuttle.emergency.is_hijacked())
|
||||
news_report = SHUTTLE_HIJACK
|
||||
world << "<BR>[TAB]Survival Rate: <B>[num_survivors] ([round((num_survivors/joined_player_list.len)*100, 0.1)]%)</B>"
|
||||
world << "<BR>"
|
||||
|
||||
@@ -421,6 +421,9 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
mode.declare_completion()//To declare normal completion.
|
||||
|
||||
if(cross_allowed)
|
||||
send_news_report()
|
||||
|
||||
//calls auto_declare_completion_* for all modes
|
||||
for(var/handler in typesof(/datum/game_mode/proc))
|
||||
if (findtext("[handler]","auto_declare_completion_"))
|
||||
@@ -443,6 +446,44 @@ var/datum/subsystem/ticker/ticker
|
||||
for(var/i in total_antagonists)
|
||||
log_game("[i]s[total_antagonists[i]].")
|
||||
|
||||
//Borers
|
||||
var/borerwin = FALSE
|
||||
if(borers.len)
|
||||
var/borertext = "<br><font size=3><b>The borers were:</b></font>"
|
||||
for(var/mob/living/simple_animal/borer/B in borers)
|
||||
if((B.key || B.controlling) && B.stat != DEAD)
|
||||
borertext += "<br>[B.controlling ? B.victim.key : B.key] was [B.truename] ("
|
||||
var/turf/location = get_turf(B)
|
||||
if(location.z == ZLEVEL_CENTCOM && B.victim)
|
||||
borertext += "escaped with host"
|
||||
else
|
||||
borertext += "failed"
|
||||
borertext += ")"
|
||||
world << borertext
|
||||
|
||||
var/total_borers = 0
|
||||
for(var/mob/living/simple_animal/borer/B in borers)
|
||||
if((B.key || B.victim) && B.stat != DEAD)
|
||||
total_borers++
|
||||
if(total_borers)
|
||||
var/total_borer_hosts = 0
|
||||
for(var/mob/living/carbon/C in mob_list)
|
||||
var/mob/living/simple_animal/borer/D = C.has_brain_worms()
|
||||
var/turf/location = get_turf(C)
|
||||
if(location.z == ZLEVEL_CENTCOM && D && D.stat != DEAD)
|
||||
total_borer_hosts++
|
||||
if(total_borer_hosts_needed <= total_borer_hosts)
|
||||
borerwin = TRUE
|
||||
world << "<b>There were [total_borers] borers alive at round end!</b>"
|
||||
world << "<b>A total of [total_borer_hosts] borers with hosts escaped on the shuttle alive. The borers needed [total_borer_hosts_needed] hosts to escape.</b>"
|
||||
if(borerwin)
|
||||
world << "<b><font color='green'>The borers were successful!</font></b>"
|
||||
else
|
||||
world << "<b><font color='red'>The borers have failed!</font></b>"
|
||||
return TRUE
|
||||
|
||||
mode.declare_station_goal_completion()
|
||||
|
||||
//Adds the del() log to world.log in a format condensable by the runtime condenser found in tools
|
||||
if(SSgarbage.didntgc.len)
|
||||
var/dellog = ""
|
||||
@@ -451,6 +492,8 @@ var/datum/subsystem/ticker/ticker
|
||||
dellog += "Failures : [SSgarbage.didntgc[path]] \n"
|
||||
world.log << dellog
|
||||
|
||||
//Collects persistence features
|
||||
SSpersistence.CollectData()
|
||||
return 1
|
||||
|
||||
/datum/subsystem/ticker/proc/send_tip_of_the_round()
|
||||
@@ -526,11 +569,6 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
minds = ticker.minds
|
||||
|
||||
Bible_icon_state = ticker.Bible_icon_state
|
||||
Bible_item_state = ticker.Bible_item_state
|
||||
Bible_name = ticker.Bible_name
|
||||
Bible_deity_name = ticker.Bible_deity_name
|
||||
|
||||
syndicate_coalition = ticker.syndicate_coalition
|
||||
factions = ticker.factions
|
||||
availablefactions = ticker.availablefactions
|
||||
@@ -551,5 +589,55 @@ var/datum/subsystem/ticker/ticker
|
||||
cinematic = ticker.cinematic
|
||||
maprotatechecked = ticker.maprotatechecked
|
||||
|
||||
/datum/subsystem/ticker/proc/send_gamemode_vote(var/)
|
||||
SSvote.initiate_vote("roundtype","server")
|
||||
|
||||
/datum/subsystem/ticker/proc/send_news_report()
|
||||
var/news_message
|
||||
var/news_source = "Nanotrasen News Network"
|
||||
switch(news_report)
|
||||
if(NUKE_SYNDICATE_BASE)
|
||||
news_message = "In a daring raid, the heroic crew of [station_name()] detonated a nuclear device in the heart of a terrorist base."
|
||||
if(STATION_DESTROYED_NUKE)
|
||||
news_message = "We would like to reassure all employees that the reports of a Syndicate backed nuclear attack on [station_name()] are, in fact, a hoax. Have a secure day!"
|
||||
if(STATION_EVACUATED)
|
||||
news_message = "The crew of [station_name()] has been evacuated amid unconfirmed reports of enemy activity."
|
||||
if(GANG_LOSS)
|
||||
news_message = "Organized crime aboard [station_name()] has been stamped out by members of our ever vigilant security team. Remember to thank your assigned officers today!"
|
||||
if(GANG_TAKEOVER)
|
||||
news_message = "Contact with [station_name()] has been lost after a sophisticated hacking attack by organized criminal elements. Stay vigilant!"
|
||||
if(BLOB_WIN)
|
||||
news_message = "[station_name()] was overcome by an unknown biological outbreak, killing all crew on board. Don't let it happen to you! Remember, a clean work station is a safe work station."
|
||||
if(BLOB_NUKE)
|
||||
news_message = "[station_name()] is currently undergoing decontanimation after a controlled burst of radiation was used to remove a biological ooze. All employees were safely evacuated prior, and are enjoying a relaxing vacation."
|
||||
if(BLOB_DESTROYED)
|
||||
news_message = "[station_name()] is currently undergoing decontamination procedures after the destruction of a biological hazard. As a reminder, any crew members experiencing cramps or bloating should report immediately to security for incineration."
|
||||
if(CULT_ESCAPE)
|
||||
news_message = "Security Alert: A group of religious fanatics have escaped from [station_name()]."
|
||||
if(CULT_FAILURE)
|
||||
news_message = "Following the dismantling of a restricted cult aboard [station_name()], we would like to remind all employees that worship outside of the Chapel is strictly prohibited, and cause for termination."
|
||||
if(CULT_SUMMON)
|
||||
news_message = "Company officials would like to clarify that [station_name()] was scheduled to be decommissioned following meteor damage earlier this year. Earlier reports of an unknowable eldritch horror were made in error."
|
||||
if(NUKE_MISS)
|
||||
news_message = "The Syndicate have bungled a terrorist attack [station_name()], detonating a nuclear weapon in empty space near by."
|
||||
if(OPERATIVES_KILLED)
|
||||
news_message = "Repairs to [station_name()] are underway after an elite Syndicate death squad was wiped out by the crew."
|
||||
if(OPERATIVE_SKIRMISH)
|
||||
news_message = "A skirmish between security forces and Syndicate agents aboard [station_name()] ended with both sides bloodied but intact."
|
||||
if(REVS_WIN)
|
||||
news_message = "Company officials have reassured investors that despite a union led revolt aboard [station_name()] that there will be no wage increases for workers."
|
||||
if(REVS_LOSE)
|
||||
news_message = "[station_name()] quickly put down a misguided attempt at mutiny. Remember, unionizing is illegal!"
|
||||
if(WIZARD_KILLED)
|
||||
news_message = "Tensions have flared with the Wizard's Federation following the death of one of their members aboard [station_name()]."
|
||||
if(STATION_NUKED)
|
||||
news_message = "[station_name()] activated its self destruct device for unknown reasons. Attempts to clone the Captain so he can be arrested and executed are under way."
|
||||
if(CLOCK_SUMMON)
|
||||
news_message = "The garbled messages about hailing a mouse and strange energy readings from [station_name()] have been discovered to be an ill-advised, if thorough, prank by a clown."
|
||||
if(CLOCK_SILICONS)
|
||||
news_message = "The project started by [station_name()] to upgrade their silicon units with advanced equipment have been largely successful, though they have thus far refused to release schematics in a violation of company policy."
|
||||
if(CLOCK_PROSELYTIZATION)
|
||||
news_message = "The burst of energy released near [station_name()] has been confirmed as merely a test of a new weapon. However, due to an unexpected mechanical error, their communications system has been knocked offline."
|
||||
if(SHUTTLE_HIJACK)
|
||||
news_message = "During routine evacuation procedures, the emergency shuttle of [station_name()] had its navigation protocols corrupted and went off course, but was recovered shortly after."
|
||||
|
||||
if(news_message)
|
||||
send2otherserver(news_source, news_message,"News_Report")
|
||||
|
||||
@@ -62,7 +62,7 @@ var/datum/subsystem/timer/SStimer
|
||||
SStimer.hashes -= hash
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
/proc/addtimer(thingToCall, procToCall, wait, unique = FALSE, ...)
|
||||
/proc/addtimer(thingToCall, procToCall, wait, unique = TIMER_NORMAL, ...)
|
||||
if (!thingToCall || !procToCall)
|
||||
return
|
||||
if (!SStimer.can_fire)
|
||||
@@ -75,12 +75,18 @@ var/datum/subsystem/timer/SStimer
|
||||
var/hashlist = args.Copy()
|
||||
|
||||
hashlist[1] = "[thingToCall](\ref[thingToCall])"
|
||||
event.hash = jointext(args, null)
|
||||
if(args.len > 4)
|
||||
event.argList = args.Copy(5)
|
||||
event.hash = jointext(hashlist, null)
|
||||
|
||||
var/bad_args = unique != TIMER_NORMAL && unique != TIMER_UNIQUE
|
||||
if(args.len > 4 || bad_args)
|
||||
if(bad_args)
|
||||
stack_trace("Invalid arguments in call to addtimer! Attempt to call [thingToCall] proc [procToCall]")
|
||||
event.argList = args.Copy(4)
|
||||
else
|
||||
event.argList = args.Copy(5)
|
||||
|
||||
// Check for dupes if unique = 1.
|
||||
if(unique)
|
||||
if(!bad_args && unique != TIMER_NORMAL) //faster than checking if(unique == TIMER_UNIQUE)
|
||||
var/datum/timedevent/hash_event = SStimer.hashes[event.hash]
|
||||
if(hash_event)
|
||||
return hash_event.id
|
||||
|
||||
@@ -58,15 +58,20 @@ var/datum/subsystem/vote/SSvote
|
||||
greatest_votes = votes
|
||||
//default-vote for everyone who didn't vote
|
||||
if(!config.vote_no_default && choices.len)
|
||||
var/non_voters = (clients.len - total_votes)
|
||||
if(non_voters > 0)
|
||||
var/list/non_voters = directory.Copy()
|
||||
non_voters -= voted
|
||||
for (var/non_voter_ckey in non_voters)
|
||||
var/client/C = non_voters[non_voter_ckey]
|
||||
if (!C || C.is_afk())
|
||||
non_voters -= non_voter_ckey
|
||||
if(non_voters.len > 0)
|
||||
if(mode == "restart")
|
||||
choices["Continue Playing"] += non_voters
|
||||
choices["Continue Playing"] += non_voters.len
|
||||
if(choices["Continue Playing"] >= greatest_votes)
|
||||
greatest_votes = choices["Continue Playing"]
|
||||
else if(mode == "gamemode")
|
||||
if(master_mode in choices)
|
||||
choices[master_mode] += non_voters
|
||||
choices[master_mode] += non_voters.len
|
||||
if(choices[master_mode] >= greatest_votes)
|
||||
greatest_votes = choices[master_mode]
|
||||
//get all options with that many votes and return them in a list
|
||||
@@ -121,13 +126,6 @@ var/datum/subsystem/vote/SSvote
|
||||
restart = 1
|
||||
else
|
||||
master_mode = .
|
||||
if("roundtype")
|
||||
if(ticker && ticker.mode)
|
||||
message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
else if(master_mode != .)
|
||||
world.save_mode(.)
|
||||
master_mode = .
|
||||
world << "<span class='adminnotice'><b>The mode is now: [master_mode]</b></span>"
|
||||
if(restart)
|
||||
var/active_admins = 0
|
||||
for(var/client/C in admins)
|
||||
@@ -176,9 +174,6 @@ var/datum/subsystem/vote/SSvote
|
||||
choices.Add("Restart Round","Continue Playing")
|
||||
if("gamemode")
|
||||
choices.Add(config.votable_modes)
|
||||
if("roundtype")
|
||||
choices.Add("secret")
|
||||
choices.Add("extended")
|
||||
if("custom")
|
||||
question = stripped_input(usr,"What is the vote for?")
|
||||
if(!question)
|
||||
|
||||
@@ -29,13 +29,13 @@ var/datum/subsystem/weather/SSweather
|
||||
var/datum/weather/W = pickweight(possible_weather_for_this_z)
|
||||
run_weather(W.name, Z)
|
||||
eligible_zlevels -= Z
|
||||
addtimer(src, "make_z_eligible", rand(3000, 6000) + W.weather_duration_upper, TRUE, Z) //Around 5-10 minutes between weathers
|
||||
addtimer(src, "make_z_eligible", rand(3000, 6000) + W.weather_duration_upper, TIMER_UNIQUE, Z) //Around 5-10 minutes between weathers
|
||||
|
||||
/datum/subsystem/weather/Initialize(start_timeofday)
|
||||
..()
|
||||
for(var/V in subtypesof(/datum/weather))
|
||||
var/datum/weather/W = V
|
||||
existing_weather |= new W
|
||||
new W //weather->New will handle adding itself to the list
|
||||
|
||||
/datum/subsystem/weather/proc/run_weather(weather_name, Z)
|
||||
if(!weather_name)
|
||||
|
||||
Reference in New Issue
Block a user