mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-20 11:34:19 +01:00
Merge remote-tracking branch 'ParadiseSS13/master' into id_computer_demote_terminate_freejob
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#define AFK_WARNED 1
|
||||
#define AFK_CRYOD 2
|
||||
#define AFK_WARNED 1
|
||||
#define AFK_CRYOD 2
|
||||
#define AFK_ADMINS_WARNED 3
|
||||
|
||||
SUBSYSTEM_DEF(afk)
|
||||
name = "AFK Watcher"
|
||||
@@ -7,24 +8,29 @@ SUBSYSTEM_DEF(afk)
|
||||
flags = SS_BACKGROUND
|
||||
offline_implications = "Players will no longer be marked as AFK. No immediate action is needed."
|
||||
var/list/afk_players = list() // Associative list. ckey as key and AFK state as value
|
||||
var/list/non_cryo_antags
|
||||
|
||||
|
||||
/datum/controller/subsystem/afk/Initialize()
|
||||
if(config.warn_afk_minimum <= 0 || config.auto_cryo_afk <= 0 || config.auto_despawn_afk <= 0)
|
||||
flags |= SS_NO_FIRE
|
||||
if(config.warn_afk_minimum <= 0 || config.auto_cryo_afk <= 0 || config.auto_despawn_afk <= 0)
|
||||
flags |= SS_NO_FIRE
|
||||
else
|
||||
non_cryo_antags = list(SPECIAL_ROLE_ABDUCTOR_AGENT, SPECIAL_ROLE_ABDUCTOR_SCIENTIST, \
|
||||
SPECIAL_ROLE_SHADOWLING, SPECIAL_ROLE_WIZARD, SPECIAL_ROLE_WIZARD_APPRENTICE, SPECIAL_ROLE_NUKEOPS)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/afk/fire()
|
||||
var/list/toRemove = list()
|
||||
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
|
||||
if(!H.ckey) // Useless non ckey creatures
|
||||
for(var/thing in GLOB.human_list)
|
||||
var/mob/living/carbon/human/H = thing
|
||||
if(!H?.ckey) // Useless non ckey creatures
|
||||
continue
|
||||
|
||||
var/turf/T
|
||||
// Only players and players with the AFK watch enabled
|
||||
// No dead, unconcious, restrained, people without jobs, people on other Z levels than the station or antags
|
||||
// No dead, unconcious, restrained, people without jobs or people on other Z levels than the station
|
||||
if(!H.client || !H.client.prefs.afk_watch || !H.mind || \
|
||||
H.stat || H.restrained() || !H.job || H.mind.special_role || \
|
||||
!is_station_level((T = get_turf(H)).z)) // Assign the turf as last. Small optimization
|
||||
H.stat || H.restrained() || !H.job || !is_station_level((T = get_turf(H)).z)) // Assign the turf as last. Small optimization
|
||||
if(afk_players[H.ckey])
|
||||
toRemove += H.ckey
|
||||
continue
|
||||
@@ -44,20 +50,27 @@ SUBSYSTEM_DEF(afk)
|
||||
if(mins_afk >= config.auto_cryo_afk && A.can_get_auto_cryod)
|
||||
if(A.fast_despawn)
|
||||
toRemove += H.ckey
|
||||
warn(H, "<span class='danger'>You are have been despawned after being AFK for [mins_afk] minutes. You have been despawned instantly due to you being in a secure area.</span>")
|
||||
msg_admins(H, mins_afk, T, "forcefully despawned", "AFK in a fast despawn area")
|
||||
warn(H, "<span class='danger'>You have been despawned after being AFK for [mins_afk] minutes. You have been despawned instantly due to you being in a secure area.</span>")
|
||||
log_afk_action(H, mins_afk, T, "despawned", "AFK in a fast despawn area")
|
||||
force_cryo_human(H)
|
||||
else if(cryo_ssd(H))
|
||||
afk_players[H.ckey] = AFK_CRYOD
|
||||
msg_admins(H, mins_afk, T, "put into cryostorage")
|
||||
warn(H, "<span class='danger'>You are AFK for [mins_afk] minutes and have been moved to cryostorage. After being AFK for [config.auto_despawn_afk] total minutes you will be fully despawned. Please eject yourself (right click, eject) out of the cryostorage if you want to avoid being despawned.</span>")
|
||||
else
|
||||
if(!(H.mind.special_role in non_cryo_antags))
|
||||
if(cryo_ssd(H))
|
||||
H.create_log(MISC_LOG, "Put into cryostorage by the AFK subsystem")
|
||||
afk_players[H.ckey] = AFK_CRYOD
|
||||
log_afk_action(H, mins_afk, T, "put into cryostorage")
|
||||
warn(H, "<span class='danger'>You are AFK for [mins_afk] minutes and have been moved to cryostorage. \
|
||||
After being AFK for another [config.auto_despawn_afk] minutes you will be fully despawned. \
|
||||
Please eject yourself (right click, eject) out of the cryostorage if you want to avoid being despawned.</span>")
|
||||
else
|
||||
message_admins("[key_name_admin(H)] at ([get_area(T).name] [ADMIN_JMP(T)]) is AFK for [mins_afk] and can't be automatically cryod due to it's antag status: ([H.mind.special_role]).")
|
||||
afk_players[H.ckey] = AFK_ADMINS_WARNED
|
||||
|
||||
else if(mins_afk >= config.auto_despawn_afk)
|
||||
var/obj/machinery/cryopod/P = H.loc
|
||||
msg_admins(H, mins_afk, T, "forcefully despawned")
|
||||
warn(H, "<span class='danger'>You are have been despawned after being AFK for [mins_afk] minutes.</span>")
|
||||
else if(afk_players[H.ckey] != AFK_ADMINS_WARNED && mins_afk >= config.auto_despawn_afk)
|
||||
log_afk_action(H, mins_afk, T, "despawned")
|
||||
warn(H, "<span class='danger'>You have been despawned after being AFK for [mins_afk] minutes.</span>")
|
||||
toRemove += H.ckey
|
||||
P.despawn_occupant()
|
||||
force_cryo_human(H)
|
||||
|
||||
removeFromWatchList(toRemove)
|
||||
|
||||
@@ -67,9 +80,8 @@ SUBSYSTEM_DEF(afk)
|
||||
if(H.client)
|
||||
window_flash(H.client)
|
||||
|
||||
/datum/controller/subsystem/afk/proc/msg_admins(mob/living/carbon/human/H, mins_afk, turf/location, action, info)
|
||||
/datum/controller/subsystem/afk/proc/log_afk_action(mob/living/carbon/human/H, mins_afk, turf/location, action, info)
|
||||
log_admin("[key_name(H)] has been [action] by the AFK Watcher subsystem after being AFK for [mins_afk] minutes.[info ? " Extra info:" + info : ""]")
|
||||
message_admins("[key_name_admin(H)] at ([get_area(location).name] [ADMIN_JMP(location)]) has been [action] by the AFK Watcher subsystem after being AFK for [mins_afk] minutes.[info ? " Extra info:" + info : ""]")
|
||||
|
||||
/datum/controller/subsystem/afk/proc/removeFromWatchList(list/toRemove)
|
||||
for(var/C in toRemove)
|
||||
@@ -80,3 +92,4 @@ SUBSYSTEM_DEF(afk)
|
||||
|
||||
#undef AFK_WARNED
|
||||
#undef AFK_CRYOD
|
||||
#undef AFK_ADMINS_WARNED
|
||||
|
||||
@@ -90,7 +90,7 @@ SUBSYSTEM_DEF(events)
|
||||
if(E.isRunning)
|
||||
message += "and is still running."
|
||||
else
|
||||
if(E.endedAt - E.startedAt > MinutesToTicks(5)) // Only mention end time if the entire duration was more than 5 minutes
|
||||
if(E.endedAt - E.startedAt > 5 MINUTES) // Only mention end time if the entire duration was more than 5 minutes
|
||||
message += "and ended at [station_time_timestamp("hh:mm:ss", E.endedAt)]."
|
||||
else
|
||||
message += "and ran to completion."
|
||||
@@ -212,38 +212,38 @@ SUBSYSTEM_DEF(events)
|
||||
|
||||
if(href_list["toggle_report"])
|
||||
report_at_round_end = !report_at_round_end
|
||||
admin_log_and_message_admins("has [report_at_round_end ? "enabled" : "disabled"] the round end event report.")
|
||||
log_and_message_admins("has [report_at_round_end ? "enabled" : "disabled"] the round end event report.")
|
||||
else if(href_list["dec_timer"])
|
||||
var/datum/event_container/EC = locate(href_list["event"])
|
||||
var/decrease = (60 * RaiseToPower(10, text2num(href_list["dec_timer"])))
|
||||
EC.next_event_time -= decrease
|
||||
admin_log_and_message_admins("decreased timer for [GLOB.severity_to_string[EC.severity]] events by [decrease/600] minute(s).")
|
||||
log_and_message_admins("decreased timer for [GLOB.severity_to_string[EC.severity]] events by [decrease/600] minute(s).")
|
||||
else if(href_list["inc_timer"])
|
||||
var/datum/event_container/EC = locate(href_list["event"])
|
||||
var/increase = (60 * RaiseToPower(10, text2num(href_list["inc_timer"])))
|
||||
EC.next_event_time += increase
|
||||
admin_log_and_message_admins("increased timer for [GLOB.severity_to_string[EC.severity]] events by [increase/600] minute(s).")
|
||||
log_and_message_admins("increased timer for [GLOB.severity_to_string[EC.severity]] events by [increase/600] minute(s).")
|
||||
else if(href_list["select_event"])
|
||||
var/datum/event_container/EC = locate(href_list["select_event"])
|
||||
var/datum/event_meta/EM = EC.SelectEvent()
|
||||
if(EM)
|
||||
admin_log_and_message_admins("has queued the [GLOB.severity_to_string[EC.severity]] event '[EM.name]'.")
|
||||
log_and_message_admins("has queued the [GLOB.severity_to_string[EC.severity]] event '[EM.name]'.")
|
||||
else if(href_list["pause"])
|
||||
var/datum/event_container/EC = locate(href_list["pause"])
|
||||
EC.delayed = !EC.delayed
|
||||
admin_log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [GLOB.severity_to_string[EC.severity]] events.")
|
||||
log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [GLOB.severity_to_string[EC.severity]] events.")
|
||||
else if(href_list["interval"])
|
||||
var/delay = input("Enter delay modifier. A value less than one means events fire more often, higher than one less often.", "Set Interval Modifier") as num|null
|
||||
if(delay && delay > 0)
|
||||
var/datum/event_container/EC = locate(href_list["interval"])
|
||||
EC.delay_modifier = delay
|
||||
admin_log_and_message_admins("has set the interval modifier for [GLOB.severity_to_string[EC.severity]] events to [EC.delay_modifier].")
|
||||
log_and_message_admins("has set the interval modifier for [GLOB.severity_to_string[EC.severity]] events to [EC.delay_modifier].")
|
||||
else if(href_list["stop"])
|
||||
if(alert("Stopping an event may have unintended side-effects. Continue?","Stopping Event!","Yes","No") != "Yes")
|
||||
return
|
||||
var/datum/event/E = locate(href_list["stop"])
|
||||
var/datum/event_meta/EM = E.event_meta
|
||||
admin_log_and_message_admins("has stopped the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
log_and_message_admins("has stopped the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
E.kill()
|
||||
else if(href_list["view_events"])
|
||||
selected_event_container = locate(href_list["view_events"])
|
||||
@@ -265,23 +265,23 @@ SUBSYSTEM_DEF(events)
|
||||
var/datum/event_meta/EM = locate(href_list["set_weight"])
|
||||
EM.weight = weight
|
||||
if(EM != new_event)
|
||||
admin_log_and_message_admins("has changed the weight of the [GLOB.severity_to_string[EM.severity]] event '[EM.name]' to [EM.weight].")
|
||||
log_and_message_admins("has changed the weight of the [GLOB.severity_to_string[EM.severity]] event '[EM.name]' to [EM.weight].")
|
||||
else if(href_list["toggle_oneshot"])
|
||||
var/datum/event_meta/EM = locate(href_list["toggle_oneshot"])
|
||||
EM.one_shot = !EM.one_shot
|
||||
if(EM != new_event)
|
||||
admin_log_and_message_admins("has [EM.one_shot ? "set" : "unset"] the oneshot flag for the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
log_and_message_admins("has [EM.one_shot ? "set" : "unset"] the oneshot flag for the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
else if(href_list["toggle_enabled"])
|
||||
var/datum/event_meta/EM = locate(href_list["toggle_enabled"])
|
||||
EM.enabled = !EM.enabled
|
||||
admin_log_and_message_admins("has [EM.enabled ? "enabled" : "disabled"] the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
log_and_message_admins("has [EM.enabled ? "enabled" : "disabled"] the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
else if(href_list["remove"])
|
||||
if(alert("This will remove the event from rotation. Continue?","Removing Event!","Yes","No") != "Yes")
|
||||
return
|
||||
var/datum/event_meta/EM = locate(href_list["remove"])
|
||||
var/datum/event_container/EC = locate(href_list["EC"])
|
||||
EC.available_events -= EM
|
||||
admin_log_and_message_admins("has removed the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
log_and_message_admins("has removed the [GLOB.severity_to_string[EM.severity]] event '[EM.name]'.")
|
||||
else if(href_list["add"])
|
||||
if(!new_event.name || !new_event.event_type)
|
||||
return
|
||||
@@ -289,12 +289,12 @@ SUBSYSTEM_DEF(events)
|
||||
return
|
||||
new_event.severity = selected_event_container.severity
|
||||
selected_event_container.available_events += new_event
|
||||
admin_log_and_message_admins("has added \a [GLOB.severity_to_string[new_event.severity]] event '[new_event.name]' of type [new_event.event_type] with weight [new_event.weight].")
|
||||
log_and_message_admins("has added \a [GLOB.severity_to_string[new_event.severity]] event '[new_event.name]' of type [new_event.event_type] with weight [new_event.weight].")
|
||||
new_event = new
|
||||
else if(href_list["clear"])
|
||||
var/datum/event_container/EC = locate(href_list["clear"])
|
||||
if(EC.next_event)
|
||||
admin_log_and_message_admins("has dequeued the [GLOB.severity_to_string[EC.severity]] event '[EC.next_event.name]'.")
|
||||
log_and_message_admins("has dequeued the [GLOB.severity_to_string[EC.severity]] event '[EC.next_event.name]'.")
|
||||
EC.next_event = null
|
||||
|
||||
Interact(usr)
|
||||
|
||||
@@ -4,10 +4,10 @@ SUBSYSTEM_DEF(garbage)
|
||||
wait = 2 SECONDS
|
||||
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
init_order = INIT_ORDER_GARBAGE
|
||||
init_order = INIT_ORDER_GARBAGE // Why does this have an init order if it has SS_NO_INIT?
|
||||
offline_implications = "Garbage collection is no longer functional, and objects will not be qdel'd. Immediate server restart recommended."
|
||||
|
||||
var/list/collection_timeout = list(0, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
|
||||
var/list/collection_timeout = list(2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
|
||||
|
||||
//Stat tracking
|
||||
var/delslasttick = 0 // number of del()'s we've done this tick
|
||||
|
||||
@@ -19,8 +19,18 @@ SUBSYSTEM_DEF(icon_smooth)
|
||||
can_fire = 0
|
||||
|
||||
/datum/controller/subsystem/icon_smooth/Initialize()
|
||||
smooth_zlevel(1,TRUE)
|
||||
smooth_zlevel(2,TRUE)
|
||||
log_startup_progress("Smoothing atoms...")
|
||||
// Smooth EVERYTHING in the world
|
||||
for(var/turf/T in world)
|
||||
if(T.smooth)
|
||||
smooth_icon(T)
|
||||
for(var/A in T)
|
||||
var/atom/AA = A
|
||||
if(AA.smooth)
|
||||
smooth_icon(AA)
|
||||
CHECK_TICK
|
||||
|
||||
// Incase any new atoms were added to the smoothing queue for whatever reason
|
||||
var/queue = smooth_queue
|
||||
smooth_queue = list()
|
||||
for(var/V in queue)
|
||||
|
||||
@@ -121,3 +121,8 @@ SUBSYSTEM_DEF(input)
|
||||
for(var/i in 1 to clients.len)
|
||||
var/client/C = clients[i]
|
||||
C.keyLoop()
|
||||
|
||||
/datum/controller/subsystem/input/Recover()
|
||||
macro_sets = SSinput.macro_sets
|
||||
movement_keys = SSinput.movement_keys
|
||||
alt_movement_keys = SSinput.alt_movement_keys
|
||||
|
||||
@@ -497,13 +497,14 @@ SUBSYSTEM_DEF(jobs)
|
||||
job.after_spawn(H)
|
||||
|
||||
//Gives glasses to the vision impaired
|
||||
if(H.disabilities & DISABILITY_FLAG_NEARSIGHTED)
|
||||
if(NEARSIGHTED in H.mutations)
|
||||
var/equipped = H.equip_to_slot_or_del(new /obj/item/clothing/glasses/regular(H), slot_glasses)
|
||||
if(equipped != 1)
|
||||
var/obj/item/clothing/glasses/G = H.glasses
|
||||
if(istype(G) && !G.prescription)
|
||||
G.prescription = 1
|
||||
G.prescription = TRUE
|
||||
G.name = "prescription [G.name]"
|
||||
H.update_nearsighted_effects()
|
||||
return H
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
GLOBAL_LIST_EMPTY(lighting_update_lights) // List of lighting sources queued for update.
|
||||
GLOBAL_LIST_EMPTY(lighting_update_corners) // List of lighting corners queued for update.
|
||||
GLOBAL_LIST_EMPTY(lighting_update_objects) // List of lighting objects queued for update.
|
||||
|
||||
SUBSYSTEM_DEF(lighting)
|
||||
name = "Lighting"
|
||||
wait = 2
|
||||
init_order = INIT_ORDER_LIGHTING
|
||||
flags = SS_TICKER
|
||||
offline_implications = "Lighting will no longer update. Shuttle call recommended."
|
||||
var/static/list/sources_queue = list() // List of lighting sources queued for update.
|
||||
var/static/list/corners_queue = list() // List of lighting corners queued for update.
|
||||
var/static/list/objects_queue = list() // List of lighting objects queued for update.
|
||||
|
||||
/datum/controller/subsystem/lighting/stat_entry()
|
||||
..("L:[GLOB.lighting_update_lights.len]|C:[GLOB.lighting_update_corners.len]|O:[GLOB.lighting_update_objects.len]")
|
||||
..("L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]")
|
||||
|
||||
/datum/controller/subsystem/lighting/Initialize(timeofday)
|
||||
if(!initialized)
|
||||
@@ -31,9 +30,10 @@ SUBSYSTEM_DEF(lighting)
|
||||
MC_SPLIT_TICK_INIT(3)
|
||||
if(!init_tick_checks)
|
||||
MC_SPLIT_TICK
|
||||
var/list/queue = sources_queue
|
||||
var/i = 0
|
||||
for(i in 1 to GLOB.lighting_update_lights.len)
|
||||
var/datum/light_source/L = GLOB.lighting_update_lights[i]
|
||||
for(i in 1 to length(queue))
|
||||
var/datum/light_source/L = queue[i]
|
||||
|
||||
L.update_corners()
|
||||
|
||||
@@ -44,14 +44,15 @@ SUBSYSTEM_DEF(lighting)
|
||||
else if(MC_TICK_CHECK)
|
||||
break
|
||||
if(i)
|
||||
GLOB.lighting_update_lights.Cut(1, i+1)
|
||||
queue.Cut(1, i + 1)
|
||||
i = 0
|
||||
|
||||
if(!init_tick_checks)
|
||||
MC_SPLIT_TICK
|
||||
|
||||
for (i in 1 to GLOB.lighting_update_corners.len)
|
||||
var/datum/lighting_corner/C = GLOB.lighting_update_corners[i]
|
||||
queue = corners_queue
|
||||
for(i in 1 to length(queue))
|
||||
var/datum/lighting_corner/C = queue[i]
|
||||
|
||||
C.update_objects()
|
||||
C.needs_update = FALSE
|
||||
@@ -60,15 +61,16 @@ SUBSYSTEM_DEF(lighting)
|
||||
else if(MC_TICK_CHECK)
|
||||
break
|
||||
if(i)
|
||||
GLOB.lighting_update_corners.Cut(1, i+1)
|
||||
queue.Cut(1, i + 1)
|
||||
i = 0
|
||||
|
||||
|
||||
if(!init_tick_checks)
|
||||
MC_SPLIT_TICK
|
||||
|
||||
for (i in 1 to GLOB.lighting_update_objects.len)
|
||||
var/atom/movable/lighting_object/O = GLOB.lighting_update_objects[i]
|
||||
queue = objects_queue
|
||||
for(i in 1 to length(queue))
|
||||
var/atom/movable/lighting_object/O = queue[i]
|
||||
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
@@ -80,7 +82,7 @@ SUBSYSTEM_DEF(lighting)
|
||||
else if(MC_TICK_CHECK)
|
||||
break
|
||||
if(i)
|
||||
GLOB.lighting_update_objects.Cut(1, i+1)
|
||||
queue.Cut(1, i + 1)
|
||||
|
||||
|
||||
/datum/controller/subsystem/lighting/Recover()
|
||||
|
||||
@@ -42,7 +42,7 @@ SUBSYSTEM_DEF(machines)
|
||||
while(currentrun.len)
|
||||
var/obj/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(O)
|
||||
if(O && !QDELETED(O))
|
||||
var/datum/powernet/newPN = new() // create a new powernet...
|
||||
propagate_network(O, newPN)//... and propagate it to the other side of the cable
|
||||
|
||||
|
||||
@@ -11,24 +11,57 @@ SUBSYSTEM_DEF(mapping)
|
||||
createRandomZlevel()
|
||||
// Seed space ruins
|
||||
if(!config.disable_space_ruins)
|
||||
var/timer = start_watch()
|
||||
log_startup_progress("Creating random space levels...")
|
||||
seedRuins(list(level_name_to_num(EMPTY_AREA)), rand(0, 3), /area/space, GLOB.space_ruins_templates)
|
||||
log_startup_progress("Loaded random space levels in [stop_watch(timer)]s.")
|
||||
|
||||
// load in extra levels of space ruins
|
||||
|
||||
var/load_zlevels_timer = start_watch()
|
||||
log_startup_progress("Creating random space levels...")
|
||||
var/num_extra_space = rand(config.extra_space_ruin_levels_min, config.extra_space_ruin_levels_max)
|
||||
for(var/i = 1, i <= num_extra_space, i++)
|
||||
var/zlev = GLOB.space_manager.add_new_zlevel("[EMPTY_AREA] #[i]", linkage = CROSSLINKED, traits = list(REACHABLE))
|
||||
seedRuins(list(zlev), rand(0, 3), /area/space, GLOB.space_ruins_templates)
|
||||
GLOB.space_manager.add_new_zlevel("Ruin Area #[i]", linkage = CROSSLINKED, traits = list(REACHABLE, SPAWN_RUINS))
|
||||
log_startup_progress("Loaded random space levels in [stop_watch(load_zlevels_timer)]s.")
|
||||
|
||||
// Now spawn ruins, random budget between 20 and 30 for all zlevels combined.
|
||||
// While this may seem like a high number, the amount of ruin Z levels can be anywhere between 3 and 7.
|
||||
// Note that this budget is not split evenly accross all zlevels
|
||||
log_startup_progress("Seeding ruins...")
|
||||
var/seed_ruins_timer = start_watch()
|
||||
seedRuins(levels_by_trait(SPAWN_RUINS), rand(20, 30), /area/space, GLOB.space_ruins_templates)
|
||||
log_startup_progress("Successfully seeded ruins in [stop_watch(seed_ruins_timer)]s.")
|
||||
|
||||
// Makes a blank space level for the sake of randomness
|
||||
GLOB.space_manager.add_new_zlevel("Empty Area", linkage = CROSSLINKED, traits = list(REACHABLE))
|
||||
|
||||
|
||||
// Setup the Z-level linkage
|
||||
GLOB.space_manager.do_transition_setup()
|
||||
|
||||
// Spawn Lavaland ruins and rivers.
|
||||
log_startup_progress("Populating lavaland...")
|
||||
var/lavaland_setup_timer = start_watch()
|
||||
seedRuins(list(level_name_to_num(MINING)), config.lavaland_budget, /area/lavaland/surface/outdoors/unexplored, GLOB.lava_ruins_templates)
|
||||
spawn_rivers(list(level_name_to_num(MINING)))
|
||||
log_startup_progress("Successfully populated lavaland in [stop_watch(lavaland_setup_timer)]s.")
|
||||
|
||||
// Now we make a list of areas for teleport locs
|
||||
// TOOD: Make these locs into lists on the SS itself, not globs
|
||||
for(var/area/AR in world)
|
||||
if(AR.no_teleportlocs)
|
||||
continue
|
||||
if(GLOB.teleportlocs[AR.name])
|
||||
continue
|
||||
var/turf/picked = safepick(get_area_turfs(AR.type))
|
||||
if(picked && is_station_level(picked.z))
|
||||
GLOB.teleportlocs[AR.name] = AR
|
||||
|
||||
GLOB.teleportlocs = sortAssoc(GLOB.teleportlocs)
|
||||
|
||||
for(var/area/AR in world)
|
||||
if(GLOB.ghostteleportlocs[AR.name])
|
||||
continue
|
||||
var/list/turfs = get_area_turfs(AR.type)
|
||||
if(turfs.len)
|
||||
GLOB.ghostteleportlocs[AR.name] = AR
|
||||
|
||||
GLOB.ghostteleportlocs = sortAssoc(GLOB.ghostteleportlocs)
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ SUBSYSTEM_DEF(mobs)
|
||||
var/static/list/cubemonkeys = list()
|
||||
|
||||
/datum/controller/subsystem/mobs/stat_entry()
|
||||
..("P:[GLOB.mob_list.len]")
|
||||
..("P:[GLOB.mob_living_list.len]")
|
||||
|
||||
/datum/controller/subsystem/mobs/Initialize(start_timeofday)
|
||||
clients_by_zlevel = new /list(world.maxz,0)
|
||||
@@ -21,17 +21,17 @@ SUBSYSTEM_DEF(mobs)
|
||||
/datum/controller/subsystem/mobs/fire(resumed = 0)
|
||||
var/seconds = wait * 0.1
|
||||
if(!resumed)
|
||||
src.currentrun = GLOB.mob_list.Copy()
|
||||
src.currentrun = GLOB.mob_living_list.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
var/times_fired = src.times_fired
|
||||
while(currentrun.len)
|
||||
var/mob/M = currentrun[currentrun.len]
|
||||
var/mob/living/L = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(M)
|
||||
M.Life(seconds, times_fired)
|
||||
if(L)
|
||||
L.Life(seconds, times_fired)
|
||||
else
|
||||
GLOB.mob_list.Remove(M)
|
||||
GLOB.mob_living_list.Remove(L)
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(mob_hunt)
|
||||
name = "Nano-Mob Hunter GO Server"
|
||||
init_order = INIT_ORDER_NANOMOB
|
||||
priority = FIRE_PRIORITY_NANOMOB // Low priority, no need for MC_TICK_CHECK due to extremely low performance impact.
|
||||
flags = SS_NO_INIT
|
||||
offline_implications = "Nano-Mob Hunter will no longer spawn mobs. No immediate action is needed."
|
||||
var/max_normal_spawns = 15 //change this to adjust the number of normal spawns that can exist at one time. trapped spawns (from traitors) don't count towards this
|
||||
var/list/normal_spawns = list()
|
||||
@@ -103,12 +104,12 @@ SUBSYSTEM_DEF(mob_hunt)
|
||||
return
|
||||
if(red_terminal && red_terminal.ready && blue_terminal && blue_terminal.ready)
|
||||
battle_turn = pick("Red", "Blue")
|
||||
red_terminal.audible_message("Battle starting!", null, 5)
|
||||
blue_terminal.audible_message("Battle starting!", null, 5)
|
||||
red_terminal.atom_say("Battle starting!")
|
||||
blue_terminal.atom_say("Battle starting!")
|
||||
if(battle_turn == "Red")
|
||||
red_terminal.audible_message("Red Player's Turn!", null, 5)
|
||||
red_terminal.atom_say("Red Player's Turn!")
|
||||
else if(battle_turn == "Blue")
|
||||
blue_terminal.audible_message("Blue Player's Turn!", null, 5)
|
||||
blue_terminal.atom_say("Blue Player's Turn!")
|
||||
|
||||
/datum/controller/subsystem/mob_hunt/proc/launch_attack(team, raw_damage, datum/mob_type/attack_type)
|
||||
if(!team || !raw_damage)
|
||||
@@ -135,11 +136,11 @@ SUBSYSTEM_DEF(mob_hunt)
|
||||
winner_terminal.ready = 0
|
||||
loser_terminal.ready = 0
|
||||
if(surrender) //surrender doesn't give exp, to avoid people just farming exp without actually doing a battle
|
||||
winner_terminal.audible_message("Your rival surrendered!", null, 2)
|
||||
winner_terminal.atom_say("Your rival surrendered!")
|
||||
else
|
||||
var/progress_message = winner_terminal.mob_info.gain_exp()
|
||||
winner_terminal.audible_message("[winner_terminal.team] Player wins!", null, 5)
|
||||
winner_terminal.audible_message(progress_message, null, 2)
|
||||
winner_terminal.atom_say("[winner_terminal.team] Player wins!")
|
||||
winner_terminal.atom_say(progress_message)
|
||||
|
||||
/datum/controller/subsystem/mob_hunt/proc/end_turn()
|
||||
red_terminal.updateUsrDialog()
|
||||
@@ -148,7 +149,7 @@ SUBSYSTEM_DEF(mob_hunt)
|
||||
return
|
||||
if(battle_turn == "Red")
|
||||
battle_turn = "Blue"
|
||||
blue_terminal.audible_message("Blue's turn.", null, 5)
|
||||
blue_terminal.atom_say("Blue's turn.")
|
||||
else if(battle_turn == "Blue")
|
||||
battle_turn = "Red"
|
||||
blue_terminal.audible_message("Red's turn.", null, 5)
|
||||
blue_terminal.atom_say("Red's turn.")
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(dcs)
|
||||
name = "Datum Component System"
|
||||
flags = SS_NO_INIT
|
||||
|
||||
var/list/elements_by_type = list()
|
||||
// Update this if you add in components which actually use this as a processor
|
||||
offline_implications = "This SS doesnt actually process anything yet. No immediate action is needed."
|
||||
|
||||
/datum/controller/subsystem/processing/dcs/Recover()
|
||||
comp_lookup = SSdcs.comp_lookup
|
||||
|
||||
/datum/controller/subsystem/processing/dcs/proc/GetElement(list/arguments)
|
||||
var/datum/element/eletype = arguments[1]
|
||||
var/element_id = eletype
|
||||
|
||||
if(!ispath(eletype, /datum/element))
|
||||
CRASH("Attempted to instantiate [eletype] as a /datum/element")
|
||||
|
||||
if(initial(eletype.element_flags) & ELEMENT_BESPOKE)
|
||||
element_id = GetIdFromArguments(arguments)
|
||||
|
||||
. = elements_by_type[element_id]
|
||||
if(.)
|
||||
return
|
||||
. = elements_by_type[element_id] = new eletype
|
||||
|
||||
/****
|
||||
* Generates an id for bespoke elements when given the argument list
|
||||
* Generating the id here is a bit complex because we need to support named arguments
|
||||
* Named arguments can appear in any order and we need them to appear after ordered arguments
|
||||
* We assume that no one will pass in a named argument with a value of null
|
||||
**/
|
||||
/datum/controller/subsystem/processing/dcs/proc/GetIdFromArguments(list/arguments)
|
||||
var/datum/element/eletype = arguments[1]
|
||||
var/list/fullid = list("[eletype]")
|
||||
var/list/named_arguments = list()
|
||||
for(var/i in initial(eletype.id_arg_index) to length(arguments))
|
||||
var/key = arguments[i]
|
||||
var/value
|
||||
if(istext(key))
|
||||
value = arguments[key]
|
||||
if(!(istext(key) || isnum(key)))
|
||||
key = "\ref[key]"
|
||||
key = "[key]" // Key is stringified so numbers dont break things
|
||||
if(!isnull(value))
|
||||
if(!(istext(value) || isnum(value)))
|
||||
value = "\ref[value]"
|
||||
named_arguments["[key]"] = value
|
||||
else
|
||||
fullid += "[key]"
|
||||
|
||||
if(length(named_arguments))
|
||||
named_arguments = sortList(named_arguments)
|
||||
fullid += named_arguments
|
||||
return list2params(fullid)
|
||||
@@ -4,3 +4,4 @@ PROCESSING_SUBSYSTEM_DEF(fastprocess)
|
||||
name = "Fast Processing"
|
||||
wait = 2
|
||||
stat_tag = "FP"
|
||||
offline_implications = "Objects using the 'Fast Processing' processor will no longer process. Shuttle call recommended."
|
||||
|
||||
@@ -3,3 +3,4 @@ PROCESSING_SUBSYSTEM_DEF(obj)
|
||||
priority = FIRE_PRIORITY_OBJ
|
||||
flags = SS_NO_INIT
|
||||
wait = 20
|
||||
offline_implications = "Objects using the 'Objects' processor will no longer process. Shuttle call recommended."
|
||||
|
||||
@@ -9,6 +9,7 @@ SUBSYSTEM_DEF(processing)
|
||||
var/stat_tag = "P" //Used for logging
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
offline_implications = "Objects using the default processor will no longer process. Shuttle call recommended."
|
||||
|
||||
/datum/controller/subsystem/processing/stat_entry()
|
||||
..("[stat_tag]:[processing.len]")
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
SUBSYSTEM_DEF(statistics)
|
||||
name = "Statistics"
|
||||
wait = 6000 // 10 minute delay between fires
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME // Only count time actually ingame to avoid logging pre-round dips
|
||||
offline_implications = "Player count and admin count statistics will no longer be logged to the database. No immediate action is needed."
|
||||
|
||||
|
||||
/datum/controller/subsystem/statistics/Initialize(start_timeofday)
|
||||
if(!config.sql_enabled)
|
||||
flags |= SS_NO_FIRE // Disable firing if SQL is disabled
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/statistics/fire(resumed = 0)
|
||||
sql_poll_players()
|
||||
|
||||
/datum/controller/subsystem/statistics/proc/sql_poll_players()
|
||||
if(!config.sql_enabled)
|
||||
return
|
||||
var/playercount = GLOB.clients.len
|
||||
var/admincount = GLOB.admins.len
|
||||
if(!GLOB.dbcon.IsConnected())
|
||||
log_game("SQL ERROR during player polling. Failed to connect.")
|
||||
else
|
||||
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
|
||||
var/DBQuery/query = GLOB.dbcon.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time) VALUES ([playercount], [admincount], '[sqltime]')")
|
||||
if(!query.Execute())
|
||||
var/err = query.ErrorMsg()
|
||||
log_game("SQL ERROR during playercount polling. Error: \[[err]\]\n")
|
||||
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* tgui subsystem
|
||||
*
|
||||
* Contains all tgui state and subsystem code.
|
||||
**/
|
||||
|
||||
|
||||
SUBSYSTEM_DEF(tgui)
|
||||
name = "TGUI"
|
||||
wait = 9
|
||||
flags = SS_NO_INIT
|
||||
priority = FIRE_PRIORITY_NANOUI // Yes I am aware that this is TGUI and I used the nanoUI fire priority. Dont @ me.
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
||||
offline_implications = "All TGUIs will no longer process. Shuttle call recommended."
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key.
|
||||
var/list/processing_uis = list() // A list of processing UIs, ungrouped.
|
||||
var/basehtml // The HTML base used for all UIs.
|
||||
|
||||
/datum/controller/subsystem/tgui/PreInit()
|
||||
basehtml = file2text('tgui/packages/tgui/public/tgui.html')
|
||||
|
||||
/datum/controller/subsystem/tgui/Shutdown()
|
||||
close_all_uis()
|
||||
|
||||
/datum/controller/subsystem/tgui/stat_entry()
|
||||
..("P:[processing_uis.len]")
|
||||
|
||||
/datum/controller/subsystem/tgui/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing_uis.Copy()
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(currentrun.len)
|
||||
var/datum/tgui/ui = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(ui && ui.user && ui.src_object)
|
||||
ui.process()
|
||||
else
|
||||
processing_uis.Remove(ui)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Get a open UI given a user, src_object, and ui_key and try to update it with data.
|
||||
*
|
||||
* required user mob The mob who opened/is using the UI.
|
||||
* required src_object datum The object/datum which owns the UI.
|
||||
* required ui_key string The ui_key of the UI.
|
||||
* optional ui datum/tgui The UI to be updated, if it exists.
|
||||
* optional force_open bool If the UI should be re-opened instead of updated.
|
||||
*
|
||||
* return datum/tgui The found UI.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE)
|
||||
if(isnull(ui)) // No UI was passed, so look for one.
|
||||
ui = get_open_ui(user, src_object, ui_key)
|
||||
|
||||
if(!isnull(ui))
|
||||
var/data = src_object.tgui_data(user) // Get data from the src_object.
|
||||
if(!force_open) // UI is already open; update it.
|
||||
ui.push_data(data)
|
||||
else // Re-open it anyways.
|
||||
ui.reinitialize(null, data)
|
||||
return ui // We found the UI, return it.
|
||||
else
|
||||
return null // We couldn't find a UI.
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Get a open UI given a user, src_object, and ui_key.
|
||||
*
|
||||
* required user mob The mob who opened/is using the UI.
|
||||
* required src_object datum The object/datum which owns the UI.
|
||||
* required ui_key string The ui_key of the UI.
|
||||
*
|
||||
* return datum/tgui The found UI.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key)
|
||||
var/src_object_key = "[src_object.UID()]"
|
||||
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
return null // No UIs open.
|
||||
else if(isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
|
||||
return null // No UIs open for this object.
|
||||
|
||||
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) // Find UIs for this object.
|
||||
if(ui.user == user) // Make sure we have the right user
|
||||
return ui
|
||||
|
||||
return null // Couldn't find a UI!
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Update all UIs attached to src_object.
|
||||
*
|
||||
* required src_object datum The object/datum which owns the UIs.
|
||||
*
|
||||
* return int The number of UIs updated.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
|
||||
var/src_object_key = "[src_object.UID()]"
|
||||
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
return 0 // Couldn't find any UIs for this object.
|
||||
|
||||
var/update_count = 0
|
||||
for(var/ui_key in open_uis[src_object_key])
|
||||
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
|
||||
if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
|
||||
ui.process(force = 1) // Update the UI.
|
||||
update_count++ // Count each UI we update.
|
||||
return update_count
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Close all UIs attached to src_object.
|
||||
*
|
||||
* required src_object datum The object/datum which owns the UIs.
|
||||
*
|
||||
* return int The number of UIs closed.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
|
||||
var/src_object_key = "[src_object.UID()]"
|
||||
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
return 0 // Couldn't find any UIs for this object.
|
||||
|
||||
var/close_count = 0
|
||||
for(var/ui_key in open_uis[src_object_key])
|
||||
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
|
||||
if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
|
||||
ui.close() // Close the UI.
|
||||
close_count++ // Count each UI we close.
|
||||
return close_count
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Close *ALL* UIs
|
||||
*
|
||||
* return int The number of UIs closed.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/close_all_uis()
|
||||
var/close_count = 0
|
||||
for(var/src_object_key in open_uis)
|
||||
for(var/ui_key in open_uis[src_object_key])
|
||||
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
|
||||
if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
|
||||
ui.close() // Close the UI.
|
||||
close_count++ // Count each UI we close.
|
||||
return close_count
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Update all UIs belonging to a user.
|
||||
*
|
||||
* required user mob The mob who opened/is using the UI.
|
||||
* optional src_object datum If provided, only update UIs belonging this src_object.
|
||||
* optional ui_key string If provided, only update UIs with this UI key.
|
||||
*
|
||||
* return int The number of UIs updated.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null)
|
||||
if(isnull(user.open_tguis) || !istype(user.open_tguis, /list) || open_uis.len == 0)
|
||||
return 0 // Couldn't find any UIs for this user.
|
||||
|
||||
var/update_count = 0
|
||||
for(var/datum/tgui/ui in user.open_tguis)
|
||||
if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
|
||||
ui.process(force = 1) // Update the UI.
|
||||
update_count++ // Count each UI we upadte.
|
||||
return update_count
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Close all UIs belonging to a user.
|
||||
*
|
||||
* required user mob The mob who opened/is using the UI.
|
||||
* optional src_object datum If provided, only close UIs belonging this src_object.
|
||||
* optional ui_key string If provided, only close UIs with this UI key.
|
||||
*
|
||||
* return int The number of UIs closed.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null)
|
||||
if(isnull(user.open_tguis) || !istype(user.open_tguis, /list) || open_uis.len == 0)
|
||||
return 0 // Couldn't find any UIs for this user.
|
||||
|
||||
var/close_count = 0
|
||||
for(var/datum/tgui/ui in user.open_tguis)
|
||||
if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
|
||||
ui.close() // Close the UI.
|
||||
close_count++ // Count each UI we close.
|
||||
return close_count
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Add a UI to the list of open UIs.
|
||||
*
|
||||
* required ui datum/tgui The UI to be added.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
|
||||
var/src_object_key = "[ui.src_object.UID()]"
|
||||
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object.
|
||||
else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
|
||||
open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key.
|
||||
|
||||
// Append the UI to all the lists.
|
||||
ui.user.open_tguis |= ui
|
||||
var/list/uis = open_uis[src_object_key][ui.ui_key]
|
||||
uis |= ui
|
||||
processing_uis |= ui
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Remove a UI from the list of open UIs.
|
||||
*
|
||||
* required ui datum/tgui The UI to be removed.
|
||||
*
|
||||
* return bool If the UI was removed or not.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
|
||||
var/src_object_key = "[ui.src_object.UID()]"
|
||||
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
return FALSE // It wasn't open.
|
||||
else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
|
||||
return FALSE // It wasn't open.
|
||||
|
||||
processing_uis.Remove(ui) // Remove it from the list of processing UIs.
|
||||
if(ui.user) // If the user exists, remove it from them too.
|
||||
ui.user.open_tguis.Remove(ui)
|
||||
var/Ukey = ui.ui_key
|
||||
var/list/uis = open_uis[src_object_key][Ukey] // Remove it from the list of open UIs.
|
||||
uis.Remove(ui)
|
||||
if(!uis.len)
|
||||
var/list/uiobj = open_uis[src_object_key]
|
||||
uiobj.Remove(Ukey)
|
||||
if(!uiobj.len)
|
||||
open_uis.Remove(src_object_key)
|
||||
|
||||
return TRUE // Let the caller know we did it.
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Handle client logout, by closing all their UIs.
|
||||
*
|
||||
* required user mob The mob which logged out.
|
||||
*
|
||||
* return int The number of UIs closed.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
|
||||
return close_user_uis(user)
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Handle clients switching mobs, by transferring their UIs.
|
||||
*
|
||||
* required user source The client's original mob.
|
||||
* required user target The client's new mob.
|
||||
*
|
||||
* return bool If the UIs were transferred.
|
||||
**/
|
||||
/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
|
||||
if(!source || isnull(source.open_tguis) || !istype(source.open_tguis, /list) || open_uis.len == 0)
|
||||
return FALSE // The old mob had no open UIs.
|
||||
|
||||
if(isnull(target.open_tguis) || !istype(target.open_tguis, /list))
|
||||
target.open_tguis = list() // Create a list for the new mob if needed.
|
||||
|
||||
for(var/datum/tgui/ui in source.open_tguis)
|
||||
ui.user = target // Inform the UIs of their new owner.
|
||||
target.open_tguis.Add(ui) // Transfer all the UIs.
|
||||
|
||||
source.open_tguis.Cut() // Clear the old list.
|
||||
return TRUE // Let the caller know we did it.
|
||||
@@ -29,7 +29,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/pregame_timeleft // This is used for calculations
|
||||
var/delay_end = 0 //if set to nonzero, the round will not restart on it's own
|
||||
var/triai = 0//Global holder for Triumvirate
|
||||
var/initialtpass = 0 //holder for inital autotransfer vote timer
|
||||
var/next_autotransfer = 0 //holder for inital autotransfer vote timer
|
||||
var/obj/screen/cinematic = null //used for station explosion cinematic
|
||||
var/round_end_announced = 0 // Spam Prevention. Announce round end only once.
|
||||
var/ticker_going = TRUE // This used to be in the unused globals, but it turns out its actually used in a load of places. Its now a ticker var because its related to round stuff, -aa
|
||||
@@ -90,6 +90,11 @@ SUBSYSTEM_DEF(ticker)
|
||||
delay_end = 0 // reset this in case round start was delayed
|
||||
mode.process()
|
||||
mode.process_job_tasks()
|
||||
|
||||
if(world.time > next_autotransfer)
|
||||
SSvote.autotransfer()
|
||||
next_autotransfer = world.time + config.vote_autotransfer_interval
|
||||
|
||||
var/game_finished = SSshuttle.emergency.mode >= SHUTTLE_ENDGAME || mode.station_was_nuked
|
||||
if(config.continuous_rounds)
|
||||
mode.check_finished() // some modes contain var-changing code in here, so call even if we don't uses result
|
||||
@@ -111,19 +116,6 @@ SUBSYSTEM_DEF(ticker)
|
||||
else
|
||||
world.Reboot("Round ended.", "end_proper", "proper completion")
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/votetimer()
|
||||
var/timerbuffer = 0
|
||||
if(initialtpass == 0)
|
||||
timerbuffer = config.vote_autotransfer_initial
|
||||
else
|
||||
timerbuffer = config.vote_autotransfer_interval
|
||||
spawn(timerbuffer)
|
||||
SSvote.autotransfer()
|
||||
initialtpass = 1
|
||||
votetimer()
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/setup()
|
||||
cultdat = setupcult()
|
||||
//Create and announce mode
|
||||
@@ -188,7 +180,14 @@ SUBSYSTEM_DEF(ticker)
|
||||
current_state = GAME_STATE_PLAYING
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
|
||||
callHook("roundstart")
|
||||
// Generate the list of playable AI cores in the world
|
||||
for(var/obj/effect/landmark/start/S in GLOB.landmarks_list)
|
||||
if(S.name != "AI")
|
||||
continue
|
||||
if(locate(/mob/living) in S.loc)
|
||||
continue
|
||||
GLOB.empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(get_turf(S))
|
||||
|
||||
|
||||
//here to initialize the random events nicely at round start
|
||||
setup_economy()
|
||||
@@ -281,17 +280,28 @@ SUBSYSTEM_DEF(ticker)
|
||||
auto_toggle_ooc(0) // Turn it off
|
||||
round_start_time = world.time
|
||||
|
||||
if(config.sql_enabled)
|
||||
spawn(3000)
|
||||
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB
|
||||
|
||||
votetimer()
|
||||
// Sets the auto shuttle vote to happen after the config duration
|
||||
next_autotransfer = world.time + config.vote_autotransfer_initial
|
||||
|
||||
for(var/mob/new_player/N in GLOB.mob_list)
|
||||
if(N.client)
|
||||
N.new_player_panel_proc()
|
||||
|
||||
return 1
|
||||
// Now that every other piece of the round has initialized, lets setup player job scaling
|
||||
var/playercount = length(GLOB.clients)
|
||||
var/highpop_trigger = 80
|
||||
|
||||
if(playercount >= highpop_trigger)
|
||||
log_debug("Playercount: [playercount] versus trigger: [highpop_trigger] - loading highpop job config")
|
||||
SSjobs.LoadJobs("config/jobs_highpop.txt")
|
||||
else
|
||||
log_debug("Playercount: [playercount] versus trigger: [highpop_trigger] - keeping standard job config")
|
||||
|
||||
#ifdef UNIT_TESTS
|
||||
RunUnitTests()
|
||||
#endif
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed = 0, override = null)
|
||||
if(cinematic)
|
||||
@@ -416,7 +426,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
EquipCustomItems(player)
|
||||
if(captainless)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!istype(M,/mob/new_player))
|
||||
if(!isnewplayer(M))
|
||||
to_chat(M, "Captainship not forced on anyone.")
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets)
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/New()
|
||||
NEW_SS_GLOBAL(SSmentor_tickets);
|
||||
PreInit();
|
||||
NEW_SS_GLOBAL(SSmentor_tickets)
|
||||
PreInit()
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets
|
||||
name = "Mentor Tickets"
|
||||
@@ -10,12 +10,13 @@ GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets
|
||||
ticket_name = "Mentor Ticket"
|
||||
span_class = "mentorhelp"
|
||||
close_rights = R_MENTOR | R_ADMIN
|
||||
offline_implications = "Mentor tickets will no longer be marked as stale. No immediate action is needed."
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/message_staff(var/msg)
|
||||
message_mentorTicket(msg)
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/Initialize()
|
||||
close_messages = list("<font color='red' size='3'><b>- [ticket_name] Closed -</b></font>",
|
||||
"<span class='boldmessage'>Please try to be as descriptive as possible in mentor helps. Mentors do not know the full situation you're in and need more information to give you a helpful response.</span>",
|
||||
close_messages = list("<font color='red' size='3'><b>- [ticket_name] Closed -</b></font>",
|
||||
"<span class='boldmessage'>Please try to be as descriptive as possible in mentor helps. Mentors do not know the full situation you're in and need more information to give you a helpful response.</span>",
|
||||
"<span class='[span_class]'>Your [ticket_name] has now been closed.</span>")
|
||||
return ..()
|
||||
|
||||
@@ -20,16 +20,17 @@ SUBSYSTEM_DEF(tickets)
|
||||
init_order = INIT_ORDER_TICKETS
|
||||
wait = 300
|
||||
priority = FIRE_PRIORITY_TICKETS
|
||||
|
||||
offline_implications = "Admin tickets will no longer be marked as stale. No immediate action is needed."
|
||||
|
||||
flags = SS_BACKGROUND
|
||||
|
||||
|
||||
var/list/allTickets = list() //make it here because someone might ahelp before the system has initialized
|
||||
|
||||
var/ticketCounter = 1
|
||||
|
||||
/datum/controller/subsystem/tickets/Initialize()
|
||||
close_messages = list("<font color='red' size='4'><b>- [ticket_name] Rejected! -</b></font>",
|
||||
"<span class='boldmessage'>Please try to be calm, clear, and descriptive in admin helps, do not assume the staff member has seen any related events, and clearly state the names of anybody you are reporting. If you asked a question, please ensure it was clear what you were asking.</span>",
|
||||
"<span class='boldmessage'>Please try to be calm, clear, and descriptive in admin helps, do not assume the staff member has seen any related events, and clearly state the names of anybody you are reporting. If you asked a question, please ensure it was clear what you were asking.</span>",
|
||||
"<span class='[span_class]'>Your [ticket_name] has now been closed.</span>")
|
||||
return ..()
|
||||
|
||||
@@ -112,7 +113,7 @@ SUBSYSTEM_DEF(tickets)
|
||||
message_staff("<span class='[span_class]'>[usr.client] / ([usr]) resolved [ticket_name] number [N]</span>")
|
||||
to_chat_safe(returnClient(N), "<span class='[span_class]'>Your [ticket_name] has now been resolved.</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/autoRespond(N)
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
@@ -124,19 +125,19 @@ SUBSYSTEM_DEF(tickets)
|
||||
if(alert(usr, "[T.ticketState == TICKET_OPEN ? "Another admin appears to already be handling this." : "This ticket is already marked as closed or resolved"] Are you sure you want to continue?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return
|
||||
T.assignStaff(C)
|
||||
|
||||
var/response_phrases = list("Thanks" = "Thanks, have a Paradise day!",
|
||||
|
||||
var/response_phrases = list("Thanks" = "Thanks, have a Paradise day!",
|
||||
"Handling It" = "The issue is being looked into, thanks.",
|
||||
"Already Resolved" = "The problem has been resolved already.",
|
||||
"Mentorhelp" = "Please redirect your question to Mentorhelp, as they are better experienced with these types of questions.",
|
||||
"Happens Again" = "Thanks, let us know if it continues to happen.",
|
||||
"Clear Cache" = "To fix a blank screen, please leave the game and clear your Byond Cache. To clear your Byond Cache, there is a Settings icon in the top right of the launcher. After you click that, go into the Games tab and hit the Clear Cache button. If the issue persists a few minutes after rejoining and doing this, please adminhelp again and state you cleared your cache." ,
|
||||
"Clear Cache" = "To fix a blank screen, go to the 'Special Verbs' tab and press 'Reload UI Resources'. If that fails, clear your BYOND cache (instructions provided with 'Reload UI Resources'). If that still fails, please adminhelp again, stating you have already done the following." ,
|
||||
"IC Issue" = "This is an In Character (IC) issue and will not be handled by admins. You could speak to Security, Internal Affairs, a Departmental Head, Nanotrasen Representetive, or any other relevant authority currently on station.",
|
||||
"Reject" = "Reject",
|
||||
"Man Up" = "Man Up",
|
||||
"Appeal on the Forums" = "Appealing a ban must occur on the forums. Privately messaging, or adminhelping about your ban will not resolve it. To appeal your ban, please head to <a href='[config.banappeals]'>[config.banappeals]</a>"
|
||||
)
|
||||
|
||||
|
||||
var/sorted_responses = list()
|
||||
for(var/key in response_phrases) //build a new list based on the short descriptive keys of the master list so we can send this as the input instead of the full paragraphs to the admin choosing which autoresponse
|
||||
sorted_responses += key
|
||||
@@ -351,7 +352,7 @@ UI STUFF
|
||||
dat += "<tr><td>[T.content[i]]</td></tr>"
|
||||
|
||||
dat += "</table><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a>[check_rights(R_ADMIN|R_MOD, 0) ? "<a href='?src=[UID()];autorespond=[T.ticketNum]'>Auto</a>": ""]<a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a>[check_rights(R_ADMIN|R_MOD, 0) ? "<a href='?src=[UID()];autorespond=[T.ticketNum]'>Auto</a>": ""]<a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
|
||||
if(!T.staffAssigned)
|
||||
dat += "No staff member assigned to this [ticket_name] - <a href='?src=[UID()];assignstaff=[T.ticketNum]'>Take Ticket</a><br />"
|
||||
@@ -447,7 +448,7 @@ UI STUFF
|
||||
return
|
||||
if(closeTicket(indexNum))
|
||||
showDetailUI(usr, indexNum)
|
||||
|
||||
|
||||
|
||||
if(href_list["detailreopen"])
|
||||
var/indexNum = text2num(href_list["detailreopen"])
|
||||
|
||||
@@ -160,7 +160,7 @@ SUBSYSTEM_DEF(timer)
|
||||
|
||||
if(timer.timeToRun < head_offset)
|
||||
bucket_resolution = null //force bucket recreation
|
||||
CRASH("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
|
||||
if(timer.callBack && !timer.spent)
|
||||
timer.callBack.InvokeAsync()
|
||||
@@ -172,7 +172,7 @@ SUBSYSTEM_DEF(timer)
|
||||
|
||||
if(timer.timeToRun < head_offset + TICKS2DS(practical_offset-1))
|
||||
bucket_resolution = null //force bucket recreation
|
||||
CRASH("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
if(timer.callBack && !timer.spent)
|
||||
timer.callBack.InvokeAsync()
|
||||
spent += timer
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
SUBSYSTEM_DEF(title)
|
||||
name = "Title Screen"
|
||||
flags = SS_NO_FIRE
|
||||
init_order = INIT_ORDER_TITLE
|
||||
|
||||
/datum/controller/subsystem/title/Initialize()
|
||||
var/list/provisional_title_screens = flist("config/title_screens/images/")
|
||||
var/list/title_screens = list()
|
||||
var/use_rare_screens = prob(1)
|
||||
|
||||
for(var/S in provisional_title_screens)
|
||||
var/list/L = splittext(S,"+")
|
||||
if(L.len == 1 && L[1] != "blank.png")
|
||||
title_screens += S
|
||||
|
||||
else if(L.len > 1)
|
||||
if(use_rare_screens && lowertext(L[1]) == "rare")
|
||||
title_screens += S
|
||||
else if(GLOB.using_map && (lowertext(L[1]) == lowertext(GLOB.using_map.name)))
|
||||
title_screens += S
|
||||
|
||||
if(!isemptylist(title_screens))
|
||||
if(length(title_screens) > 1)
|
||||
for(var/S in title_screens)
|
||||
var/list/L = splittext(S,".")
|
||||
if(L.len != 2 || L[1] != "default")
|
||||
continue
|
||||
title_screens -= S
|
||||
break
|
||||
|
||||
var/file_path = "config/title_screens/images/[pick(title_screens)]"
|
||||
|
||||
var/icon/icon = new(fcopy_rsc(file_path))
|
||||
|
||||
for(var/turf/unsimulated/wall/splashscreen/splash in world)
|
||||
splash.icon = icon
|
||||
|
||||
return ..()
|
||||
@@ -367,7 +367,7 @@ SUBSYSTEM_DEF(vote)
|
||||
var/votedesc = capitalize(mode)
|
||||
if(mode == "custom")
|
||||
votedesc += " ([question])"
|
||||
admin_log_and_message_admins("cancelled the running [votedesc] vote.")
|
||||
log_and_message_admins("cancelled the running [votedesc] vote.")
|
||||
reset()
|
||||
if("toggle_restart")
|
||||
if(admin)
|
||||
|
||||
@@ -20,7 +20,7 @@ SUBSYSTEM_DEF(weather)
|
||||
var/datum/weather/W = V
|
||||
if(W.aesthetic || W.stage != MAIN_STAGE)
|
||||
continue
|
||||
for(var/i in GLOB.living_mob_list)
|
||||
for(var/i in GLOB.mob_living_list)
|
||||
var/mob/living/L = i
|
||||
if(W.can_weather_act(L))
|
||||
W.weather_act(L)
|
||||
@@ -57,7 +57,6 @@ SUBSYSTEM_DEF(weather)
|
||||
break
|
||||
if(!ispath(weather_datum_type, /datum/weather))
|
||||
CRASH("run_weather called with invalid weather_datum_type: [weather_datum_type || "null"]")
|
||||
return
|
||||
|
||||
if(isnull(z_levels))
|
||||
z_levels = levels_by_trait(initial(weather_datum_type.target_trait))
|
||||
@@ -65,7 +64,6 @@ SUBSYSTEM_DEF(weather)
|
||||
z_levels = list(z_levels)
|
||||
else if(!islist(z_levels))
|
||||
CRASH("run_weather called with invalid z_levels: [z_levels || "null"]")
|
||||
return
|
||||
|
||||
var/datum/weather/W = new weather_datum_type(z_levels)
|
||||
W.telegraph()
|
||||
|
||||
Reference in New Issue
Block a user