Merge remote-tracking branch 'Citadel-Station-13/master' into Citadel-Station-13/custom_roundstart_items

This commit is contained in:
kevinz000
2017-07-16 20:30:27 -07:00
1402 changed files with 636727 additions and 311525 deletions
+11 -1
View File
@@ -208,6 +208,8 @@
var/generate_minimaps = 0
var/grey_assistants = 0
var/id_console_jobslot_delay = 30
var/lavaland_budget = 60
var/space_budget = 16
@@ -261,6 +263,8 @@
var/mice_roundstart = 10 // how many wire chewing rodents spawn at roundstart.
var/irc_announce_new_game = FALSE
/datum/configuration/New()
gamemode_cache = typecacheof(/datum/game_mode,TRUE)
for(var/T in gamemode_cache)
@@ -410,6 +414,8 @@
usewhitelist = TRUE
if("allow_metadata")
allow_Metadata = 1
if("id_console_jobslot_delay")
id_console_jobslot_delay = text2num(value)
if("inactivity_period")
inactivity_period = text2num(value) * 10 //documented as seconds in config.txt
if("afk_period")
@@ -424,7 +430,7 @@
popup_admin_pm = 1
if("allow_holidays")
allow_holidays = 1
if("useircbot")
if("useircbot") //tgs2 support
useircbot = 1
if("ticklag")
var/ticklag = text2num(value)
@@ -537,6 +543,8 @@
error_silence_time = text2num(value)
if("error_msg_delay")
error_msg_delay = text2num(value)
if("irc_announce_new_game")
irc_announce_new_game = TRUE
else
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
@@ -828,6 +836,8 @@
if ("endmap")
maplist[currentmap.map_name] = currentmap
currentmap = null
if ("disabled")
currentmap = null
else
GLOB.config_error_log << "Unknown command in map vote config: '[command]'"
+27 -24
View File
@@ -14,15 +14,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe
//GOT IT MEMORIZED?
GLOBAL_VAR_INIT(MC_restart_clear, 0)
GLOBAL_VAR_INIT(MC_restart_timeout, 0)
GLOBAL_VAR_INIT(MC_restart_count, 0)
//current tick limit, assigned by the queue controller before running a subsystem.
//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits
GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
/datum/controller/master
name = "Master"
@@ -59,6 +50,14 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
var/current_runlevel //for scheduling different subsystems for different stages of the round
var/static/restart_clear = 0
var/static/restart_timeout = 0
var/static/restart_count = 0
//current tick limit, assigned before running a subsystem.
//used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
var/static/current_ticklimit = TICK_LIMIT_RUNNING
/datum/controller/master/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
subsystems = list()
@@ -83,20 +82,21 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
sortTim(subsystems, /proc/cmp_subsystem_init)
reverseRange(subsystems)
for(var/datum/controller/subsystem/ss in subsystems)
testing("Shutdown [ss.name] subsystem")
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()
. = -1 //so if we runtime, things know we failed
if (world.time < GLOB.MC_restart_timeout)
if (world.time < Master.restart_timeout)
return 0
if (world.time < GLOB.MC_restart_clear)
GLOB.MC_restart_count *= 0.5
if (world.time < Master.restart_clear)
Master.restart_count *= 0.5
var/delay = 50 * ++GLOB.MC_restart_count
GLOB.MC_restart_timeout = world.time + delay
GLOB.MC_restart_clear = world.time + (delay * 2)
var/delay = 50 * ++Master.restart_count
Master.restart_timeout = world.time + delay
Master.restart_clear = world.time + (delay * 2)
Master.processing = 0 //stop ticking this one
try
new/datum/controller/master()
@@ -139,6 +139,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
if(FireHim)
Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one
subsystems = Master.subsystems
current_runlevel = Master.current_runlevel
StartProcessing(10)
else
to_chat(world, "<span class='boldannounce'>The Master Controller is having some issues, we will need to re-initialize EVERYTHING</span>")
@@ -163,20 +164,21 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
var/start_timeofday = REALTIMEOFDAY
// Initialize subsystems.
GLOB.CURRENT_TICKLIMIT = config.tick_limit_mc_init
current_ticklimit = config.tick_limit_mc_init
for (var/datum/controller/subsystem/SS in subsystems)
if (SS.flags & SS_NO_INIT)
continue
SS.Initialize(REALTIMEOFDAY)
CHECK_TICK
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
var/time = (REALTIMEOFDAY - start_timeofday) / 10
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
to_chat(world, "<span class='boldannounce'>[msg]</span>")
log_world(msg)
SetRunLevel(1)
if (!current_runlevel)
SetRunLevel(1)
// Sort subsystems by display setting for easy access.
sortTim(subsystems, /proc/cmp_subsystem_display)
@@ -204,6 +206,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
set waitfor = 0
if(delay)
sleep(delay)
testing("Master starting processing")
var/rtn = Loop()
if (rtn > 0 || processing < 0)
return //this was suppose to happen.
@@ -274,7 +277,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
while (1)
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
if (processing <= 0)
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
@@ -282,7 +285,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
if (world.tick_usage > TICK_LIMIT_MC)
sleep_delta += 2
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
sleep(world.tick_lag * (processing + sleep_delta))
continue
@@ -320,7 +323,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
if (!error_level)
iteration++
error_level++
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
@@ -332,7 +335,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
if (!error_level)
iteration++
error_level++
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
error_level--
@@ -343,7 +346,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
iteration++
last_run = world.time
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
current_ticklimit = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
sleep(world.tick_lag * (processing + sleep_delta))
@@ -434,7 +437,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
GLOB.CURRENT_TICKLIMIT = round(world.tick_usage + tick_precentage)
current_ticklimit = round(world.tick_usage + tick_precentage)
if (!(queue_node_flags & SS_TICKER))
ran_non_ticker = TRUE
+1 -1
View File
@@ -7,7 +7,7 @@
#define SSAIR_SUPERCONDUCTIVITY 7
SUBSYSTEM_DEF(air)
name = "Air"
name = "Atmospherics"
init_order = INIT_ORDER_AIR
priority = 20
wait = 5
+2 -2
View File
@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(atoms)
else if(!A.initialized)
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
return qdeleted || QDELETED(A)
return qdeleted || QDELING(A)
/datum/controller/subsystem/atoms/proc/map_loader_begin()
old_initialized = initialized
@@ -150,7 +150,7 @@ SUBSYSTEM_DEF(atoms)
/datum/controller/subsystem/atoms/Shutdown()
var/initlog = InitLog()
if(initlog)
text2file("[GLOB.log_directory]/initialize.log", initlog)
text2file(initlog, "[GLOB.log_directory]/initialize.log")
#undef BAD_INIT_QDEL_BEFORE
#undef BAD_INIT_DIDNT_INIT
+44 -19
View File
@@ -1,8 +1,10 @@
SUBSYSTEM_DEF(blackbox)
name = "Blackbox"
wait = 6000
flags = SS_NO_TICK_CHECK
flags = SS_NO_TICK_CHECK | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
init_order = INIT_ORDER_BLACKBOX
var/list/msg_common = list()
var/list/msg_science = list()
var/list/msg_command = list()
@@ -17,6 +19,8 @@ SUBSYSTEM_DEF(blackbox)
var/list/feedback = list() //list of datum/feedback_variable
var/sealed = FALSE //time to stop tracking stats?
//poll population
/datum/controller/subsystem/blackbox/fire()
if(!SSdbcore.Connect())
@@ -26,7 +30,7 @@ SUBSYSTEM_DEF(blackbox)
if(M.client)
playercount += 1
var/admincount = GLOB.admins.len
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON('[world.internet_address]'), '[world.port]')")
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
query_record_playercount.Execute()
/datum/controller/subsystem/blackbox/Recover()
@@ -42,9 +46,10 @@ SUBSYSTEM_DEF(blackbox)
msg_cargo = SSblackbox.msg_cargo
msg_other = SSblackbox.msg_other
feedback = SSblackbox.feedback
sealed = SSblackbox.sealed
//no touchie
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
if(var_name == "feedback")
@@ -55,6 +60,9 @@ SUBSYSTEM_DEF(blackbox)
return FALSE
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len)
var/pda_msg_amt = 0
var/rc_msg_amt = 0
@@ -80,26 +88,21 @@ SUBSYSTEM_DEF(blackbox)
add_details("radio_usage","PDA-[pda_msg_amt]")
add_details("radio_usage","RC-[rc_msg_amt]")
set_details("round_end","[time2text(world.realtime)]") //This one MUST be the last one that gets set.
if (!SSdbcore.Connect())
return
var/sqlrowlist = ""
var/list/sqlrowlist = list()
for (var/datum/feedback_variable/FV in feedback)
if (sqlrowlist != "")
sqlrowlist += ", " //a comma (,) at the start of the first row to insert will trigger a SQL error
sqlrowlist += list(list("time" = "Now()", "round_id" = GLOB.round_id, "var_name" = "'[sanitizeSQL(FV.get_variable())]'", "var_value" = FV.get_value(), "details" = "'[sanitizeSQL(FV.get_details())]'"))
if (sqlrowlist == "")
if (!length(sqlrowlist))
return
var/datum/DBQuery/query_feedback_save = SSdbcore.NewQuery("INSERT DELAYED IGNORE INTO [format_table_name("feedback")] VALUES " + sqlrowlist)
query_feedback_save.Execute()
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
if(sealed)
return
switch(freq)
if(1459)
msg_common += blackbox_msg
@@ -134,26 +137,38 @@ SUBSYSTEM_DEF(blackbox)
return FV
/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_value(value)
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.inc(value)
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.dec(value)
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_details(details)
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.add_details(details)
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
if(sealed)
return
if(!SSdbcore.Connect())
return
if(!L || !L.key || !L.mind)
@@ -171,19 +186,29 @@ SUBSYSTEM_DEF(blackbox)
var/mob/LA = L.lastattacker
laname = sanitizeSQL(LA.real_name)
lakey = sanitizeSQL(LA.key)
var/sqlgender = sanitizeSQL(L.gender)
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
var/sqlfire = sanitizeSQL(L.getFireLoss())
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
var/sqloxy = sanitizeSQL(L.getOxyLoss())
var/sqltox = sanitizeSQL(L.getStaminaLoss())
var/sqlclone = sanitizeSQL(L.getStaminaLoss())
var/sqltox = sanitizeSQL(L.getToxLoss())
var/sqlclone = sanitizeSQL(L.getCloneLoss())
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
var/coord = sanitizeSQL("[L.x], [L.y], [L.z]")
var/x_coord = sanitizeSQL(L.x)
var/y_coord = sanitizeSQL(L.y)
var/z_coord = sanitizeSQL(L.z)
var/map = sanitizeSQL(SSmapping.config.map_name)
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, coord, mapname, server_ip, server_port) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[SQLtime()]', '[laname]', '[lakey]', '[sqlgender]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[coord]', '[map]', INET_ATON('[world.internet_address]'), '[world.port]')")
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina])")
query_report_death.Execute()
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
return
if(IsAdminAdvancedProcCall())
var/msg = "[key_name_admin(usr)] sealed the blackbox!"
message_admins(msg)
log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
sealed = TRUE
//feedback variable datum, for storing all kinds of data
/datum/feedback_variable
+19 -13
View File
@@ -1,7 +1,7 @@
SUBSYSTEM_DEF(dbcore)
name = "Database"
flags = SS_NO_INIT|SS_NO_FIRE
init_order = INIT_ORDER_DBCORE
var/const/FAILED_DB_CONNECTION_CUTOFF = 5
var/const/Default_Cursor = 0
@@ -23,12 +23,18 @@ SUBSYSTEM_DEF(dbcore)
var/failed_connections = 0
/datum/controller/subsystem/dbcore/PreInit()
_db_con = _dm_db_new_con()
if(!_db_con)
_db_con = _dm_db_new_con()
/datum/controller/subsystem/dbcore/Recover()
_db_con = SSdbcore._db_con
/datum/controller/subsystem/dbcore/Shutdown()
//This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem
if(SSdbcore.Connect())
var/sql_station_name = sanitizeSQL(station_name())
var/datum/DBQuery/query_round_end = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET end_datetime = Now(), game_mode_result = '[SSticker.mode_result]', end_state = '[SSticker.end_state]', station_name = '[sql_station_name]' WHERE id = [GLOB.round_id]")
query_round_end.Execute()
if(IsConnected())
Disconnect()
@@ -47,7 +53,7 @@ SUBSYSTEM_DEF(dbcore)
if(failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect anymore.
return FALSE
if(!config.sql_enabled)
return FALSE
@@ -170,16 +176,16 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
var/_db_query
/datum/DBQuery/New(sql_query, datum/controller/subsystem/dbcore/connection_handler, cursor_handler)
if(sql_query)
if(sql_query)
sql = sql_query
if(connection_handler)
if(connection_handler)
db_connection = connection_handler
if(cursor_handler)
if(cursor_handler)
default_cursor = cursor_handler
item = list()
_db_query = _dm_db_new_query()
/datum/DBQuery/proc/Connect(datum/controller/subsystem/dbcore/connection_handler)
/datum/DBQuery/proc/Connect(datum/controller/subsystem/dbcore/connection_handler)
db_connection = connection_handler
/datum/DBQuery/proc/warn_execute()
@@ -193,16 +199,16 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
if(!. && log_error)
log_sql("[ErrorMsg()] | Query used: [sql]")
/datum/DBQuery/proc/NextRow()
/datum/DBQuery/proc/NextRow()
return _dm_db_next_row(_db_query,item,conversions)
/datum/DBQuery/proc/RowsAffected()
return _dm_db_rows_affected(_db_query)
/datum/DBQuery/proc/RowCount()
/datum/DBQuery/proc/RowCount()
return _dm_db_row_count(_db_query)
/datum/DBQuery/proc/ErrorMsg()
/datum/DBQuery/proc/ErrorMsg()
return _dm_db_error_msg(_db_query)
/datum/DBQuery/proc/Columns()
@@ -231,11 +237,11 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
return db_connection.Quote(str)
/datum/DBQuery/proc/SetConversion(column,conversion)
if(istext(column))
if(istext(column))
column = columns.Find(column)
if(!conversions)
if(!conversions)
conversions = list(column)
else if(conversions.len < column)
else if(conversions.len < column)
conversions.len = column
conversions[column] = conversion
+1 -1
View File
@@ -105,7 +105,7 @@ SUBSYSTEM_DEF(events)
//These are needed because /area/engine has to be removed from the list, but we still want these areas to get fucked up.
var/list/danger_areas = list(
/area/engine/break_room,
/area/engine/chiefs_office)
/area/crew_quarters/heads/chief)
//Need to locate() as it's just a list of paths.
return locate(pick((GLOB.the_station_areas - safe_areas) + danger_areas))
+510
View File
@@ -0,0 +1,510 @@
SUBSYSTEM_DEF(explosion)
priority = 99
wait = 1
flags = SS_TICKER|SS_NO_INIT
var/list/explosions
var/rebuild_tick_split_count = FALSE
var/tick_portions_required = 0
var/list/logs
var/list/zlevels_that_ignore_bombcap
var/list/doppler_arrays
//legacy caps, set by config
var/devastation_cap = 3
var/heavy_cap = 7
var/light_cap = 14
var/flash_cap = 14
var/flame_cap = 14
var/dyn_ex_scale = 0.5
var/id_counter = 0
/datum/controller/subsystem/explosion/PreInit()
doppler_arrays = list()
logs = list()
explosions = list()
zlevels_that_ignore_bombcap = list("[ZLEVEL_MINING]")
/datum/controller/subsystem/explosion/Shutdown()
QDEL_LIST(explosions)
QDEL_LIST(logs)
zlevels_that_ignore_bombcap.Cut()
/datum/controller/subsystem/explosion/Recover()
explosions = SSexplosion.explosions
logs = SSexplosion.logs
id_counter = SSexplosion.id_counter
rebuild_tick_split_count = TRUE
zlevels_that_ignore_bombcap = SSexplosion.zlevels_that_ignore_bombcap
doppler_arrays = SSexplosion.doppler_arrays
devastation_cap = SSexplosion.devastation_cap
heavy_cap = SSexplosion.heavy_cap
light_cap = SSexplosion.light_cap
flash_cap = SSexplosion.flash_cap
flame_cap = SSexplosion.flame_cap
dyn_ex_scale = SSexplosion.dyn_ex_scale
/datum/controller/subsystem/explosion/fire()
var/list/cached_explosions = explosions
var/num_explosions = cached_explosions.len
if(!num_explosions)
return
//figure exactly how many tick splits are required
var/num_splits
if(rebuild_tick_split_count)
var/reactionary = config.reactionary_explosions
num_splits = num_explosions
for(var/I in cached_explosions)
var/datum/explosion/E = I
if(!E.turfs_processed)
++num_splits
if(reactionary && !E.densities_processed)
++num_splits
tick_portions_required = num_splits
else
num_splits = tick_portions_required
MC_SPLIT_TICK_INIT(num_splits)
for(var/I in cached_explosions)
var/datum/explosion/E = I
var/etp = E.turfs_processed
if(!etp)
if(GatherTurfs(E))
--tick_portions_required
etp = TRUE
MC_SPLIT_TICK
var/edp = E.densities_processed
if(!edp)
if(DensityCalculate(E, etp))
--tick_portions_required
edp = TRUE
MC_SPLIT_TICK
if(ProcessExplosion(E, edp)) //splits the tick
--tick_portions_required
explosions -= E
logs += E
NotifyDopplers(E)
MC_SPLIT_TICK
/datum/controller/subsystem/explosion/proc/NotifyDopplers(datum/explosion/E)
for(var/array in doppler_arrays)
var/obj/machinery/doppler_array/A = array
A.sense_explosion(E.epicenter, E.devastation, E.heavy, E.light, E.finished_at - E.started_at, E.orig_dev_range, E.orig_heavy_range, E.orig_light_range)
/datum/controller/subsystem/explosion/proc/Create(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0 , silent = FALSE, smoke = FALSE)
epicenter = get_turf(epicenter)
if(!epicenter)
return
if(adminlog)
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area: [get_area(epicenter)] [ADMIN_COORDJMP(epicenter)]")
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z])")
var/datum/explosion/E = new(++id_counter, epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range, silent, smoke, ignorecap)
if(heavy_impact_range > 1)
var/datum/effect_system/explosion/Eff
if(smoke)
Eff = new /datum/effect_system/explosion/smoke
else
Eff = new
Eff.set_up(epicenter)
Eff.start()
//flash mobs
if(flash_range)
for(var/mob/living/L in viewers(flash_range, epicenter))
L.flash_act()
if(!silent)
ExplosionSound(epicenter, devastation_range, heavy_impact_range, E.extent)
//add to SS
if(E.extent)
tick_portions_required += 2 + (config.reactionary_explosions ? 1 : 0)
explosions += E
else
logs += E //Already done processing
/datum/controller/subsystem/explosion/proc/CreateDynamic(atom/epicenter, power, flash_range, adminlog = TRUE, ignorecap = TRUE, flame_range = 0 , silent = FALSE, smoke = TRUE)
if(!power)
return
var/range = round((2 * power) ** dyn_ex_scale)
Create(epicenter, round(range * 0.25), round(range * 0.5), round(range), flash_range*range, adminlog, ignorecap, flame_range*range, silent, smoke)
// Using default dyn_ex scale:
// 100 explosion power is a (5, 10, 20) explosion.
// 75 explosion power is a (4, 8, 17) explosion.
// 50 explosion power is a (3, 7, 14) explosion.
// 25 explosion power is a (2, 5, 10) explosion.
// 10 explosion power is a (1, 3, 6) explosion.
// 5 explosion power is a (0, 1, 3) explosion.
// 1 explosion power is a (0, 0, 1) explosion.
/datum/explosion
var/explosion_id
var/turf/epicenter
var/started_at
var/finished_at
var/tick_started
var/tick_finished
var/turfs_processed = FALSE
var/densities_processed = FALSE
var/orig_dev_range
var/orig_heavy_range
var/orig_light_range
var/orig_flash_range
var/orig_flame_range
var/devastation
var/heavy
var/light
var/extent
var/flash
var/flame
var/gather_dist = 0
var/list/gathered_turfs
var/list/calculated_turfs
var/list/unsafe_turfs
/datum/explosion/New(id, turf/epi, devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range, silent, smoke, ignorecap)
explosion_id = id
epicenter = epi
densities_processed = !config.reactionary_explosions
orig_dev_range = devastation_range
orig_heavy_range = heavy_impact_range
orig_light_range = light_impact_range
orig_flash_range = flash_range
orig_flame_range = flame_range
if(!ignorecap && !("[epicenter.z]" in SSexplosion.zlevels_that_ignore_bombcap))
//Clamp all values
devastation_range = min(SSexplosion.devastation_cap, devastation_range)
heavy_impact_range = min(SSexplosion.heavy_cap, heavy_impact_range)
light_impact_range = min(SSexplosion.light_cap, light_impact_range)
flash_range = min(SSexplosion.flash_cap, flash_range)
flame_range = min(SSexplosion.flame_cap, flame_range)
//store this
devastation = devastation_range
heavy = heavy_impact_range
light = light_impact_range
extent = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
flash = flash_range
flame = flame_range
started_at = REALTIMEOFDAY
tick_started = world.time
gathered_turfs = list()
calculated_turfs = list()
unsafe_turfs = list()
// Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves.
// Stereo users will also hear the direction of the explosion!
// Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions.
// 3/7/14 will calculate to 80 + 35
/proc/ExplosionSound(turf/epicenter, devastation_range, heavy_impact_range, extent)
var/far_dist = 0
far_dist += heavy_impact_range * 5
far_dist += devastation_range * 20
var/z0 = epicenter.z
var/frequency = get_rand_frequency()
var/ex_sound = get_sfx("explosion")
for(var/mob/M in GLOB.player_list)
// Double check for client
var/turf/M_turf = get_turf(M)
if(M_turf && M_turf.z == z0)
var/dist = get_dist(M_turf, epicenter)
// If inside the blast radius + world.view - 2
if(dist <= round(extent + world.view - 2, 1))
M.playsound_local(epicenter, ex_sound, 100, 1, frequency, falloff = 5)
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
/datum/explosion/Destroy()
SSexplosion.explosions -= src
SSexplosion.logs -= src
LAZYCLEARLIST(gathered_turfs)
LAZYCLEARLIST(calculated_turfs)
LAZYCLEARLIST(unsafe_turfs)
return ..()
/datum/controller/subsystem/explosion/proc/GatherTurfs(datum/explosion/E)
var/turf/epicenter = E.epicenter
var/x0 = epicenter.x
var/y0 = epicenter.y
var/z0 = epicenter.z
var/c_dist = E.gather_dist
var/dist = E.extent
var/list/L = E.gathered_turfs
if(!c_dist)
L += epicenter
++c_dist
while( c_dist <= dist )
var/y = y0 + c_dist
var/x = x0 - c_dist + 1
for(x in x to x0 + c_dist)
var/turf/T = locate(x, y, z0)
if(T)
L += T
y = y0 + c_dist - 1
x = x0 + c_dist
for(y in y0 - c_dist to y)
var/turf/T = locate(x, y, z0)
if(T)
L += T
y = y0 - c_dist
x = x0 + c_dist - 1
for(x in x0 - c_dist to x)
var/turf/T = locate(x, y, z0)
if(T)
L += T
y = y0 - c_dist + 1
x = x0 - c_dist
for(y in y to y0 + c_dist)
var/turf/T = locate(x, y, z0)
if(T)
L += T
++c_dist
if(MC_TICK_CHECK)
break
if(c_dist > dist)
E.turfs_processed = TRUE
return TRUE
else
E.gather_dist = c_dist
return FALSE
/datum/controller/subsystem/explosion/proc/DensityCalculate(datum/explosion/E, done_gathering_turfs)
var/list/L = E.calculated_turfs
var/cut_to = 1
for(var/I in E.gathered_turfs) // we cache the explosion block rating of every turf in the explosion area
var/turf/T = I
++cut_to
var/current_exp_block = T.density ? T.explosion_block : 0
for(var/obj/machinery/door/D in T)
if(D.density)
current_exp_block += D.explosion_block
for(var/obj/structure/window/W in T)
if(W.reinf && W.fulltile)
current_exp_block += W.explosion_block
for(var/obj/structure/blob/B in T)
current_exp_block += B.explosion_block
L[T] = current_exp_block
if(MC_TICK_CHECK)
E.gathered_turfs.Cut(1, cut_to)
return FALSE
E.gathered_turfs.Cut()
return done_gathering_turfs
/datum/controller/subsystem/explosion/proc/ProcessExplosion(datum/explosion/E, done_calculating_turfs)
//cache shit for speed
var/id = E.explosion_id
var/list/cached_unsafe = E.unsafe_turfs
var/list/cached_exp_block = E.calculated_turfs
var/list/affected_turfs = cached_exp_block ? cached_exp_block : E.gathered_turfs
var/devastation_range = E.devastation
var/heavy_impact_range = E.heavy
var/light_impact_range = E.light
var/flame_range = E.flame
var/throw_range_max = E.extent
var/turf/epi = E.epicenter
var/x0 = epi.x
var/y0 = epi.y
var/cut_to = 1
for(var/TI in affected_turfs)
var/turf/T = TI
++cut_to
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
var/dist = init_dist
if(cached_exp_block)
var/turf/Trajectory = T
while(Trajectory != epi)
Trajectory = get_step_towards(Trajectory, epi)
dist += cached_exp_block[Trajectory]
var/flame_dist = dist < flame_range
var/throw_dist = dist
if(dist < devastation_range)
dist = 1
else if(dist < heavy_impact_range)
dist = 2
else if(dist < light_impact_range)
dist = 3
else
dist = 0
//------- EX_ACT AND TURF FIRES -------
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
new /obj/effect/hotspot(T) //Mostly for ambience!
if(dist > 0)
T.explosion_level = max(T.explosion_level, dist) //let the bigger one have it
T.explosion_id = id
T.ex_act(dist)
cached_unsafe += T
//--- THROW ITEMS AROUND ---
var/throw_dir = get_dir(epi, T)
for(var/obj/item/I in T)
if(!I.anchored)
var/throw_range = rand(throw_dist, throw_range_max)
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Resets when it finishes throwing, regardless of hitting anything)
I.throw_at(throw_at, throw_range, 4)
if(MC_TICK_CHECK)
var/circumference = (PI * (init_dist + 4) * 2) //+4 to radius to prevent shit gaps
if(cached_unsafe.len > circumference) //only do this every revolution
for(var/Unexplode in cached_unsafe)
var/turf/UnexplodeT = Unexplode
UnexplodeT.explosion_level = 0
cached_unsafe.Cut()
done_calculating_turfs = FALSE
break
affected_turfs.Cut(1, cut_to)
if(!done_calculating_turfs)
return FALSE
//unfuck the shit
for(var/Unexplode in cached_unsafe)
var/turf/UnexplodeT = Unexplode
UnexplodeT.explosion_level = 0
cached_unsafe.Cut()
E.finished_at = REALTIMEOFDAY
E.tick_finished = world.time
return TRUE
/client/proc/check_bomb_impacts()
set name = "Check Bomb Impact"
set category = "Debug"
var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No")
var/turf/epicenter = get_turf(mob)
if(!epicenter)
return
var/x0 = epicenter.x
var/y0 = epicenter.y
var/dev = 0
var/heavy = 0
var/light = 0
var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb")
var/choice = input("Bomb Size?") in choices
switch(choice)
if(null)
return 0
if("Small Bomb")
dev = 1
heavy = 2
light = 3
if("Medium Bomb")
dev = 2
heavy = 3
light = 4
if("Big Bomb")
dev = 3
heavy = 5
light = 7
if("Custom Bomb")
dev = input("Devestation range (Tiles):") as num
heavy = input("Heavy impact range (Tiles):") as num
light = input("Light impact range (Tiles):") as num
else
return
var/datum/explosion/E = new(null, epicenter, dev, heavy, light, ignorecap = TRUE)
while(!SSexplosion.GatherTurfs(E))
stoplag()
var/list/turfs
if(newmode)
while(!SSexplosion.DensityCalculate(E, TRUE))
stoplag()
turfs = E.calculated_turfs.Copy()
else
turfs = E.gathered_turfs.Copy()
qdel(E)
for(var/I in turfs)
var/turf/T = I
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0) + turfs[T]
if(dist < dev)
T.color = "red"
T.maptext = "Dev"
else if (dist < heavy)
T.color = "yellow"
T.maptext = "Heavy"
else if (dist < light)
T.color = "blue"
T.maptext = "Light"
CHECK_TICK
sleep(100)
for(var/I in turfs)
var/turf/T = I
T.color = null
T.maptext = null
-27
View File
@@ -1,27 +0,0 @@
SUBSYSTEM_DEF(fields)
name = "Fields"
wait = 2
priority = 40
flags = SS_KEEP_TIMING
var/list/datum/proximity_monitor/advanced/running = list()
var/list/datum/proximity_monitor/advanced/currentrun = list()
/datum/controller/subsystem/fields/fire(resumed = 0)
if(!resumed)
src.currentrun = running.Copy()
var/list/currentrun = src.currentrun
while(currentrun.len)
var/datum/proximity_monitor/advanced/F = currentrun[currentrun.len]
currentrun.len--
if(!F.requires_processing)
continue
F.process()
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/fields/proc/register_new_field(datum/proximity_monitor/advanced/F)
running += F
/datum/controller/subsystem/fields/proc/unregister_field(datum/proximity_monitor/advanced/F)
running -= F
+3 -3
View File
@@ -61,7 +61,7 @@ SUBSYSTEM_DEF(garbage)
for(var/path in sleptDestroy)
dellog += "Path : [path] \n"
dellog += "Sleeps : [sleptDestroy[path]] \n"
text2file("[GLOB.log_directory]/qdel.log", dellog.Join())
text2file(dellog.Join(), "[GLOB.log_directory]/qdel.log")
/datum/controller/subsystem/garbage/fire()
HandleToBeQueued()
@@ -164,8 +164,8 @@ SUBSYSTEM_DEF(garbage)
if (time > highest_del_time)
highest_del_time = time
if (time > 10)
log_game("Error: [type]([refID]) took longer then 1 second to delete (took [time/10] seconds to delete)")
message_admins("Error: [type]([refID]) took longer then 1 second to delete (took [time/10] seconds to delete).")
log_game("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete)")
message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).")
postpone(time/5)
/datum/controller/subsystem/garbage/proc/HardQueue(datum/A)
+49 -18
View File
@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(job)
var/initial_players_to_assign = 0 //used for checking against population caps
var/list/prioritized_jobs = list()
var/list/latejoin_trackers = list() //Don't read this list, use GetLateJoinTurfs() instead
/datum/controller/subsystem/job/Initialize(timeofday)
if(!occupations.len)
@@ -223,7 +224,7 @@ SUBSYSTEM_DEF(job)
//Get the players who are ready
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready && player.mind && !player.mind.assigned_role)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)
unassigned += player
initial_players_to_assign = unassigned.len
@@ -378,23 +379,11 @@ SUBSYSTEM_DEF(job)
continue
S = sloc
break
if(S)
SendToAtom(H, S, buckle = FALSE)
if(!S) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper
log_world("Couldn't find a round start spawn point for [rank]")
S = get_turf(pick(GLOB.latejoin))
if(!S) //final attempt, lets find some area in the arrivals shuttle to spawn them in to.
log_world("Couldn't find a round start latejoin spawn point.")
for(var/turf/T in get_area_turfs(/area/shuttle/arrival))
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
S = T
continue
if(istype(S, /obj/effect/landmark) && isturf(S.loc))
H.loc = S.loc
SendToLateJoin(H)
if(H.mind)
H.mind.assigned_role = rank
@@ -466,7 +455,7 @@ SUBSYSTEM_DEF(job)
var/level5 = 0 //banned
var/level6 = 0 //account too young
for(var/mob/dead/new_player/player in GLOB.player_list)
if(!(player.ready && player.mind && !player.mind.assigned_role))
if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role))
continue //This player is not ready
if(jobban_isbanned(player, job.title))
level5++
@@ -499,7 +488,7 @@ SUBSYSTEM_DEF(job)
Debug("Popcap overflow Check observer located, Player: [player]")
to_chat(player, "<b>You have failed to qualify for any job you desired.</b>")
unassigned -= player
player.ready = 0
player.ready = PLAYER_NOT_READY
/datum/controller/subsystem/job/Recover()
@@ -516,3 +505,45 @@ SUBSYSTEM_DEF(job)
newjob.total_positions = J.total_positions
newjob.spawn_positions = J.spawn_positions
newjob.current_positions = J.current_positions
/datum/controller/subsystem/job/proc/SendToAtom(mob/M, atom/A, buckle)
if(buckle && isliving(M) && istype(A, /obj/structure/chair))
var/obj/structure/chair/C = A
if(C.buckle_mob(M, FALSE, FALSE))
return
M.forceMove(get_turf(A))
/datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE)
if(latejoin_trackers.len)
SendToAtom(M, pick(latejoin_trackers), buckle)
else
//bad mojo
var/area/shuttle/arrival/A = locate() in GLOB.sortedAreas
if(A)
//first check if we can find a chair
var/obj/structure/chair/C = locate() in A
if(C)
SendToAtom(M, C, buckle)
return
else //last hurrah
var/list/avail = list()
for(var/turf/T in A)
if(!is_blocked_turf(T, TRUE))
avail += T
if(avail.len)
SendToAtom(M, pick(avail), FALSE)
return
//pick an open spot on arrivals and dump em
var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival))
if(arrivals_turfs.len)
for(var/turf/T in arrivals_turfs)
if(!is_blocked_turf(T, TRUE))
SendToAtom(M, T, FALSE)
return
//last chance, pick ANY spot on arrivals and dump em
SendToAtom(M, arrivals_turfs[1], FALSE)
else
var/msg = "Unable to send mob [M] to late join!"
message_admins(msg)
CRASH(msg)
+8 -7
View File
@@ -15,14 +15,15 @@ SUBSYSTEM_DEF(lighting)
/datum/controller/subsystem/lighting/Initialize(timeofday)
if (config.starlight)
for(var/I in GLOB.sortedAreas)
var/area/A = I
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
A.luminosity = 0
if(!initialized)
if (config.starlight)
for(var/I in GLOB.sortedAreas)
var/area/A = I
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
A.luminosity = 0
create_all_lighting_objects()
initialized = TRUE
create_all_lighting_objects()
initialized = TRUE
fire(FALSE, TRUE)
+3 -3
View File
@@ -37,11 +37,11 @@ SUBSYSTEM_DEF(machines)
var/seconds = wait * 0.1
while(currentrun.len)
var/datum/thing = currentrun[currentrun.len]
var/obj/machinery/thing = currentrun[currentrun.len]
currentrun.len--
if(thing && thing.process(seconds) != PROCESS_KILL)
if(thing:use_power)
thing:auto_use_power() //add back the power state
if(thing.use_power)
thing.auto_use_power() //add back the power state
else
processing -= thing
if (thing)
+8 -6
View File
@@ -43,14 +43,14 @@ SUBSYSTEM_DEF(mapping)
loading_ruins = TRUE
var/mining_type = config.minetype
if (mining_type == "lavaland")
seedRuins(list(5), global.config.lavaland_budget, /area/lavaland/surface/outdoors, lava_ruins_templates)
seedRuins(list(ZLEVEL_LAVALAND), global.config.lavaland_budget, /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
spawn_rivers()
// deep space ruins
var/space_zlevels = list()
for(var/i in ZLEVEL_SPACEMIN to ZLEVEL_SPACEMAX)
switch(i)
if(ZLEVEL_MINING, ZLEVEL_LAVALAND, ZLEVEL_EMPTY_SPACE)
if(ZLEVEL_MINING, ZLEVEL_LAVALAND, ZLEVEL_EMPTY_SPACE, ZLEVEL_TRANSIT)
continue
else
space_zlevels += i
@@ -113,13 +113,15 @@ SUBSYSTEM_DEF(mapping)
/datum/controller/subsystem/mapping/proc/loadWorld()
//if any of these fail, something has gone horribly, HORRIBLY, wrong
var/list/FailedZs = list()
var/start_time = REALTIMEOFDAY
INIT_ANNOUNCE("Loading [config.map_name]...")
TryLoadZ(config.GetFullMapPath(), FailedZs, ZLEVEL_STATION)
INIT_ANNOUNCE("Loaded station in [(REALTIMEOFDAY - start_time)/10]s!")
SSblackbox.add_details("map_name", config.map_name)
if(SSdbcore.Connect())
var/datum/DBQuery/query_round_map_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET map_name = '[config.map_name]' WHERE id = [GLOB.round_id]")
query_round_map_name.Execute()
if(config.minetype != "lavaland")
INIT_ANNOUNCE("WARNING: A map without lavaland set as it's minetype was loaded! This is being ignored! Update the maploader code!")
@@ -130,7 +132,7 @@ SUBSYSTEM_DEF(mapping)
var/msg = "RED ALERT! The following map files failed to load: [FailedZs[1]]"
if(FailedZs.len > 1)
for(var/I in 2 to FailedZs.len)
msg += ", [I]"
msg += ", [FailedZs[I]]"
msg += ". Yell at your server host!"
INIT_ANNOUNCE(msg)
#undef INIT_ANNOUNCE
@@ -0,0 +1,6 @@
PROCESSING_SUBSYSTEM_DEF(fields)
name = "Fields"
wait = 2
priority = 40
flags = SS_KEEP_TIMING | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
@@ -27,11 +27,12 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
processing = SSoverlays.processing
/datum/controller/subsystem/processing/overlays/fire(resumed = FALSE, mc_check = TRUE)
var/list/processing = src.processing
while(processing.len)
var/atom/thing = processing[processing.len]
processing.len--
if(thing)
thing.compile_overlays(FALSE)
thing.compile_overlays()
if(mc_check)
if(MC_TICK_CHECK)
break
@@ -161,7 +162,7 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
if(NOT_QUEUED_ALREADY && need_compile) //have we caught more pokemon?
QUEUE_FOR_COMPILE
/atom/proc/copy_overlays(atom/other, cut_old = FALSE) //copys our_overlays from another atom
/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
if(!other)
if(cut_old)
cut_overlays()
@@ -190,3 +191,18 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
/image/proc/cut_overlays(x)
overlays.Cut()
/image/proc/copy_overlays(atom/other, cut_old)
if(!other)
if(cut_old)
cut_overlays()
return
var/list/cached_other = other.our_overlays
if(cached_other)
if(cut_old || !overlays.len)
overlays = cached_other.Copy()
else
overlays |= cached_other
else if(cut_old)
cut_overlays()
@@ -22,9 +22,7 @@ SUBSYSTEM_DEF(processing)
while(current_run.len)
var/datum/thing = current_run[current_run.len]
current_run.len--
if(thing)
thing.process(wait)
else
if(QDELETED(thing) || thing.process(wait) == PROCESS_KILL)
processing -= thing
if (MC_TICK_CHECK)
return
@@ -33,4 +31,4 @@ SUBSYSTEM_DEF(processing)
/datum/proc/process()
set waitfor = 0
STOP_PROCESSING(SSobj, src)
return 0
return 0
+10 -2
View File
@@ -5,6 +5,7 @@ SUBSYSTEM_DEF(server_maint)
wait = 6
flags = SS_POST_FIRE_TIMING
priority = 10
init_order = INIT_ORDER_SERVER_MAINT
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/list/currentrun
@@ -16,7 +17,7 @@ SUBSYSTEM_DEF(server_maint)
/datum/controller/subsystem/server_maint/fire(resumed = FALSE)
if(!resumed)
src.currentrun = GLOB.clients.Copy()
var/list/currentrun = src.currentrun
var/round_started = SSticker.HasRoundStarted()
@@ -37,4 +38,11 @@ SUBSYSTEM_DEF(server_maint)
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
return
#undef PING_BUFFER_TIME
/datum/controller/subsystem/server_maint/Shutdown()
kick_clients_in_lobby("<span class='boldannounce'>The round came to an end with you in the lobby.</span>", TRUE) //second parameter ensures only afk clients are kicked
for(var/thing in GLOB.clients)
var/client/C = thing
if(C && config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
C << link("byond://[config.server]")
#undef PING_BUFFER_TIME
+40 -14
View File
@@ -1,4 +1,5 @@
#define HIGHLIGHT_DYNAMIC_TRANSIT 1
#define MAX_TRANSIT_REQUEST_RETRIES 10
SUBSYSTEM_DEF(shuttle)
name = "Shuttle"
@@ -13,6 +14,7 @@ SUBSYSTEM_DEF(shuttle)
var/list/turf/transit_turfs = list()
var/list/transit_requesters = list()
var/list/transit_request_failures = list()
var/clear_transit = FALSE
//emergency shuttle stuff
@@ -25,6 +27,7 @@ SUBSYSTEM_DEF(shuttle)
var/area/emergencyLastCallLoc
var/emergencyCallAmount = 0 //how many times the escape shuttle was called
var/emergencyNoEscape
var/emergencyNoRecall = FALSE
var/list/hostileEnvironments = list()
//supply shuttle stuff
@@ -46,7 +49,7 @@ SUBSYSTEM_DEF(shuttle)
var/lockdown = FALSE //disallow transit after nuke goes off
var/auto_call = 72000 //time before in deciseconds in which the shuttle is auto called. Default is 2 hours.
var/auto_call = 99000 //time before in deciseconds in which the shuttle is auto called. Default is 2½ hours plus 15 for the shuttle. So total is 3.
/datum/controller/subsystem/shuttle/Initialize(timeofday)
if(!arrivals)
@@ -74,12 +77,9 @@ SUBSYSTEM_DEF(shuttle)
..()
/datum/controller/subsystem/shuttle/proc/setup_transit_zone()
if(GLOB.transit_markers.len == 0)
WARNING("No /obj/effect/landmark/transit placed on the map!")
return
// transit zone
var/turf/A = get_turf(GLOB.transit_markers[1])
var/turf/B = get_turf(GLOB.transit_markers[2])
var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,ZLEVEL_TRANSIT))
var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,ZLEVEL_TRANSIT))
for(var/i in block(A, B))
var/turf/T = i
T.ChangeTurf(/turf/open/space)
@@ -88,11 +88,8 @@ SUBSYSTEM_DEF(shuttle)
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
/datum/controller/subsystem/shuttle/proc/color_space()
if(GLOB.transit_markers.len == 0)
WARNING("No /obj/effect/landmark/transit placed on the map!")
return
var/turf/A = get_turf(GLOB.transit_markers[1])
var/turf/B = get_turf(GLOB.transit_markers[2])
var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,ZLEVEL_TRANSIT))
var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,ZLEVEL_TRANSIT))
for(var/i in block(A, B))
var/turf/T = i
// Only dying the "pure" space, not the transit tiles
@@ -146,7 +143,12 @@ SUBSYSTEM_DEF(shuttle)
var/requester = popleft(transit_requesters)
var/success = generate_transit_dock(requester)
if(!success) // BACK OF THE QUEUE
transit_requesters += requester
transit_request_failures[requester]++
if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES)
transit_requesters += requester
else
var/obj/docking_port/mobile/M = requester
M.transit_failure()
if(MC_TICK_CHECK)
return
@@ -217,7 +219,27 @@ SUBSYSTEM_DEF(shuttle)
emergency.request(null, signal_origin, html_decode(emergency_reason), 0)
log_game("[key_name(user)] has called the shuttle.")
message_admins("[key_name_admin(user)] has called the shuttle.")
message_admins("[key_name_admin(user)] has called the shuttle. (<A HREF='?_src_=holder;trigger_centcom_recall=1'>TRIGGER CENTCOM RECALL</A>)")
/datum/controller/subsystem/shuttle/proc/centcom_recall(old_timer, admiral_message)
if(emergency.mode != SHUTTLE_CALL || emergency.timer != old_timer)
return
emergency.cancel()
if(!admiral_message)
admiral_message = pick(GLOB.admiral_messages)
var/intercepttext = "<font size = 3><b>NanoTrasen Update</b>: Request For Shuttle.</font><hr>\
To whom it may concern:<br><br>\
We have taken note of the situation upon [station_name()] and have come to the \
conclusion that it does not warrant the abandonment of the station.<br>\
If you do not agree with our opinion we suggest that you open a direct \
line with us and explain the nature of your crisis.<br><br>\
<i>This message has been automatically generated based upon readings from long \
range diagnostic tools. To assure the quality of your request every finalized report \
is reviewed by an on-call rear admiral.<br>\
<b>Rear Admiral's Notes:</b> \
[admiral_message]"
print_command_report(intercepttext, announce = TRUE)
// Called when an emergency shuttle mobile docking port is
// destroyed, which will only happen with admin intervention
@@ -523,4 +545,8 @@ SUBSYSTEM_DEF(shuttle)
for(var/obj/docking_port/mobile/M in mobile)
if(M.is_in_shuttle_bounds(A))
return TRUE
/datum/controller/subsystem/shuttle/proc/get_containing_shuttle(atom/A)
for(var/obj/docking_port/mobile/M in mobile)
if(M.is_in_shuttle_bounds(A))
return M
+109 -42
View File
@@ -20,6 +20,7 @@ SUBSYSTEM_DEF(ticker)
var/login_music //music played in pregame lobby
var/round_end_sound //music/jingle played when the world reboots
var/round_end_sound_sent = TRUE //If all clients have loaded it
var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking.
@@ -59,10 +60,13 @@ SUBSYSTEM_DEF(ticker)
var/round_start_time = 0
var/list/round_start_events
var/mode_result = "undefined"
var/end_state = "undefined"
var/modevoted = FALSE //Have we sent a vote for the gamemode?
/datum/controller/subsystem/ticker/Initialize(timeofday)
load_mode()
var/list/music = world.file2list(ROUND_START_MUSIC_LIST, "\n")
login_music = pick(music)
@@ -82,6 +86,8 @@ SUBSYSTEM_DEF(ticker)
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
to_chat(world, "<span class='boldnotice'>Welcome to [station_name()]!</span>")
current_state = GAME_STATE_PREGAME
//Everyone who wants to be an observer is now spawned
create_observers()
if(!modevoted)
send_gamemode_vote()
fire()
@@ -93,7 +99,7 @@ SUBSYSTEM_DEF(ticker)
totalPlayersReady = 0
for(var/mob/dead/new_player/player in GLOB.player_list)
++totalPlayers
if(player.ready)
if(player.ready == PLAYER_READY_TO_PLAY)
++totalPlayersReady
if(start_immediately)
@@ -127,7 +133,7 @@ SUBSYSTEM_DEF(ticker)
scripture_states = scripture_unlock_alert(scripture_states)
SSshuttle.autoEnd()
if(!mode.explosion_in_progress && mode.check_finished() || force_ending)
if(!mode.explosion_in_progress && mode.check_finished(force_ending) || force_ending)
current_state = GAME_STATE_FINISHED
toggle_ooc(1) // Turn it on
declare_completion(force_ending)
@@ -235,6 +241,8 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/PostSetup()
set waitfor = 0
mode.post_setup()
GLOB.start_state = new /datum/station_state()
GLOB.start_state.count(1)
//Cleanup some stuff
for(var/obj/effect/landmark/start/S in GLOB.landmarks_list)
//Deleting Startpoints but we need the ai point to AI-ize people later
@@ -243,7 +251,7 @@ SUBSYSTEM_DEF(ticker)
var/list/adm = get_admin_counts()
var/list/allmins = adm["present"]
send2irc("Server", "Round of [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
send2irc("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)
if(!HasRoundStarted())
@@ -402,7 +410,7 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready && player.mind)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
GLOB.joined_player_list += player.ckey
player.create_character(FALSE)
else
@@ -434,7 +442,7 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/transfer_characters()
var/list/livings = list()
for(var/mob/dead/new_player/player in GLOB.player_list)
for(var/mob/dead/new_player/player in GLOB.mob_list)
var/mob/living = player.transfer_character()
if(living)
qdel(player)
@@ -575,45 +583,16 @@ SUBSYSTEM_DEF(ticker)
CHECK_TICK
//Borers
var/borerwin = FALSE
if(GLOB.borers.len)
var/borertext = "<br><font size=3><b>The borers were:</b></font>"
for(var/mob/living/simple_animal/borer/B in GLOB.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 += ")"
to_chat(world, borertext)
mode.declare_station_goal_completion()
var/total_borers = 0
for(var/mob/living/simple_animal/borer/B in GLOB.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 GLOB.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(GLOB.total_borer_hosts_needed <= total_borer_hosts)
borerwin = TRUE
to_chat(world, "<b>There were [total_borers] borers alive at round end!</b>")
to_chat(world, "<b>A total of [total_borer_hosts] borers with hosts escaped on the shuttle alive. The borers needed [GLOB.total_borer_hosts_needed] hosts to escape.</b>")
if(borerwin)
to_chat(world, "<b><font color='green'>The borers were successful!</font></b>")
else
to_chat(world, "<b><font color='red'>The borers have failed!</font></b>")
//medals, placed far down so that people can actually see the commendations.
if(GLOB.commendations.len)
to_chat(world, "<b><font size=3>Medal Commendations:</font></b>")
for (var/com in GLOB.commendations)
to_chat(world, com)
CHECK_TICK
mode.declare_station_goal_completion()
CHECK_TICK
//Adds the del() log to world.log in a format condensable by the runtime condenser found in tools
@@ -635,11 +614,14 @@ SUBSYSTEM_DEF(ticker)
//Collects persistence features
SSpersistence.CollectData()
//stop collecting feedback during grifftime
SSblackbox.Seal()
sleep(50)
if(mode.station_was_nuked)
world.Reboot("Station destroyed by Nuclear Device.", "end_proper", "nuke")
Reboot("Station destroyed by Nuclear Device.", "nuke")
else
world.Reboot("Round ended.", "end_proper", "proper completion")
Reboot("Round ended.", "proper completion")
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/m
@@ -742,6 +724,15 @@ SUBSYSTEM_DEF(ticker)
cinematic = SSticker.cinematic
maprotatechecked = SSticker.maprotatechecked
switch (current_state)
if(GAME_STATE_SETTING_UP)
Master.SetRunLevel(RUNLEVEL_SETUP)
if(GAME_STATE_PLAYING)
Master.SetRunLevel(RUNLEVEL_GAME)
if(GAME_STATE_FINISHED)
Master.SetRunLevel(RUNLEVEL_POSTGAME)
modevoted = SSticker.modevoted
/datum/controller/subsystem/ticker/proc/send_news_report()
@@ -806,3 +797,79 @@ SUBSYSTEM_DEF(ticker)
start_at = world.time + newtime
else
timeLeft = newtime
//Everyone who wanted to be an observer gets made one now
/datum/controller/subsystem/ticker/proc/create_observers()
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_OBSERVE && player.mind)
//Break chain since this has a sleep input in it
addtimer(CALLBACK(player, /mob/dead/new_player.proc/make_me_an_observer), 1)
/datum/controller/subsystem/ticker/proc/load_mode()
var/mode = trim(file2text("data/mode.txt"))
if(mode)
GLOB.master_mode = mode
else
GLOB.master_mode = "extended"
log_game("Saved mode is '[GLOB.master_mode]'")
/datum/controller/subsystem/ticker/proc/save_mode(the_mode)
var/F = file("data/mode.txt")
fdel(F)
F << the_mode
/datum/controller/subsystem/ticker/proc/SetRoundEndSound(the_sound)
set waitfor = FALSE
round_end_sound_sent = FALSE
round_end_sound = fcopy_rsc(the_sound)
for(var/thing in GLOB.clients)
var/client/C = thing
if (!C)
continue
C.Export("##action=load_rsc", round_end_sound)
round_end_sound_sent = TRUE
/datum/controller/subsystem/ticker/proc/Reboot(reason, end_string, delay)
set waitfor = FALSE
if(usr && !check_rights(R_SERVER, TRUE))
return
if(!delay)
delay = config.round_end_countdown * 10
var/skip_delay = check_rights()
if(delay_end && !skip_delay)
to_chat(world, "<span class='boldannounce'>An admin has delayed the round end.</span>")
return
to_chat(world, "<span class='boldannounce'>Rebooting World in [delay/10] [(delay >= 10 && delay < 20) ? "second" : "seconds"]. [reason]</span>")
var/start_wait = world.time
UNTIL(round_end_sound_sent || (world.time - start_wait) > (delay * 2)) //don't wait forever
sleep(delay - (world.time - start_wait))
if(delay_end && !skip_delay)
to_chat(world, "<span class='boldannounce'>Reboot was cancelled by an admin.</span>")
return
if(end_string)
end_state = end_string
log_game("<span class='boldannounce'>Rebooting World. [reason]</span>")
world.Reboot()
/datum/controller/subsystem/ticker/Shutdown()
if(!round_end_sound)
round_end_sound = pick(\
'sound/roundend/newroundsexy.ogg',
'sound/roundend/apcdestroyed.ogg',
'sound/roundend/bangindonk.ogg',
'sound/roundend/leavingtg.ogg',
'sound/roundend/its_only_game.ogg',
'sound/roundend/yeehaw.ogg',
'sound/roundend/disappointed.ogg'\
)
world << sound(round_end_sound)
+4 -1
View File
@@ -43,7 +43,7 @@ SUBSYSTEM_DEF(timer)
WARNING(msg)
if(bucket_auto_reset)
bucket_resolution = 0
log_world("Active timers at tick [world.time]:")
for(var/I in processing)
var/datum/timedevent/TE = I
@@ -365,10 +365,13 @@ SUBSYSTEM_DEF(timer)
var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
if (flags & TIMER_STOPPABLE)
return timer.id
return TIMER_ID_NULL
/proc/deltimer(id)
if (!id)
return FALSE
if (id == TIMER_ID_NULL)
CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag")
if (!istext(id))
if (istype(id, /datum/timedevent))
qdel(id)
+6
View File
@@ -55,6 +55,12 @@ SUBSYSTEM_DEF(title)
var/F = file("data/previous_title.dat")
F << file_path
for(var/thing in GLOB.clients)
if(!thing)
continue
var/obj/screen/splash/S = new(thing, FALSE)
S.Fade(FALSE,FALSE)
/datum/controller/subsystem/title/Recover()
icon = SStitle.icon
splash_turf = SStitle.splash_turf
+7 -7
View File
@@ -2,9 +2,9 @@ SUBSYSTEM_DEF(vote)
name = "Vote"
wait = 10
flags = SS_KEEP_TIMING|SS_NO_INIT
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
flags = SS_KEEP_TIMING|SS_NO_INIT
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/initiator = null
var/started_time = null
@@ -120,13 +120,13 @@ SUBSYSTEM_DEF(vote)
if(SSticker && SSticker.mode)//Don't change the mode if the round already started.
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
GLOB.master_mode = .
world.save_mode(.)
SSticker.save_mode(.)
to_chat(world, "<span class='adminnotice'><b>The mode is now: [GLOB.master_mode]</b></span>")
log_admin("Gamemode has been voted for and switched to: [GLOB.master_mode].")
if("gamemode")
if(GLOB.master_mode != .)
world.save_mode(.)
if(SSticker.HasRoundStarted())
SSticker.save_mode(.)
if(SSticker.HasRoundStarted())
restart = 1
else
GLOB.master_mode = .
@@ -137,7 +137,7 @@ SUBSYSTEM_DEF(vote)
active_admins = 1
break
if(!active_admins)
world.Reboot("Restart vote successful.", "end_error", "restart vote")
SSticker.Reboot("Restart vote successful.", "restart vote")
else
to_chat(world, "<span style='boldannounce'>Notice:Restart vote will not restart the server automatically because there are active admins on.</span>")
message_admins("A restart vote has passed, but there are active admins on with +server, so it has been canceled. If you wish, you may restart the server.")