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