Fixes conflict and screen object breaking

This commit is contained in:
variableundefined
2018-10-21 08:31:46 +08:00
1144 changed files with 37485 additions and 20931 deletions
+2 -2
View File
@@ -6,10 +6,10 @@
/datum/controller/process/fast_process/statProcess()
..()
stat(null, "[fast_processing.len] fast processes")
stat(null, "[GLOB.fast_processing.len] fast processes")
/datum/controller/process/fast_process/doWork()
for(last_object in fast_processing)
for(last_object in GLOB.fast_processing)
var/obj/O = last_object
try
O.process()
+8 -28
View File
@@ -2,7 +2,6 @@ var/global/datum/controller/process/npcai/npcai_master
/datum/controller/process/npcai
var/current_cycle
var/saved_voice = 0
/datum/controller/process/npcai/setup()
name = "npc ai"
@@ -12,18 +11,18 @@ var/global/datum/controller/process/npcai/npcai_master
/datum/controller/process/npcai/started()
..()
if(!simple_animal_list)
simple_animal_list = list()
if(!snpc_list)
snpc_list = list()
if(!GLOB.simple_animal_list)
GLOB.simple_animal_list = list()
if(!GLOB.snpc_list)
GLOB.snpc_list = list()
/datum/controller/process/npcai/statProcess()
..()
stat(null, "[simple_animal_list.len] simple animals")
stat(null, "[snpc_list.len] SNPC's")
stat(null, "[GLOB.simple_animal_list.len] simple animals")
stat(null, "[GLOB.snpc_list.len] SNPC's")
/datum/controller/process/npcai/doWork()
for(last_object in simple_animal_list)
for(last_object in GLOB.simple_animal_list)
var/mob/living/simple_animal/M = last_object
if(istype(M) && !QDELETED(M))
if(!M.client && M.stat == CONSCIOUS)
@@ -34,26 +33,7 @@ var/global/datum/controller/process/npcai/npcai_master
SCHECK
else
catchBadType(M)
simple_animal_list -= M
if(ticker.current_state == GAME_STATE_FINISHED && !saved_voice)
var/mob/living/carbon/human/interactive/M = safepick(snpc_list)
if(M)
M.saveVoice()
saved_voice = 1
for(last_object in snpc_list)
var/mob/living/carbon/human/interactive/M = last_object
if(istype(M) && !QDELETED(M))
try
if(!M.alternateProcessing || M.forceProcess)
M.doProcess()
catch(var/exception/e)
catchException(e, M)
SCHECK
else
catchBadType(M)
snpc_list -= M
GLOB.simple_animal_list -= M
current_cycle++
-119
View File
@@ -1,119 +0,0 @@
var/global/datum/controller/process/npcpool/npc_master
/datum/controller/process/npcpool
var/list/canBeUsed = list()
var/list/canBeUsed_non = list()
var/list/needsDelegate = list()
var/list/needsAssistant = list()
var/list/needsHelp_non = list()
var/list/botPool_l = list() //list of all npcs using the pool
var/list/botPool_l_non = list() //list of all non SNPC mobs using the pool
/datum/controller/process/npcpool/setup()
name = "npc pool"
schedule_interval = 100
start_delay = 17
log_startup_progress("NPC pool ticker starting up.")
/datum/controller/process/npcpool/copyStateFrom(var/datum/controller/process/npcpool/target)
canBeUsed = target.canBeUsed
canBeUsed_non = target.canBeUsed_non
needsDelegate = target.needsDelegate
needsAssistant = target.needsAssistant
needsHelp_non = target.needsHelp_non
botPool_l = target.botPool_l
botPool_l_non = target.botPool_l_non
DECLARE_GLOBAL_CONTROLLER(npcpool, npc_master)
/datum/controller/process/npcpool/proc/insertBot(toInsert)
if(istype(toInsert, /mob/living/carbon/human/interactive))
botPool_l |= toInsert
/datum/controller/process/npcpool/proc/removeBot(toRemove)
botPool_l -= toRemove
/datum/controller/process/npcpool/statProcess()
..()
stat(null, "T [botPool_l.len + botPool_l_non.len] | D [needsDelegate.len] | A [needsAssistant.len + needsHelp_non.len] | U [canBeUsed.len + canBeUsed_non.len]")
/datum/controller/process/npcpool/doWork()
//bot delegation and coordination systems
//General checklist/Tasks for delegating a task or coordinating it (for SNPCs)
// 1. Bot proximity to task target: if too far, delegate, if close, coordinate
// 2. Bot Health/status: check health with bots in local area, if their health is higher, delegate task to them, else coordinate
// 3. Process delegation: if a bot (or bots) has been delegated, assign them to the task.
// 4. Process coordination: if a bot(or bots) has been asked to coordinate, assign them to help.
// 5. Do all assignments: goes through the delegated/coordianted bots and assigns the right variables/tasks to them.
listclearnulls(canBeUsed)
//SNPC handling
for(var/mob/living/carbon/human/interactive/check in botPool_l)
if(!check)
botPool_l -= check
continue
var/checkInRange = view(SNPC_MAX_RANGE_FIND, check)
if(!(locate(check.TARGET) in checkInRange))
needsDelegate |= check
else if(check.IsDeadOrIncap(0))
needsDelegate |= check
else if(check.doing & SNPC_FIGHTING)
needsAssistant |= check
else
canBeUsed |= check
SCHECK
if(needsDelegate.len)
needsDelegate -= pick(needsDelegate) // cheapo way to make sure stuff doesn't pingpong around in the pool forever. delegation runs seperately to each loop so it will work much smoother
for(var/mob/living/carbon/human/interactive/check in needsDelegate)
if(!check)
needsDelegate -= check
continue
if(canBeUsed.len)
var/mob/living/carbon/human/interactive/candidate = pick(canBeUsed)
var/facCount = 0
var/helpProb = 0
for(var/C in check.faction)
for(var/D in candidate.faction)
if(D == C)
helpProb = min(100, helpProb + 25)
facCount++
if(facCount == 1 && helpProb > 0)
helpProb = 100
if(prob(helpProb))
if(candidate.takeDelegate(check))
needsDelegate -= check
canBeUsed -= candidate
candidate.change_eye_color(255, 0, 0)
SCHECK
if(needsAssistant.len)
needsAssistant -= pick(needsAssistant)
for(var/mob/living/carbon/human/interactive/check in needsAssistant)
if(!check)
needsAssistant -= check
continue
if(canBeUsed.len)
var/mob/living/carbon/human/interactive/candidate = pick(canBeUsed)
var/facCount = 0
var/helpProb = 0
for(var/C in check.faction)
for(var/D in candidate.faction)
if(D == C)
helpProb = min(100, helpProb + 25)
facCount++
if(facCount == 1 && helpProb > 0)
helpProb = 100
if(prob(helpProb))
if(candidate.takeDelegate(check, 0))
needsAssistant -= check
canBeUsed -= candidate
candidate.change_eye_color(255, 255, 0)
SCHECK
+6 -2
View File
@@ -85,6 +85,7 @@
var/githuburl = "http://example.org"
var/donationsurl = "http://example.org"
var/repositoryurl = "http://example.org"
var/discordurl = "http://example.org"
var/overflow_server_url
var/forbid_singulo_possession = 0
@@ -388,7 +389,10 @@
if("githuburl")
config.githuburl = value
if("discordurl")
config.discordurl = value
if("donationsurl")
config.donationsurl = value
@@ -782,4 +786,4 @@
if(M.can_start())
runnable_modes[M] = probabilities[M.config_tag]
// to_chat(world, "DEBUG: runnable_mode\[[runnable_modes.len]\] = [M.config_tag]")
return runnable_modes
return runnable_modes
+5 -5
View File
@@ -54,20 +54,20 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
message_admins("<span class='adminnotice'>Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5 - defcon) * processing_interval] ticks.</span>")
--defcon
if(2)
to_chat(admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5 - defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.</span>")
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5 - defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.</span>")
--defcon
if(1)
to_chat(admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5 - defcon) * processing_interval] ticks. Killing and restarting...</span>")
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5 - defcon) * processing_interval] ticks. Killing and restarting...</span>")
--defcon
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
to_chat(admins, "<span class='adminnotice'>MC restarted successfully</span>")
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
else if(rtn < 0)
log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
to_chat(admins, "<span class='boldannounce'>ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.</span>")
to_chat(GLOB.admins, "<span class='boldannounce'>ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.</span>")
//if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again
//no need to handle that specially when defcon 0 can handle it
if(0) //DEFCON 0! (mc failed to restart)
@@ -75,7 +75,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
if(rtn > 0)
defcon = 4
master_iteration = 0
to_chat(admins, "<span class='adminnotice'>MC restarted successfully</span>")
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
else
defcon = min(defcon + 1,5)
master_iteration = Master.iteration
+2 -2
View File
@@ -149,7 +149,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined."
BadBoy.flags |= SS_NO_FIRE
if(msg)
to_chat(admins, "<span class='boldannounce'>[msg]</span>")
to_chat(GLOB.admins, "<span class='boldannounce'>[msg]</span>")
log_world(msg)
if(istype(Master.subsystems))
@@ -609,7 +609,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
/datum/controller/master/proc/UpdateTickRate()
if(!processing)
return
var/client_count = length(clients)
var/client_count = length(GLOB.clients)
if(client_count < config.disable_high_pop_mc_mode_amount)
processing = config.base_mc_tick_rate
else if(client_count > config.high_pop_mc_mode_amount)
+5 -5
View File
@@ -66,8 +66,8 @@ SUBSYSTEM_DEF(air)
/datum/controller/subsystem/air/Initialize(timeofday)
setup_overlays() // Assign icons and such for gas-turf-overlays
setup_allturfs()
setup_atmos_machinery(machines)
setup_pipenets(machines)
setup_atmos_machinery(GLOB.machines)
setup_pipenets(GLOB.machines)
..()
@@ -363,19 +363,19 @@ SUBSYSTEM_DEF(air)
plmaster.icon = 'icons/effects/tile_effects.dmi'
plmaster.icon_state = "plasma"
plmaster.layer = FLY_LAYER
plmaster.mouse_opacity = 0
plmaster.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
slmaster = new /obj/effect/overlay()
slmaster.icon = 'icons/effects/tile_effects.dmi'
slmaster.icon_state = "sleeping_agent"
slmaster.layer = FLY_LAYER
slmaster.mouse_opacity = 0
slmaster.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
icemaster = new /obj/effect/overlay()
icemaster.icon = 'icons/turf/overlays.dmi'
icemaster.icon_state = "snowfloor"
icemaster.layer = TURF_LAYER + 0.1
icemaster.mouse_opacity = 0
icemaster.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
#undef SSAIR_PIPENETS
#undef SSAIR_ATMOSMACHINERY
+17 -51
View File
@@ -59,7 +59,6 @@ SUBSYSTEM_DEF(garbage)
msg += " | Fail:[fail_counts.Join(",")]"
..(msg)
/* TO-DO
/datum/controller/subsystem/garbage/Shutdown()
//Adds the del() log to the qdel log file
var/list/dellog = list()
@@ -83,45 +82,24 @@ SUBSYSTEM_DEF(garbage)
if(I.no_hint)
dellog += "\tNo hint: [I.no_hint] times"
log_qdel(dellog.Join("\n"))
*/
/datum/controller/subsystem/garbage/fire()
//the fact that this resets its processing each fire (rather then resume where it left off) is intentional.
var/queue = GC_QUEUE_PREQUEUE
var/queue = GC_QUEUE_CHECK
while(state == SS_RUNNING)
switch(queue)
if(GC_QUEUE_PREQUEUE)
HandlePreQueue()
queue = GC_QUEUE_PREQUEUE + 1
if(GC_QUEUE_CHECK)
HandleQueue(GC_QUEUE_CHECK)
queue = GC_QUEUE_CHECK + 1
if(GC_QUEUE_HARDDELETE)
HandleQueue(GC_QUEUE_HARDDELETE)
if(state == SS_PAUSED) //make us wait again before the next run.
state = SS_RUNNING
break
if(state == SS_PAUSED) //make us wait again before the next run.
state = SS_RUNNING
//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond.
//Don't attempt to optimize, not worth the effort.
/datum/controller/subsystem/garbage/proc/HandlePreQueue()
var/list/tobequeued = queues[GC_QUEUE_PREQUEUE]
var/static/count = 0
if(count)
var/c = count
count = 0 //so if we runtime on the Cut, we don't try again.
tobequeued.Cut(1, c + 1)
for(var/ref in tobequeued)
count++
Queue(ref, GC_QUEUE_PREQUEUE + 1)
if(MC_TICK_CHECK)
break
if(count)
tobequeued.Cut(1, count + 1)
count = 0
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
if(level == GC_QUEUE_CHECK)
@@ -143,7 +121,7 @@ SUBSYSTEM_DEF(garbage)
if(!refID)
count++
if(MC_TICK_CHECK)
break
return
continue
var/GCd_at_time = queue[refID]
@@ -162,7 +140,7 @@ SUBSYSTEM_DEF(garbage)
reference_find_on_fail -= refID //It's deleted we don't care anymore.
#endif
if(MC_TICK_CHECK)
break
return
continue
// Something's still referring to the qdel'd object.
@@ -185,27 +163,20 @@ SUBSYSTEM_DEF(garbage)
if(GC_QUEUE_HARDDELETE)
HardDelete(D)
if(MC_TICK_CHECK)
break
return
continue
Queue(D, level + 1)
if(MC_TICK_CHECK)
break
return
if(count)
queue.Cut(1, count + 1)
count = 0
/datum/controller/subsystem/garbage/proc/PreQueue(datum/D)
if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
queues[GC_QUEUE_PREQUEUE] += D
D.gc_destroyed = GC_QUEUED_FOR_QUEUING
/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK)
if(isnull(D))
return
if(D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL)
level = GC_QUEUE_HARDDELETE
if(level > GC_QUEUE_COUNT)
HardDelete(D)
return
@@ -251,11 +222,6 @@ SUBSYSTEM_DEF(garbage)
message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time / 10] seconds to delete).")
postpone(time)
/datum/controller/subsystem/garbage/proc/HardQueue(datum/D)
if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
queues[GC_QUEUE_PREQUEUE] += D
D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
/datum/controller/subsystem/garbage/Recover()
if(istype(SSgarbage.queues))
for(var/i in 1 to SSgarbage.queues.len)
@@ -300,8 +266,8 @@ SUBSYSTEM_DEF(garbage)
#if DM_VERSION > 511
#warn Remove the garbage bypass code below
#endif
var/Removein512 = SEND_SIGNAL(D, COMSIG_PARENT_QDELETED, force) // Give the components a chance to prevent their parent from being deleted
KillMeIn512(Removein512)
if(SEND_SIGNAL(D, COMSIG_PARENT_QDELETED, force)) // Give the components a chance to prevent their parent from being deleted
return
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
var/start_time = world.time
var/start_tick = world.tick_usage
@@ -316,7 +282,7 @@ SUBSYSTEM_DEF(garbage)
return
switch(hint)
if(QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
if(QDEL_HINT_IWILLGC)
D.gc_destroyed = world.time
return
@@ -336,18 +302,18 @@ SUBSYSTEM_DEF(garbage)
#endif
I.no_respect_force++
SSgarbage.PreQueue(D)
if(QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate()
SSgarbage.HardQueue(D)
SSgarbage.Queue(D)
if(QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete
SSgarbage.Queue(D, GC_QUEUE_HARDDELETE)
if(QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
SSgarbage.HardDelete(D)
if(QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
#ifdef TESTING
D.find_references()
#endif
if(QDEL_HINT_IFFAIL_FINDREFERENCE)
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
#ifdef TESTING
SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
#endif
@@ -357,7 +323,7 @@ SUBSYSTEM_DEF(garbage)
testing("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
#endif
I.no_hint++
SSgarbage.PreQueue(D)
SSgarbage.Queue(D)
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
@@ -472,4 +438,4 @@ SUBSYSTEM_DEF(garbage)
CHECK_TICK
#endif
#endif
#endif
+32
View File
@@ -0,0 +1,32 @@
SUBSYSTEM_DEF(icon_smooth)
name = "Icon Smoothing"
init_order = INIT_ORDER_ICON_SMOOTHING
wait = 1
priority = FIRE_PRIOTITY_SMOOTHING
flags = SS_TICKER
var/list/smooth_queue = list()
/datum/controller/subsystem/icon_smooth/fire()
while(smooth_queue.len)
var/atom/A = smooth_queue[smooth_queue.len]
smooth_queue.len--
smooth_icon(A)
if(MC_TICK_CHECK)
return
if(!smooth_queue.len)
can_fire = 0
/datum/controller/subsystem/icon_smooth/Initialize()
smooth_zlevel(1,TRUE)
smooth_zlevel(2,TRUE)
var/queue = smooth_queue
smooth_queue = list()
for(var/V in queue)
var/atom/A = V
if(!A || A.z <= 2)
continue
smooth_icon(A)
CHECK_TICK
..()
+3 -3
View File
@@ -67,7 +67,7 @@ SUBSYSTEM_DEF(machines)
/datum/controller/subsystem/machines/proc/process_premachines(resumed = 0)
/* Literally exists as snowflake for fucking powersinks goddamnit */
if(!resumed)
src.currentrun = processing_power_items.Copy()
src.currentrun = GLOB.processing_power_items.Copy()
//cache for sanid speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
@@ -75,9 +75,9 @@ SUBSYSTEM_DEF(machines)
currentrun.len--
if(!QDELETED(I))
if(!I.pwr_drain())
processing_power_items.Remove(I)
GLOB.processing_power_items.Remove(I)
else
processing_power_items.Remove(I)
GLOB.processing_power_items.Remove(I)
if(MC_TICK_CHECK)
return
+3 -3
View File
@@ -7,12 +7,12 @@ SUBSYSTEM_DEF(mobs)
var/list/currentrun = list()
/datum/controller/subsystem/mobs/stat_entry()
..("P:[mob_list.len]")
..("P:[GLOB.mob_list.len]")
/datum/controller/subsystem/mobs/fire(resumed = 0)
var/seconds = wait * 0.1
if(!resumed)
src.currentrun = mob_list.Copy()
src.currentrun = GLOB.mob_list.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
@@ -23,6 +23,6 @@ SUBSYSTEM_DEF(mobs)
if(M)
M.Life(seconds, times_fired)
else
mob_list.Remove(M)
GLOB.mob_list.Remove(M)
if(MC_TICK_CHECK)
return
@@ -1,6 +1,7 @@
var/global/datum/controller/process/mob_hunt/mob_hunt_server
/datum/controller/process/mob_hunt
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.
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()
var/max_trap_spawns = 15 //change this to adjust the number of trap spawns that can exist at one time. traps spawned beyond this point clear the oldest traps
@@ -12,11 +13,7 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
var/obj/machinery/computer/mob_battle_terminal/blue_terminal
var/battle_turn = null
/datum/controller/process/mob_hunt/setup()
name = "Nano-Mob Hunter GO Server"
start_delay = 20
/datum/controller/process/mob_hunt/doWork()
/datum/controller/subsystem/mob_hunt/fire(resumed = FALSE)
if(reset_cooldown) //if reset_cooldown is set (we are on cooldown, duh), reduce the remaining cooldown every cycle
reset_cooldown--
if(!server_status)
@@ -25,10 +22,8 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
if(normal_spawns.len < max_normal_spawns)
spawn_mob()
DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
//leaving this here in case admins want to use it for a random mini-event or something
/datum/controller/process/mob_hunt/proc/server_crash(recover_time = 3000)
/datum/controller/subsystem/mob_hunt/proc/server_crash(recover_time = 3000)
server_status = 0
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
client.disconnect("Server Crash")
@@ -46,7 +41,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
//set a timer to automatically recover after recover_time has passed (can be manually restarted if you get impatient too)
addtimer(CALLBACK(src, .proc/auto_recover), recover_time, TIMER_UNIQUE)
/datum/controller/process/mob_hunt/proc/client_mob_update()
/datum/controller/subsystem/mob_hunt/proc/client_mob_update()
var/list/ex_players = list()
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
var/mob/living/carbon/human/H = client.get_player()
@@ -58,14 +53,14 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
for(var/obj/effect/nanomob/N in (normal_spawns + trap_spawns))
N.conceal(ex_players)
/datum/controller/process/mob_hunt/proc/auto_recover()
/datum/controller/subsystem/mob_hunt/proc/auto_recover()
if(server_status != 0)
return
server_status = 1
while(normal_spawns.len < max_normal_spawns) //repopulate the server's spawns completely if we auto-recover from crash
spawn_mob()
/datum/controller/process/mob_hunt/proc/manual_reboot()
/datum/controller/subsystem/mob_hunt/proc/manual_reboot()
if(server_status && reset_cooldown)
return 0
for(var/obj/effect/nanomob/N in trap_spawns)
@@ -76,12 +71,12 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
reset_cooldown = 25 //25 controller cycle cooldown for manual restarts
return 1
/datum/controller/process/mob_hunt/proc/spawn_mob()
/datum/controller/subsystem/mob_hunt/proc/spawn_mob()
var/list/nanomob_types = subtypesof(/datum/mob_hunt)
var/datum/mob_hunt/mob_info = pick(nanomob_types)
new mob_info()
/datum/controller/process/mob_hunt/proc/register_spawn(datum/mob_hunt/mob_info)
/datum/controller/subsystem/mob_hunt/proc/register_spawn(datum/mob_hunt/mob_info)
if(!mob_info)
return 0
var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info)
@@ -89,7 +84,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
new_mob.reveal()
return 1
/datum/controller/process/mob_hunt/proc/register_trap(datum/mob_hunt/mob_info)
/datum/controller/subsystem/mob_hunt/proc/register_trap(datum/mob_hunt/mob_info)
if(!mob_info)
return 0
if(!mob_info.is_trap)
@@ -102,7 +97,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
old_trap.despawn()
return 1
/datum/controller/process/mob_hunt/proc/start_check()
/datum/controller/subsystem/mob_hunt/proc/start_check()
if(battle_turn) //somehow we got called mid-battle, so lets just stop now
return
if(red_terminal && red_terminal.ready && blue_terminal && blue_terminal.ready)
@@ -114,7 +109,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
else if(battle_turn == "Blue")
blue_terminal.audible_message("Blue Player's Turn!", null, 5)
/datum/controller/process/mob_hunt/proc/launch_attack(team, raw_damage, datum/mob_type/attack_type)
/datum/controller/subsystem/mob_hunt/proc/launch_attack(team, raw_damage, datum/mob_type/attack_type)
if(!team || !raw_damage)
return
var/obj/machinery/computer/mob_battle_terminal/target = null
@@ -126,7 +121,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
return
target.receive_attack(raw_damage, attack_type)
/datum/controller/process/mob_hunt/proc/end_battle(loser, surrender = 0)
/datum/controller/subsystem/mob_hunt/proc/end_battle(loser, surrender = 0)
var/obj/machinery/computer/mob_battle_terminal/winner_terminal = null
var/obj/machinery/computer/mob_battle_terminal/loser_terminal = null
if(loser == "Red")
@@ -145,7 +140,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
winner_terminal.audible_message("[winner_terminal.team] Player wins!", null, 5)
winner_terminal.audible_message(progress_message, null, 2)
/datum/controller/process/mob_hunt/proc/end_turn()
/datum/controller/subsystem/mob_hunt/proc/end_turn()
red_terminal.updateUsrDialog()
blue_terminal.updateUsrDialog()
if(!battle_turn)
+1 -1
View File
@@ -54,7 +54,7 @@ SUBSYSTEM_DEF(nightshift)
announce("Good evening, crew. To reduce power consumption and stimulate the circadian rhythms of some species, all of the lights aboard the station have been dimmed for the night.")
else
announce("Good morning, crew. As it is now day time, all of the lights aboard the station have been restored to their former brightness.")
for(var/A in apcs)
for(var/A in GLOB.apcs)
var/obj/machinery/power/apc/APC = A
if(is_station_level(APC.z))
APC.set_nightshift(active)
+24
View File
@@ -0,0 +1,24 @@
SUBSYSTEM_DEF(npcai)
name = "NPC AI" // Simple AI controller, isolated from the SNPC one (NPCPool).
flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND
priority = FIRE_PRIORITY_NPC
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/simple_animal_list = list()
/datum/controller/subsystem/npcai/stat_entry()
..("SimAnimals:[simple_animal_list.len]")
/datum/controller/subsystem/npcai/fire(resumed = FALSE)
if(!resumed)
src.simple_animal_list = simple_animal_list.Copy()
for(var/mob/living/simple_animal/M in simple_animal_list)
if(istype(M) && !QDELETED(M))
if(!M.client && M.stat == CONSCIOUS)
M.process_ai()
if(MC_TICK_CHECK)
return
else
simple_animal_list -= M
/datum/controller/subsystem/npcai/Recover()
simple_animal_list = SSnpcai.simple_animal_list
+127
View File
@@ -0,0 +1,127 @@
#define PROCESSING_NPCS 0
#define PROCESSING_DELEGATES 1
#define PROCESSING_ASSISTANTS 2
SUBSYSTEM_DEF(npcpool)
name = "NPC Pool"
flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND
priority = FIRE_PRIORITY_NPC
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/canBeUsed = list()
var/list/needsDelegate = list()
var/list/needsAssistant = list()
var/list/processing = list()
var/list/currentrun = list()
var/stage
/datum/controller/subsystem/npcpool/stat_entry()
..("NPCS:[processing.len]|D:[needsDelegate.len]|A:[needsAssistant.len]|U:[canBeUsed.len]")
/datum/controller/subsystem/npcpool/proc/stop_processing(mob/living/carbon/human/interactive/I)
processing -= I
currentrun -= I
needsDelegate -= I
canBeUsed -= I
needsAssistant -= I
/datum/controller/subsystem/npcpool/fire(resumed = FALSE)
//bot delegation and coordination systems
//General checklist/Tasks for delegating a task or coordinating it (for SNPCs)
// 1. Bot proximity to task target: if too far, delegate, if close, coordinate
// 2. Bot Health/status: check health with bots in local area, if their health is higher, delegate task to them, else coordinate
// 3. Process delegation: if a bot (or bots) has been delegated, assign them to the task.
// 4. Process coordination: if a bot(or bots) has been asked to coordinate, assign them to help.
// 5. Do all assignments: goes through the delegated/coordianted bots and assigns the right variables/tasks to them.
if (!resumed)
currentrun = processing.Copy()
stage = PROCESSING_NPCS
//cache for sanic speed (lists are references anyways)
var/list/cachecurrentrun = currentrun
var/list/cachecanBeUsed = canBeUsed
if(stage == PROCESSING_NPCS)
while(cachecurrentrun.len)
var/mob/living/carbon/human/interactive/thing = cachecurrentrun[cachecurrentrun.len]
--cachecurrentrun.len
thing.InteractiveProcess()
var/checkInRange = view(SNPC_MAX_RANGE_FIND,thing)
if(thing.IsDeadOrIncap(FALSE) || !(locate(thing.TARGET) in checkInRange))
needsDelegate += thing
else if(thing.doing & SNPC_FIGHTING)
needsAssistant += thing
else
cachecanBeUsed += thing
if (MC_TICK_CHECK)
return
stage = PROCESSING_DELEGATES
cachecurrentrun = needsDelegate //localcache
currentrun = cachecurrentrun
if(stage == PROCESSING_DELEGATES)
while(cachecurrentrun.len && cachecanBeUsed.len)
var/mob/living/carbon/human/interactive/check = cachecurrentrun[cachecurrentrun.len]
var/mob/living/carbon/human/interactive/candidate = cachecanBeUsed[cachecanBeUsed.len]
--cachecurrentrun.len
var/helpProb = 0
var/list/chfac = check.faction
var/list/canfac = candidate.faction
var/facCount = LAZYLEN(chfac) * LAZYLEN(canfac)
for(var/C in chfac)
if(C in canfac)
helpProb = min(100,helpProb + 25)
if(helpProb >= 100)
break
if(facCount == 1 && helpProb)
helpProb = 100
if(prob(helpProb) && candidate.takeDelegate(check))
--cachecanBeUsed.len
candidate.change_eye_color(255, 0, 0)
candidate.update_icons()
if(MC_TICK_CHECK)
return
stage = PROCESSING_ASSISTANTS
cachecurrentrun = needsAssistant //localcache
currentrun = cachecurrentrun
//no need for the stage check
while(cachecurrentrun.len && cachecanBeUsed.len)
var/mob/living/carbon/human/interactive/check = cachecurrentrun[cachecurrentrun.len]
var/mob/living/carbon/human/interactive/candidate = cachecanBeUsed[cachecanBeUsed.len]
--cachecurrentrun.len
var/helpProb = 0
var/list/chfac = check.faction
var/list/canfac = candidate.faction
var/facCount = LAZYLEN(chfac) * LAZYLEN(canfac)
for(var/C in chfac)
if(C in canfac)
helpProb = min(100,helpProb + 25)
if(helpProb >= 100)
break
if(facCount == 1 && helpProb)
helpProb = 100
if(prob(helpProb) && candidate.takeDelegate(check,FALSE))
--cachecanBeUsed.len
candidate.change_eye_color(255, 255, 0)
candidate.update_icons()
if(!cachecurrentrun.len || MC_TICK_CHECK) //don't change SS state if it isn't necessary
return
/datum/controller/subsystem/npcpool/Recover()
processing = SSnpcpool.processing
+212
View File
@@ -0,0 +1,212 @@
SUBSYSTEM_DEF(overlays)
name = "Overlay"
flags = SS_TICKER
wait = 1
priority = FIRE_PRIORITY_OVERLAYS
init_order = INIT_ORDER_OVERLAY
var/list/queue
var/list/stats
var/list/overlay_icon_state_caches
var/list/overlay_icon_cache
/datum/controller/subsystem/overlays/PreInit()
overlay_icon_state_caches = list()
overlay_icon_cache = list()
queue = list()
stats = list()
/datum/controller/subsystem/overlays/Initialize()
initialized = TRUE
fire(mc_check = FALSE)
return ..()
/datum/controller/subsystem/overlays/stat_entry()
..("Ov:[length(queue)]")
/datum/controller/subsystem/overlays/Recover()
overlay_icon_state_caches = SSoverlays.overlay_icon_state_caches
overlay_icon_cache = SSoverlays.overlay_icon_cache
queue = SSoverlays.queue
/datum/controller/subsystem/overlays/fire(resumed = FALSE, mc_check = TRUE)
var/list/queue = src.queue
var/static/count = 0
if(count)
var/c = count
count = 0 //so if we runtime on the Cut, we don't try again.
queue.Cut(1, c + 1)
for(var/thing in queue)
count++
if(thing)
var/atom/A = thing
COMPILE_OVERLAYS(A)
if(mc_check)
if(MC_TICK_CHECK)
break
else
CHECK_TICK
if(count)
queue.Cut(1, count + 1)
count = 0
/proc/iconstate2appearance(icon, iconstate)
var/static/image/stringbro = new()
var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches
var/list/cached_icon = icon_states_cache[icon]
if(cached_icon)
var/cached_appearance = cached_icon["[iconstate]"]
if(cached_appearance)
return cached_appearance
stringbro.icon = icon
stringbro.icon_state = iconstate
if(!cached_icon) //not using the macro to save an associated lookup
cached_icon = list()
icon_states_cache[icon] = cached_icon
var/cached_appearance = stringbro.appearance
cached_icon["[iconstate]"] = cached_appearance
return cached_appearance
/proc/icon2appearance(icon)
var/static/image/iconbro = new()
var/list/icon_cache = SSoverlays.overlay_icon_cache
. = icon_cache[icon]
if(!.)
iconbro.icon = icon
. = iconbro.appearance
icon_cache[icon] = .
/atom/proc/build_appearance_list(old_overlays)
var/static/image/appearance_bro = new()
var/list/new_overlays = list()
if(!islist(old_overlays))
old_overlays = list(old_overlays)
for(var/overlay in old_overlays)
if(!overlay)
continue
if(istext(overlay))
new_overlays += iconstate2appearance(icon, overlay)
else if(isicon(overlay))
new_overlays += icon2appearance(overlay)
else
if(isloc(overlay))
var/atom/A = overlay
if(A.flags_2 & OVERLAY_QUEUED_2)
COMPILE_OVERLAYS(A)
appearance_bro.appearance = overlay //this works for images and atoms too!
if(!ispath(overlay))
var/image/I = overlay
appearance_bro.dir = I.dir
new_overlays += appearance_bro.appearance
return new_overlays
#define NOT_QUEUED_ALREADY (!(flags_2 & OVERLAY_QUEUED_2))
#define QUEUE_FOR_COMPILE flags_2 |= OVERLAY_QUEUED_2; SSoverlays.queue += src;
/atom/proc/cut_overlays(priority = FALSE)
LAZYINITLIST(priority_overlays)
LAZYINITLIST(remove_overlays)
LAZYINITLIST(add_overlays)
remove_overlays = overlays.Copy()
add_overlays.Cut()
if(priority)
priority_overlays.Cut()
//If not already queued for work and there are overlays to remove
if(NOT_QUEUED_ALREADY && remove_overlays.len)
QUEUE_FOR_COMPILE
/atom/proc/cut_overlay(list/overlays, priority)
if(!overlays)
return
overlays = build_appearance_list(overlays)
LAZYINITLIST(add_overlays) //always initialized after this point
LAZYINITLIST(priority_overlays)
LAZYINITLIST(remove_overlays)
var/a_len = add_overlays.len
var/r_len = remove_overlays.len
var/p_len = priority_overlays.len
remove_overlays += overlays
add_overlays -= overlays
if(priority)
var/list/cached_priority = priority_overlays
LAZYREMOVE(cached_priority, overlays)
var/fa_len = add_overlays.len
var/fr_len = remove_overlays.len
var/fp_len = priority_overlays.len
//If not already queued and there is work to be done
if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len || fp_len != p_len))
QUEUE_FOR_COMPILE
/atom/proc/add_overlay(list/overlays, priority = FALSE)
if(!overlays)
return
overlays = build_appearance_list(overlays)
LAZYINITLIST(add_overlays) //always initialized after this point
LAZYINITLIST(priority_overlays)
var/a_len = add_overlays.len
var/p_len = priority_overlays.len
if(priority)
priority_overlays += overlays //or in the image. Can we use [image] = image?
var/fp_len = priority_overlays.len
if(NOT_QUEUED_ALREADY && fp_len != p_len)
QUEUE_FOR_COMPILE
else
add_overlays += overlays
var/fa_len = add_overlays.len
if(NOT_QUEUED_ALREADY && fa_len != a_len)
QUEUE_FOR_COMPILE
/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
if(!other)
if(cut_old)
cut_overlays()
return
var/list/cached_other = other.overlays.Copy()
if(cached_other)
if(cut_old || !LAZYLEN(overlays))
remove_overlays = overlays
add_overlays = cached_other
if(NOT_QUEUED_ALREADY)
QUEUE_FOR_COMPILE
else if(cut_old)
cut_overlays()
#undef NOT_QUEUED_ALREADY
#undef QUEUE_FOR_COMPILE
//TODO: Better solution for these?
/image/proc/add_overlay(x)
overlays |= x
/image/proc/cut_overlay(x)
overlays -= x
/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.overlays.Copy()
if(cached_other)
if(cut_old || !overlays.len)
overlays = cached_other
else
overlays |= cached_other
else if(cut_old)
cut_overlays()
@@ -1,8 +1,11 @@
var/datum/controller/process/shuttle/shuttle_master
#define CALL_SHUTTLE_REASON_LENGTH 12
var/const/CALL_SHUTTLE_REASON_LENGTH = 12
/datum/controller/process/shuttle
SUBSYSTEM_DEF(shuttle)
name = "Shuttle"
wait = 10
init_order = INIT_ORDER_SHUTTLE
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME
var/list/mobile = list()
var/list/stationary = list()
var/list/transit = list()
@@ -37,15 +40,8 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12
var/datum/round_event/shuttle_loan/shuttle_loan
var/sold_atoms = ""
/datum/controller/process/shuttle/setup()
name = "shuttle"
schedule_interval = 20
var/watch = start_watch()
log_startup_progress("Initializing shuttle docks...")
initialize_docks()
var/count = mobile.len + stationary.len + transit.len
log_startup_progress(" Initialized [count] docks in [stop_watch(watch)]s.")
/datum/controller/subsystem/shuttle/Initialize(start_timeofday)
ordernum = rand(1,9000)
if(!emergency)
WARNING("No /obj/docking_port/mobile/emergency placed on the map!")
@@ -53,8 +49,8 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12
WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!")
if(!supply)
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
ordernum = rand(1,9000)
initial_load()
for(var/typepath in subtypesof(/datum/supply_packs))
var/datum/supply_packs/P = new typepath()
@@ -62,36 +58,39 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12
supply_packs["[P.type]"] = P
initial_move()
/datum/controller/process/shuttle/doWork()
points += points_per_decisecond * schedule_interval
return ..()
/datum/controller/subsystem/shuttle/stat_entry(msg)
..("M:[mobile.len] S:[stationary.len] T:[transit.len]")
/datum/controller/subsystem/shuttle/proc/initial_load()
for(var/obj/docking_port/D in world)
D.register()
CHECK_TICK
/datum/controller/subsystem/shuttle/fire(resumed = FALSE)
points += points_per_decisecond * wait
for(var/thing in mobile)
if(thing)
var/obj/docking_port/mobile/P = thing
P.check()
continue
CHECK_TICK
mobile.Remove(thing)
DECLARE_GLOBAL_CONTROLLER(shuttle, shuttle_master)
/datum/controller/process/shuttle/proc/initialize_docks()
for(var/obj/docking_port/D in world)
D.register()
/datum/controller/process/shuttle/proc/getShuttle(id)
/datum/controller/subsystem/shuttle/proc/getShuttle(id)
for(var/obj/docking_port/mobile/M in mobile)
if(M.id == id)
return M
WARNING("couldn't find shuttle with id: [id]")
/datum/controller/process/shuttle/proc/getDock(id)
/datum/controller/subsystem/shuttle/proc/getDock(id)
for(var/obj/docking_port/stationary/S in stationary)
if(S.id == id)
return S
WARNING("couldn't find dock with id: [id]")
/datum/controller/process/shuttle/proc/requestEvac(mob/user, call_reason)
/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
if(!emergency)
WARNING("requestEvac(): There is no emergency shuttle, but the shuttle was called. Using the backup shuttle instead.")
if(!backup_shuttle)
@@ -151,19 +150,19 @@ DECLARE_GLOBAL_CONTROLLER(shuttle, shuttle_master)
// Called when an emergency shuttle mobile docking port is
// destroyed, which will only happen with admin intervention
/datum/controller/process/shuttle/proc/emergencyDeregister()
/datum/controller/subsystem/shuttle/proc/emergencyDeregister()
// When a new emergency shuttle is created, it will override the
// backup shuttle.
emergency = backup_shuttle
/datum/controller/process/shuttle/proc/cancelEvac(mob/user)
/datum/controller/subsystem/shuttle/proc/cancelEvac(mob/user)
if(canRecall())
emergency.cancel(get_area(user))
log_game("[key_name(user)] has recalled the shuttle.")
message_admins("[key_name_admin(user)] has recalled the shuttle.")
return 1
/datum/controller/process/shuttle/proc/canRecall()
/datum/controller/subsystem/shuttle/proc/canRecall()
if(emergency.mode != SHUTTLE_CALL)
return
if(!emergency.canRecall)
@@ -178,10 +177,10 @@ DECLARE_GLOBAL_CONTROLLER(shuttle, shuttle_master)
return
return 1
/datum/controller/process/shuttle/proc/autoEvac()
/datum/controller/subsystem/shuttle/proc/autoEvac()
var/callShuttle = 1
for(var/thing in shuttle_caller_list)
for(var/thing in GLOB.shuttle_caller_list)
if(istype(thing, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = thing
if(AI.stat || !AI.client)
@@ -205,7 +204,7 @@ DECLARE_GLOBAL_CONTROLLER(shuttle, shuttle_master)
message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.")
//try to move/request to dockHome if possible, otherwise dockAway. Mainly used for admin buttons
/datum/controller/process/shuttle/proc/toggleShuttle(shuttleId, dockHome, dockAway, timed)
/datum/controller/subsystem/shuttle/proc/toggleShuttle(shuttleId, dockHome, dockAway, timed)
var/obj/docking_port/mobile/M = getShuttle(shuttleId)
if(!M)
return 1
@@ -222,7 +221,7 @@ DECLARE_GLOBAL_CONTROLLER(shuttle, shuttle_master)
return 0 //dock successful
/datum/controller/process/shuttle/proc/moveShuttle(shuttleId, dockId, timed)
/datum/controller/subsystem/shuttle/proc/moveShuttle(shuttleId, dockId, timed)
var/obj/docking_port/mobile/M = getShuttle(shuttleId)
var/obj/docking_port/stationary/D = getDock(dockId)
if(!M)
@@ -235,8 +234,29 @@ DECLARE_GLOBAL_CONTROLLER(shuttle, shuttle_master)
return 2
return 0 //dock successful
/datum/controller/process/shuttle/proc/initial_move()
/datum/controller/subsystem/shuttle/proc/initial_move()
for(var/obj/docking_port/mobile/M in mobile)
if(!M.roundstart_move)
continue
M.dockRoundstart()
/datum/controller/subsystem/shuttle/proc/generateSupplyOrder(packId, _orderedby, _orderedbyRank, _comment, _crates)
if(!packId)
return
var/datum/supply_packs/P = supply_packs["[packId]"]
if(!P)
return
var/datum/supply_order/O = new()
O.ordernum = ordernum++
O.object = P
O.orderedby = _orderedby
O.orderedbyRank = _orderedbyRank
O.comment = _comment
O.crates = _crates
requestlist += O
return O
#undef CALL_SHUTTLE_REASON_LENGTH
+380
View File
@@ -0,0 +1,380 @@
//Defines
//Deciseconds until ticket becomes stale if unanswered. Alerts admins.
#define ADMIN_TICKET_TIMEOUT 6000 // 10 minutes
//Decisecions before the user is allowed to open another ticket while their existing one is open.
#define ADMIN_TICKET_DUPLICATE_COOLDOWN 3000 // 5 minutes
//Status defines
#define ADMIN_TICKET_OPEN 1
#define ADMIN_TICKET_CLOSED 2
#define ADMIN_TICKET_RESOLVED 3
#define ADMIN_TICKET_STALE 4
SUBSYSTEM_DEF(tickets)
name = "Tickets"
init_order = INIT_ORDER_TICKETS
wait = 300
priority = FIRE_PRIORITY_TICKETS
flags = SS_BACKGROUND
var/list/allTickets
var/ticketCounter = 1
/datum/controller/subsystem/tickets/Initialize()
LAZYINITLIST(allTickets)
return ..()
/datum/controller/subsystem/tickets/fire()
var/stales = checkStaleness()
if(LAZYLEN(stales))
var/report
for(var/num in stales)
report += "[num], "
message_adminTicket("<span class='adminticket'>Tickets [report] have been open for over [ADMIN_TICKET_TIMEOUT / 600] minutes. Changing status to stale.</span>")
/datum/controller/subsystem/tickets/stat_entry()
..("Tickets: [LAZYLEN(allTickets)]")
/datum/controller/subsystem/tickets/proc/checkStaleness()
var/stales = list()
for(var/T in allTickets)
var/datum/admin_ticket/ticket = T
if(!(ticket.ticketState == ADMIN_TICKET_OPEN))
continue
if(world.time > ticket.timeUntilStale && (!ticket.lastAdminResponse || !ticket.adminAssigned))
var/id = ticket.makeStale()
stales += id
return stales
//Return the current ticket number ready to be called off.
/datum/controller/subsystem/tickets/proc/getTicketCounter()
return ticketCounter
//Return the ticket counter and increment
/datum/controller/subsystem/tickets/proc/getTicketCounterAndInc()
. = ticketCounter
ticketCounter++
return
/datum/controller/subsystem/tickets/proc/resolveAllOpenTickets() // Resolve all open tickets
for(var/i in allTickets)
var/datum/admin_ticket/T = i
resolveTicket(T.ticketNum)
//Open a new ticket and populate details then add to the list of open tickets
/datum/controller/subsystem/tickets/proc/newTicket(client/C, passedContent, title)
if(!C || !passedContent)
return
//Check if the user has an open ticket already within the cooldown period, if so we don't create a new one and re-set the cooldown period
var/datum/admin_ticket/existingTicket = checkForOpenTicket(C)
if(existingTicket)
existingTicket.setCooldownPeriod()
to_chat(C.mob, "<span class='adminticket'>Your ticket #[existingTicket.ticketNum] remains open! Visit \"My tickets\" under the Admin Tab to view it.</span>")
return
if(!title)
title = passedContent
var/datum/admin_ticket/T = new(title, passedContent)
T.clientName = C
T.locationSent = C.mob.loc.name
T.mobControlled = C.mob
//Inform the user that they have opened a ticket
to_chat(C, "<span class='adminticket'>You have opened admin ticket number #[(SStickets.getTicketCounter() - 1)]! Please be patient and we will help you soon!</span>")
//Set ticket state with key N to open
/datum/controller/subsystem/tickets/proc/openTicket(N)
var/datum/admin_ticket/T = SStickets.allTickets[N]
if(T.ticketState != ADMIN_TICKET_OPEN)
T.ticketState = ADMIN_TICKET_OPEN
return TRUE
//Set ticket state with key N to resolved
/datum/controller/subsystem/tickets/proc/resolveTicket(N)
var/datum/admin_ticket/T = SStickets.allTickets[N]
if(T.ticketState != ADMIN_TICKET_RESOLVED)
T.ticketState = ADMIN_TICKET_RESOLVED
return TRUE
//Set ticket state with key N to closed
/datum/controller/subsystem/tickets/proc/closeTicket(N)
var/datum/admin_ticket/T = SStickets.allTickets[N]
if(T.ticketState != ADMIN_TICKET_CLOSED)
T.ticketState = ADMIN_TICKET_CLOSED
return TRUE
//Check if the user already has a ticket open and within the cooldown period.
/datum/controller/subsystem/tickets/proc/checkForOpenTicket(client/C)
for(var/datum/admin_ticket/T in allTickets)
if(T.clientName == C && T.ticketState == ADMIN_TICKET_OPEN && (T.ticketCooldown > world.time))
return T
return FALSE
//Check if the user has ANY ticket not resolved or closed.
/datum/controller/subsystem/tickets/proc/checkForTicket(client/C)
var/list/tickets = list()
for(var/datum/admin_ticket/T in allTickets)
if(T.clientName == C && (T.ticketState == ADMIN_TICKET_OPEN || T.ticketState == ADMIN_TICKET_STALE))
tickets += T
if(tickets.len)
return tickets
return FALSE
//return the client of a ticket number
/datum/controller/subsystem/tickets/proc/returnClient(N)
var/datum/admin_ticket/T = SStickets.allTickets[N]
return T.clientName
/datum/controller/subsystem/tickets/proc/assignAdminToTicket(client/C, var/N)
var/datum/admin_ticket/T = SStickets.allTickets[N]
T.assignAdmin(C)
return TRUE
//Single admin ticket
/datum/admin_ticket
var/ticketNum // Ticket number
var/clientName // Client which opened the ticket
var/timeOpened // Time the ticket was opened
var/title //The initial message with links
var/list/content // content of the admin help
var/lastAdminResponse // Last admin who responded
var/lastResponseTime // When the admin last responded
var/locationSent // Location the player was when they send the ticket
var/mobControlled // Mob they were controlling
var/ticketState // State of the ticket, open, closed, resolved etc
var/timeUntilStale // When the ticket goes stale
var/ticketCooldown // Cooldown before allowing the user to open another ticket.
var/adminAssigned // Admin who has assigned themselves to this ticket
/datum/admin_ticket/New(tit, cont)
title = tit
content = list()
content += cont
timeOpened = worldtime2text()
timeUntilStale = world.time + ADMIN_TICKET_TIMEOUT
setCooldownPeriod()
ticketNum = SStickets.getTicketCounterAndInc()
ticketState = ADMIN_TICKET_OPEN
SStickets.allTickets += src
//Set the cooldown period for the ticket. The time when it's created plus the defined cooldown time.
/datum/admin_ticket/proc/setCooldownPeriod()
ticketCooldown = world.time + ADMIN_TICKET_DUPLICATE_COOLDOWN
//Set the last admin who responded as the client passed as an arguement.
/datum/admin_ticket/proc/setLastAdminResponse(client/C)
lastAdminResponse = C
lastResponseTime = worldtime2text()
//Return the ticket state as a colour coded text string.
/datum/admin_ticket/proc/state2text()
switch(ticketState)
if(ADMIN_TICKET_OPEN)
return "<font color='green'>OPEN</font>"
if(ADMIN_TICKET_RESOLVED)
return "<font color='blue'>RESOLVED</font>"
if(ADMIN_TICKET_CLOSED)
return "<font color='red'>CLOSED</font>"
if(ADMIN_TICKET_STALE)
return "<font color='orange'>STALE</font>"
//Assign the client passed to var/adminAsssigned
/datum/admin_ticket/proc/assignAdmin(client/C)
if(!C)
return
adminAssigned = C
return TRUE
/datum/admin_ticket/proc/addResponse(client/C, msg)
if(C.holder)
setLastAdminResponse(C)
msg = "[C]: [msg]"
content += msg
/datum/admin_ticket/proc/makeStale()
ticketState = ADMIN_TICKET_STALE
return ticketNum
/*
UI STUFF
*/
/datum/controller/subsystem/tickets/proc/returnUI(tab = ADMIN_TICKET_OPEN)
set name = "Open Ticket Interface"
set category = "Tickets"
//dat
var/trStyle = "border-top:2px solid; border-bottom:2px solid; padding-top: 5px; padding-bottom: 5px;"
var/tdStyleleft = "border-top:2px solid; border-bottom:2px solid; width:150px; text-align:center;"
var/tdStyle = "border-top:2px solid; border-bottom:2px solid;"
var/datum/admin_ticket/ticket
var/dat
dat += "<head><style>.adminticket{border:2px solid}</style></head>"
dat += "<body><h1>Admin Tickets</h1>"
dat +="<a href='?src=[UID()];refresh=1'>Refresh</a><br /><a href='?src=[UID()];showopen=1'>Open Tickets</a><a href='?src=[UID()];showresolved=1'>Resolved Tickets</a><a href='?src=[UID()];showclosed=1'>Closed Tickets</a>"
if(tab == ADMIN_TICKET_OPEN)
dat += "<h2>Open Tickets</h2>"
dat += "<table style='width:1300px; border: 3px solid;'>"
dat +="<tr style='[trStyle]'><th style='[tdStyleleft]'>Control</th><th style='[tdStyle]'>Ticket</th></tr>"
if(tab == ADMIN_TICKET_OPEN)
for(var/T in allTickets)
ticket = T
if(ticket.ticketState == ADMIN_TICKET_OPEN || ticket.ticketState == ADMIN_TICKET_STALE)
dat += "<tr style='[trStyle]'><td style ='[tdStyleleft]'><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a> <br /> #[ticket.ticketNum] ([ticket.timeOpened]) [ticket.ticketState == ADMIN_TICKET_STALE ? "<font color='red'><b>STALE</font>" : ""] </td><td style='[tdStyle]'><b>[ticket.title]</td></tr>"
else
continue
else if(tab == ADMIN_TICKET_RESOLVED)
dat += "<h2>Resolved Tickets</h2>"
for(var/T in allTickets)
ticket = T
if(ticket.ticketState == ADMIN_TICKET_RESOLVED)
dat += "<tr style='[trStyle]'><td style ='[tdStyleleft]'><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a> <br /> #[ticket.ticketNum] ([ticket.timeOpened]) </td><td style='[tdStyle]'><b>[ticket.title]</td></tr>"
else
continue
else if(tab == ADMIN_TICKET_CLOSED)
dat += "<h2>Closed Tickets</h2>"
for(var/T in allTickets)
ticket = T
if(ticket.ticketState == ADMIN_TICKET_CLOSED)
dat += "<tr style='[trStyle]'><td style ='[tdStyleleft]'><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a> <br /> #[ticket.ticketNum] ([ticket.timeOpened]) </td><td style='[tdStyle]'><b>[ticket.title]</td></tr>"
else
continue
dat += "</table></body>"
return dat
/datum/controller/subsystem/tickets/proc/showUI(mob/user, tab)
var/dat = null
dat = returnUI(tab)
var/datum/browser/popup = new(user, "admintickets", "Admin Tickets", 1400, 600)
popup.set_content(dat)
popup.open()
/datum/controller/subsystem/tickets/proc/showDetailUI(mob/user, ticketID)
var/datum/admin_ticket/T = SStickets.allTickets[ticketID]
var/status = "[T.state2text()]"
var/dat = "<h1>Admin Tickets</h1>"
dat +="<a href='?src=[UID()];refresh=1'>Show All</a><a href='?src=[UID()];refreshdetail=[T.ticketNum]'>Refresh</a>"
dat += "<h2>Ticket #[T.ticketNum]</h2>"
dat += "<h3>[T.clientName] / [T.mobControlled] opened this ticket at [T.timeOpened] at location [T.locationSent]</h3>"
dat += "<h4>Ticket Status: <font color='red'>[status]</font>"
dat += "<table style='width:950px; border: 3px solid;'>"
dat += "<tr><td>[T.title]</td></tr>"
if(T.content.len > 1)
for(var/i = 2, i <= T.content.len, i++)
dat += "<tr><td>[T.content[i]]</td></tr>"
dat += "</table><br /><br />"
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a><a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
if(!T.adminAssigned)
dat += "No admin assigned to this ticket - <a href='?src=[UID()];assignadmin=[T.ticketNum]'>Take Ticket</a><br />"
else
dat += "[T.adminAssigned] is assigned to this Ticket. - <a href='?src=[UID()];assignadmin=[T.ticketNum]'>Take Ticket</a><br />"
if(T.lastAdminResponse)
dat += "<b>Last Admin Response:</b> [T.lastAdminResponse] at [T.lastResponseTime]"
else
dat +="<font color='red'>No Admin Response</font>"
dat += "<br /><br />"
dat += "<a href='?src=[UID()];detailclose=[T.ticketNum]'>Close Ticket</a>"
var/datum/browser/popup = new(user, "adminticketsdetail", "Admin Ticket #[T.ticketNum]", 1000, 600)
popup.set_content(dat)
popup.open()
/datum/controller/subsystem/tickets/proc/userDetailUI(mob/user)
//dat
var/tickets = checkForTicket(user.client)
var/dat
dat += "<h1>Your open tickets</h1>"
dat += "<table>"
for(var/datum/admin_ticket/T in tickets)
dat += "<tr><td><h2>Ticket #[T.ticketNum]</h2></td></tr>"
for(var/i = 1, i <= T.content.len, i++)
dat += "<tr><td>[T.content[i]]</td></tr>"
dat += "</table>"
var/datum/browser/popup = new(user, "userticketsdetail", "Tickets", 1000, 600)
popup.set_content(dat)
popup.open()
/datum/controller/subsystem/tickets/Topic(href, href_list)
if(href_list["refresh"])
showUI(usr)
return
if(href_list["refreshdetail"])
var/indexNum = text2num(href_list["refreshdetail"])
showDetailUI(usr, indexNum)
return
if(href_list["showopen"])
showUI(usr, ADMIN_TICKET_OPEN)
return
if(href_list["showresolved"])
showUI(usr, ADMIN_TICKET_RESOLVED)
return
if(href_list["showclosed"])
showUI(usr, ADMIN_TICKET_CLOSED)
return
if(href_list["details"])
var/indexNum = text2num(href_list["details"])
showDetailUI(usr, indexNum)
return
if(href_list["resolve"])
var/indexNum = text2num(href_list["resolve"])
if(SStickets.resolveTicket(indexNum))
message_adminTicket("[usr.client] / ([usr]) resolved admin ticket number [indexNum]")
to_chat(returnClient(indexNum), "<span class='adminticket'>Your admin ticket has now been resolved.</span>")
showUI(usr)
if(href_list["detailresolve"])
var/indexNum = text2num(href_list["detailresolve"])
if(SStickets.resolveTicket(indexNum))
message_adminTicket("[usr.client] / ([usr]) resolved admin ticket number [indexNum]")
to_chat(returnClient(indexNum), "<span class='adminticket'>Your admin ticket has now been resolved.</span>")
showDetailUI(usr, indexNum)
if(href_list["detailclose"])
var/indexNum = text2num(href_list["detailclose"])
if(alert("Are you sure? This will send a negative message.",,"Yes","No") != "Yes")
return
if(SStickets.closeTicket(indexNum))
message_adminTicket("[usr.client] / ([usr]) closed admin ticket number [indexNum]")
to_chat(returnClient(indexNum), "<font color='red' size='4'><b>- AdminHelp Rejected! -</b></font>")
to_chat(returnClient(indexNum), "<span class='boldmessage'>Please try to be calm, clear, and descriptive in admin helps, do not assume the admin 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>")
to_chat(returnClient(indexNum), "<span class='adminticket'>Your ticket has now been closed.</span>")
showDetailUI(usr, indexNum)
if(href_list["detailreopen"])
var/indexNum = text2num(href_list["detailreopen"])
if(SStickets.openTicket(indexNum))
message_adminTicket("[usr.client] / ([usr]) re-opened admin ticket number [indexNum]")
showDetailUI(usr, indexNum)
if(href_list["assignadmin"])
var/indexNum = text2num(href_list["assignadmin"])
if(SStickets.assignAdminToTicket(usr.client, indexNum))
message_adminTicket("[usr.client] / ([usr]) has taken ticket number [indexNum]")
to_chat(returnClient(indexNum), "<span class='adminticket'>Your ticket is being handled by [usr.client].")
showDetailUI(usr, indexNum)
+112 -106
View File
@@ -1,5 +1,5 @@
#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth)
#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN) + 1)
#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN)||BUCKET_LEN)
#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1)))
#define TIMER_ID_MAX (2**24) //max float with integer precision
@@ -10,7 +10,7 @@ SUBSYSTEM_DEF(timer)
flags = SS_TICKER|SS_NO_INIT
var/list/second_queue = list() //awe, yes, you've had first queue, but what about second queue? Contains: /datum/timedevent
var/list/second_queue = list() //awe, yes, you've had first queue, but what about second queue?
var/list/hashes = list()
var/head_offset = 0 //world.time of the first entry in the the bucket.
@@ -38,15 +38,15 @@ SUBSYSTEM_DEF(timer)
/datum/controller/subsystem/timer/fire(resumed = FALSE)
var/lit = last_invoke_tick
var/last_check = world.time - TIMER_NO_INVOKE_WARNING
var/last_check = world.time - TICKS2DS(BUCKET_LEN*1.5)
var/list/bucket_list = src.bucket_list
if(!bucket_count)
last_invoke_tick = world.time
if(lit && lit < last_check && last_invoke_warning < last_check)
if(lit && lit < last_check && head_offset < last_check && last_invoke_warning < last_check)
last_invoke_warning = world.time
var/msg = "No regular timers processed in the last [TIMER_NO_INVOKE_WARNING] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!"
var/msg = "No regular timers processed in the last [BUCKET_LEN*1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!"
message_admins(msg)
WARNING(msg)
if(bucket_auto_reset)
@@ -71,6 +71,7 @@ SUBSYSTEM_DEF(timer)
for(var/I in second_queue)
log_world(get_timer_debug_string(I))
var/cut_start_index = 1
var/next_clienttime_timer_index = 0
var/len = length(clienttime_timers)
@@ -90,11 +91,17 @@ SUBSYSTEM_DEF(timer)
ctime_timer.spent = REALTIMEOFDAY
callBack.InvokeAsync()
qdel(ctime_timer)
if(ctime_timer.flags & TIMER_LOOP)
ctime_timer.spent = 0
clienttime_timers.Insert(ctime_timer, 1)
cut_start_index++
else
qdel(ctime_timer)
if(next_clienttime_timer_index)
clienttime_timers.Cut(1,next_clienttime_timer_index+1)
clienttime_timers.Cut(cut_start_index,next_clienttime_timer_index+1)
if(MC_TICK_CHECK)
return
@@ -197,8 +204,22 @@ SUBSYSTEM_DEF(timer)
bucket_count -= length(spent)
for(var/spent_timer in spent)
qdel(spent_timer)
for(var/i in spent)
var/datum/timedevent/qtimer = i
if(QDELETED(qtimer))
bucket_count++
continue
if(!(qtimer.flags & TIMER_LOOP))
qdel(qtimer)
else
bucket_count++
qtimer.spent = 0
qtimer.bucketEject()
if(qtimer.flags & TIMER_CLIENT_TIME)
qtimer.timeToRun = REALTIMEOFDAY + qtimer.wait
else
qtimer.timeToRun = world.time + qtimer.wait
qtimer.bucketJoin()
spent.len = 0
@@ -294,6 +315,7 @@ SUBSYSTEM_DEF(timer)
var/id
var/datum/callback/callBack
var/timeToRun
var/wait
var/hash
var/list/flags
var/spent = 0 //time we ran the timer.
@@ -302,14 +324,19 @@ SUBSYSTEM_DEF(timer)
var/datum/timedevent/next
var/datum/timedevent/prev
/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash)
/datum/timedevent/New(datum/callback/callBack, wait, flags, hash)
var/static/nextid = 1
id = TIMER_ID_NULL
src.callBack = callBack
src.timeToRun = timeToRun
src.wait = wait
src.flags = flags
src.hash = hash
if(flags & TIMER_CLIENT_TIME)
timeToRun = REALTIMEOFDAY + wait
else
timeToRun = world.time + wait
if(flags & TIMER_UNIQUE)
SStimer.hashes[hash] = src
@@ -321,68 +348,15 @@ SUBSYSTEM_DEF(timer)
nextid++
SStimer.timer_id_dict[id] = src
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
if((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]")
if(callBack.object != GLOBAL_PROC)
if(callBack.object != GLOBAL_PROC && !QDESTROYING(callBack.object))
LAZYADD(callBack.object.active_timers, src)
var/list/L
if(flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if(timeToRun >= TIMER_MAX)
L = SStimer.second_queue
if(L)
//binary search sorted insert
var/cttl = length(L)
if(cttl)
var/left = 1
var/right = cttl
var/mid = (left+right) >> 1 //rounded divide by two for hedgehogs
var/datum/timedevent/item
while(left < right)
item = L[mid]
if(item.timeToRun <= timeToRun)
left = mid+1
else
right = mid
mid = (left+right) >> 1
item = L[mid]
mid = item.timeToRun > timeToRun ? mid : mid+1
L.Insert(mid, src)
else
L += src
return
//get the list of buckets
var/list/bucket_list = SStimer.bucket_list
//calculate our place in the bucket list
var/bucket_pos = BUCKET_POS(src)
//get the bucket for our tick
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
//empty bucket, we will just add ourselves
if(!bucket_head)
bucket_list[bucket_pos] = src
return
//other wise, lets do a simplified linked list add.
if(!bucket_head.prev)
bucket_head.prev = bucket_head
next = bucket_head
prev = bucket_head.prev
next.prev = src
prev.next = src
bucketJoin()
/datum/timedevent/Destroy()
..()
@@ -406,31 +380,7 @@ SUBSYSTEM_DEF(timer)
if(!spent)
spent = world.time
var/bucketpos = BUCKET_POS(src)
var/datum/timedevent/buckethead
var/list/bucket_list = SStimer.bucket_list
if(bucketpos > 0)
buckethead = bucket_list[bucketpos]
if(buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if(timeToRun < TIMER_MAX || next || prev)
SStimer.bucket_count--
else
var/l = length(SStimer.second_queue)
SStimer.second_queue -= src
if(l == length(SStimer.second_queue))
SStimer.bucket_count--
if(prev == next && next)
next.prev = null
prev.next = null
else
if(prev)
prev.next = next
if(next)
next.prev = prev
bucketEject()
else
if(prev && prev.next == src)
prev.next = next
@@ -440,6 +390,66 @@ SUBSYSTEM_DEF(timer)
prev = null
return QDEL_HINT_IWILLGC
/datum/timedevent/proc/bucketEject()
var/bucketpos = BUCKET_POS(src)
var/list/bucket_list = SStimer.bucket_list
var/list/second_queue = SStimer.second_queue
var/datum/timedevent/buckethead
if(bucketpos > 0)
buckethead = bucket_list[bucketpos]
if(buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if(timeToRun < TIMER_MAX || next || prev)
SStimer.bucket_count--
else
var/l = length(second_queue)
second_queue -= src
if(l == length(second_queue))
SStimer.bucket_count--
if(prev != next)
prev.next = next
next.prev = prev
else
if(prev)
prev.next = null
if(next)
next.prev = null
prev = next = null
/datum/timedevent/proc/bucketJoin()
var/list/L
if(flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if(timeToRun >= TIMER_MAX)
L = SStimer.second_queue
if(L)
BINARY_INSERT(src, L, datum/timedevent, timeToRun)
return
//get the list of buckets
var/list/bucket_list = SStimer.bucket_list
//calculate our place in the bucket list
var/bucket_pos = BUCKET_POS(src)
//get the bucket for our tick
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
//empty bucket, we will just add ourselves
if(!bucket_head)
bucket_list[bucket_pos] = src
return
//other wise, lets do a simplified linked list add.
if(!bucket_head.prev)
bucket_head.prev = bucket_head
next = bucket_head
prev = bucket_head.prev
next.prev = src
prev.next = src
/datum/timedevent/proc/getcallingtype()
. = "ERROR"
if(callBack.object == GLOBAL_PROC)
@@ -452,13 +462,12 @@ SUBSYSTEM_DEF(timer)
CRASH("addtimer called without a callback")
if(wait < 0)
stack_trace("addtimer called with a negative wait. Converting to 0")
stack_trace("addtimer called with a negative wait. Converting to [world.tick_lag]")
//alot of things add short timers on themselves in their destroy, we ignore those cases
if(wait >= 1 && callback && callback.object && callback.object != GLOBAL_PROC && QDELETED(callback.object))
stack_trace("addtimer called with a callback assigned to a qdeleted object")
if(callback.object != GLOBAL_PROC && QDELETED(callback.object) && !QDESTROYING(callback.object))
stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait")
wait = max(wait, 0)
wait = max(CEILING(wait, world.tick_lag), world.tick_lag)
if(wait >= INFINITY)
CRASH("Attempted to create timer with INFINITY delay")
@@ -468,9 +477,9 @@ SUBSYSTEM_DEF(timer)
if(flags & TIMER_UNIQUE)
var/list/hashlist
if(flags & TIMER_NO_HASH_WAIT)
hashlist = list(callback.object, "([callback.object.UID()])", callback.delegate, flags & TIMER_CLIENT_TIME)
hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, flags & TIMER_CLIENT_TIME)
else
hashlist = list(callback.object, "([callback.object.UID()])", callback.delegate, wait, flags & TIMER_CLIENT_TIME)
hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, wait, flags & TIMER_CLIENT_TIME)
hashlist += callback.arguments
hash = hashlist.Join("|||||||")
@@ -486,13 +495,10 @@ SUBSYSTEM_DEF(timer)
if(hash_timer.flags & TIMER_STOPPABLE)
. = hash_timer.id
return
else if(flags & TIMER_OVERRIDE)
stack_trace("TIMER_OVERRIDE used without TIMER_UNIQUE")
var/timeToRun = world.time + wait
if(flags & TIMER_CLIENT_TIME)
timeToRun = REALTIMEOFDAY + wait
var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
var/datum/timedevent/timer = new(callback, wait, flags, hash)
return timer.id
/proc/deltimer(id)
@@ -515,4 +521,4 @@ SUBSYSTEM_DEF(timer)
#undef BUCKET_LEN
#undef BUCKET_POS
#undef TIMER_MAX
#undef TIMER_ID_MAX
#undef TIMER_ID_MAX
+1 -1
View File
@@ -19,7 +19,7 @@ SUBSYSTEM_DEF(weather)
var/datum/weather/W = V
if(W.aesthetic || W.stage != MAIN_STAGE)
continue
for(var/i in living_mob_list)
for(var/i in GLOB.living_mob_list)
var/mob/living/L = i
if(W.can_weather_act(L))
W.weather_act(L)
+3 -3
View File
@@ -85,10 +85,10 @@
debug_variables(SSmobs)
feedback_add_details("admin_verb","DMob")
if("NPC AI")
debug_variables(npcai_master)
debug_variables(SSnpcai)
feedback_add_details("admin_verb","DNPCAI")
if("Shuttle")
debug_variables(shuttle_master)
debug_variables(SSshuttle)
feedback_add_details("admin_verb","DShuttle")
if("Timer")
debug_variables(SStimer)
@@ -100,7 +100,7 @@
debug_variables(space_manager)
feedback_add_details("admin_verb","DSpace")
if("Mob Hunt Server")
debug_variables(mob_hunt_server)
debug_variables(SSmob_hunt)
feedback_add_details("admin_verb","DMobHuntServer")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
+1 -1
View File
@@ -95,7 +95,7 @@ var/global/list/round_voters = list() //Keeps track of the individuals voting fo
choices = sorted_choices
//default-vote for everyone who didn't vote
if(!config.vote_no_default && choices.len)
var/non_voters = (clients.len - total_votes)
var/non_voters = (GLOB.clients.len - total_votes)
if(non_voters > 0)
if(mode == "restart")
choices["Continue Playing"] += non_voters