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:
Poojawa
2016-12-22 03:57:55 -06:00
committed by GitHub
parent f5e143a452
commit cf59ac1c3d
2215 changed files with 707445 additions and 87041 deletions
+42
View File
@@ -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
+84
View File
@@ -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"
+2 -2
View File
@@ -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,
-33
View File
@@ -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
+28 -18
View File
@@ -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"
+8 -4
View File
@@ -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)
..()
+14 -6
View File
@@ -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
+94 -43
View File
@@ -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
+1 -1
View File
@@ -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()
+52 -35
View File
@@ -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)
+50
View File
@@ -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
+20 -39
View File
@@ -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
+36 -6
View File
@@ -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
+87
View File
@@ -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
+48
View File
@@ -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)
@@ -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
+17
View File
@@ -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()
+279 -20
View File
@@ -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
+3 -2
View File
@@ -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
+44
View File
@@ -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
+37
View File
@@ -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]))
+3
View File
@@ -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]")
+124 -36
View File
@@ -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")
+11 -5
View File
@@ -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
+9 -14
View File
@@ -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)
+2 -2
View File
@@ -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)