Merge branch 'master' of https://github.com/PolarisSS13/Polaris into NanoUI

Conflicts:
	code/game/machinery/adv_med.dm
This commit is contained in:
SinTwo
2016-06-20 11:51:25 -04:00
552 changed files with 14848 additions and 9750 deletions

View File

@@ -3,9 +3,9 @@ language: c
sudo: false
env:
BYOND_MAJOR="509"
BYOND_MINOR="1318"
MACRO_COUNT=1004
BYOND_MAJOR="510"
BYOND_MINOR="1346"
MACRO_COUNT=987
cache:
directories:

BIN
btime.dll Normal file

Binary file not shown.

BIN
btime.so Normal file

Binary file not shown.

View File

@@ -24,9 +24,6 @@
/obj/machinery/atmospherics/unary/freezer/New()
..()
initialize_directions = dir
/obj/machinery/atmospherics/unary/freezer/map/New()
..()
circuit = new circuit(src)
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)

View File

@@ -24,9 +24,6 @@
/obj/machinery/atmospherics/unary/heater/New()
..()
initialize_directions = dir
/obj/machinery/atmospherics/unary/heater/map/New()
..()
circuit = new circuit(src)
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)

18
code/__defines/btime.dm Normal file
View File

@@ -0,0 +1,18 @@
// Comment this out if the external btime library is unavailable
#define PRECISE_TIMER_AVAILABLE
#ifdef PRECISE_TIMER_AVAILABLE
var/global/__btime__libName = "btime.[world.system_type==MS_WINDOWS?"dll":"so"]"
#define TimeOfHour (__extern__timeofhour)
#define __extern__timeofhour text2num(call(__btime__libName, "gettime")())
/hook/startup/proc/checkbtime()
try
// This will always return 1 unless the btime library cannot be accessed
if(TimeOfHour || 1) return 1
catch(var/exception/e)
log_to_dd("PRECISE_TIMER_AVAILABLE is defined in btime.dm, but calling the btime library failed: [e]")
log_to_dd("This is a fatal error. The world will now shut down.")
del(world)
#else
#define TimeOfHour (world.timeofday % 36000)
#endif

View File

@@ -35,18 +35,20 @@
#define ORGAN_BLEEDING (1<<1)
#define ORGAN_BROKEN (1<<2)
#define ORGAN_DESTROYED (1<<3)
#define ORGAN_ROBOT (1<<4)
#define ORGAN_SPLINTED (1<<5)
#define ORGAN_DEAD (1<<6)
#define ORGAN_MUTATED (1<<7)
#define ORGAN_ASSISTED (1<<8)
#define ORGAN_SPLINTED (1<<4)
#define ORGAN_DEAD (1<<5)
#define ORGAN_MUTATED (1<<6)
#define DROPLIMB_EDGE 0
#define DROPLIMB_BLUNT 1
#define DROPLIMB_BURN 2
// Damage above this value must be repaired with surgery.
#define ROBOLIMB_SELF_REPAIR_CAP 30
#define ROBOLIMB_REPAIR_CAP 30
#define ORGAN_ASSISTED 1 // Like pacemakers, not robotic
#define ORGAN_ROBOT 2 // Fully robotic, no organic parts
#define ORGAN_LIFELIKE 3 // Robotic, made to appear organic
//Germs and infections.
#define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still.

View File

@@ -50,6 +50,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define NETWORK_SECURITY "Security"
#define NETWORK_TELECOM "Tcomsat"
#define NETWORK_THUNDER "Thunderdome"
#define NETWORK_COMMUNICATORS "Communicators"
// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret")

View File

@@ -23,7 +23,7 @@
// Some arbitrary defines to be used by self-pruning global lists. (see master_controller)
#define PROCESS_KILL 26 // Used to trigger removal from a processing list.
#define MAX_GEAR_COST 10 // Used in chargen for accessory loadout limit.
#define MAX_GEAR_COST 15 // Used in chargen for accessory loadout limit.
// For secHUDs and medHUDs and variants. The number is the location of the image on the list hud_list of humans.
#define HEALTH_HUD 1 // A simple line rounding the mob's number health.

View File

@@ -26,11 +26,11 @@
#define BORGXRAY 0x4
#define BORGMATERIAL 8
#define HOSTILE_STANCE_IDLE 1
#define HOSTILE_STANCE_ALERT 2
#define HOSTILE_STANCE_ATTACK 3
#define HOSTILE_STANCE_ATTACKING 4
#define HOSTILE_STANCE_TIRED 5
#define STANCE_IDLE 1
#define STANCE_ALERT 2
#define STANCE_ATTACK 3
#define STANCE_ATTACKING 4
#define STANCE_TIRED 5
#define LEFT 1
#define RIGHT 2
@@ -185,4 +185,9 @@
#define MOB_PULL_NONE 0
#define MOB_PULL_SMALLER 1
#define MOB_PULL_SAME 2
#define MOB_PULL_LARGER 3
#define MOB_PULL_LARGER 3
//XENOBIO2 FLAGS
#define NOMUT 0
#define COLORMUT 1
#define SPECIESMUT 2

View File

@@ -11,7 +11,10 @@
#define PROCESS_DEFAULT_HANG_ALERT_TIME 600 // 60 seconds
#define PROCESS_DEFAULT_HANG_RESTART_TIME 900 // 90 seconds
#define PROCESS_DEFAULT_SCHEDULE_INTERVAL 50 // 50 ticks
#define PROCESS_DEFAULT_SLEEP_INTERVAL 2 // 2 ticks
#define PROCESS_DEFAULT_SLEEP_INTERVAL 8 // 2 ticks
#define PROCESS_DEFAULT_CPU_THRESHOLD 90 // 90%
//#define UPDATE_QUEUE_DEBUG
// SCHECK macros
// This references src directly to work around a weird bug with try/catch
#define SCHECK_EVERY(this_many_calls) if(++src.calls_since_last_scheck >= this_many_calls) sleepCheck()
#define SCHECK SCHECK_EVERY(50)

View File

@@ -12,7 +12,8 @@
#define TECH_ILLEGAL "syndicate"
#define TECH_ARCANE "arcane"
#define IMPRINTER 0x1 //For circuits. Uses glass/chemicals.
#define PROTOLATHE 0x2 //New stuff. Uses glass/metal/chemicals
#define MECHFAB 0x4 //Mechfab
#define CHASSIS 0x8 //For protolathe, but differently
#define IMPRINTER 0x0001 //For circuits. Uses glass/chemicals.
#define PROTOLATHE 0x0002 //New stuff. Uses glass/metal/chemicals
#define MECHFAB 0x0004 //Mechfab
#define CHASSIS 0x0008 //For protolathe, but differently
#define PROSFAB 0x0010 //For prosthetics fab

View File

@@ -0,0 +1 @@
var/datum/gear_tweak/color/gear_tweak_free_color_choice = new()

View File

@@ -74,7 +74,6 @@ var/global/list/GlobalPool = list()
D.Destroy()
D.ResetVars()
D.disposed = 1 //Set to stop processing while pooled
/proc/IsPooled(var/datum/D)
if(isnull(GlobalPool[D.type]))
@@ -86,7 +85,6 @@ var/global/list/GlobalPool = list()
New(arglist(args))
else
New(args)
disposed = null
/atom/movable/Prepare(args)
var/list/args_list = args

View File

@@ -248,6 +248,46 @@
. |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down.
return .
//Uses dview to quickly return mobs and objects in view,
// then adds additional mobs or objects if they are in range 'smartly',
// based on their presence in lists of players or registered objects
// Type: 1-audio, 2-visual, 0-neither
/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/type = 1)
var/list/mobs = list()
var/list/objs = list()
var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM)
var/list/hearturfs = list()
for(var/atom/movable/AM in hear)
if(ismob(AM))
mobs += AM
hearturfs += AM.locs[1]
else if(isobj(AM))
objs += AM
hearturfs += AM.locs[1]
//A list of every mob with a client
for(var/mob/M in player_list)
if(M.loc && M.locs[1] in hearturfs)
mobs |= M
else if(M.stat == DEAD)
switch(type)
if(1) //Audio messages use ghost_ears
if(M.is_preference_enabled(/datum/client_preference/ghost_ears))
mobs |= M
if(2) //Visual messages use ghost_sight
if(M.is_preference_enabled(/datum/client_preference/ghost_sight))
mobs |= M
//For objects below the top level who still want to hear
for(var/obj/O in listening_objects)
if(O.loc && O.locs[1] in hearturfs)
objs |= O
return list("mobs" = mobs, "objs" = objs)
#define SIGN(X) ((X<0)?-1:1)
proc

View File

@@ -11,6 +11,7 @@ var/global/list/human_mob_list = list() //List of all human mobs and sub-type
var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
var/global/list/listening_objects = list() //List of all objects which care about receiving messages (communicators, radios, etc)
var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
@@ -33,6 +34,8 @@ var/global/list/language_keys[0] // Table of say codes for all languages
var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check.
var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise.
var/list/mannequins_
// Posters
var/global/list/poster_designs = list()
@@ -49,45 +52,7 @@ var/global/list/facial_hair_styles_male_list = list()
var/global/list/facial_hair_styles_female_list = list()
var/global/list/skin_styles_female_list = list() //unused
//Underwear
var/global/list/underwear_top_t = list(
"Bra, Red" = "t1", "Bra, White" = "t2", "Bra, Yellow" = "t3", "Bra, Blue" = "t4", "Bra, Black" = "t5", "Lacy Bra" = "t6", "Sports Bra, Black" = "t7", "Sports Bra, White" = "t8",
"Sports Bra Alt, Black" = "t9", "Sporta Bra Alt, White" = "t10", "Bra, Baby-Blue" = "t11", "Bra, Green" = "t12", "Bra, Pink" = "t13", "Bra, Violet" = "t14",
"Lacy Bra Alt" = "t15", "Lacy Bra Alt, Violet" = "t16", "Halterneck Bra, Black" = "t17", "Halterneck Bra, Blue" = "t18", "Halterneck Bra, Green" = "t19", "Halterneck Bra, Purple" = "t20",
"Halterneck Bra, Red" = "t21", "Halterneck Bra, Teal" = "t22", "Halterneck Bra, Violet" = "t23", "Halterneck Bra, White" = "t24", "None")
var/global/list/underwear_bottom_t = list(
"Briefs, White" = "b1", "Briefs, Grey" = "b2", "Briefs, Green" = "b3", "Briefs, Blue" = "b4", "Briefs, Black" = "b5", "Boxers, Loveheart" = "b7", "Boxers, Black" = "b8",
"Boxers, Grey" = "b9", "Boxers, Green & Blue Striped" = "b10", "Panties, Red" = "b11", "Panties, White" = "b12", "Panties, Yellow" = "b13", "Panties, Blue" = "b14",
"Panties, Light-Black" = "b15", "Thong" = "b16", "Panties, Black" = "b17", "Panties Alt, White" = "b18", "Compression Shorts, Black" = "b19", "Compression Shorts, White" = "b20",
"Compression Shorts, Baby-Blue" = "b21", "Panties, Green" = "b22", "Compression Shorts, Pink" = "b23", "Thong, Violet" = "b24", "Thong Alt" = "b25", "Thong Alt, Violet" = "b26",
"Alt Thong, Black" = "b27", "Alt Thong, Blue" = "b28", "Alt Thong, Green" = "b29", "Alt Thong, Purple" = "b30", "Alt Thong, Red" = "b31", "Alt Thong, Teal" = "b32",
"Alt Thong, Violet" = "b33", "Alt Thong, White" = "b34", "None")
//undershirt
var/global/list/undershirt_t = list(
"White tank top" = "u1", "Black tank top" = "u2", "Black shirt" = "u3",
"White shirt" = "u4", "White shirt 2" = "shirt_white_s", "White tank top 2" = "tank_white_s",
"Black shirt 2" = "shirt_black_s", "Grey shirt" = "shirt_grey_s", "Heart shirt" = "lover_s",
"I love NT shirt" = "ilovent_s", "White shortsleeve shirt" = "whiteshortsleeve_s", "Purple shortsleeve shirt" = "purpleshortsleeve_s",
"Blue shortsleeve shirt" = "blueshortsleeve_s", "Green shortsleeve shirt" = "greenshortsleeve_s", "Black shortsleeve shirt" = "blackshortsleeve_s",
"Blue shirt" = "blueshirt_s", "Red shirt" = "redshirt_s", "Yellow shirt" = "yellowshirt_s", "Green shirt" = "greenshirt_s",
"Blue polo shirt" = "bluepolo_s", "Red polo shirt" = "redpolo_s", "White polo shirt" = "whitepolo_s",
"Grey-yellow polo shirt" = "grayyellowpolo_s", "Fire tank top" = "tank_fire_s", "NT shirt" = "shirt_nano_s",
"Blue shirt 2" = "shirt_blue_s", "Red shirt 2" = "shirt_red_s", "Red tank top" = "tank_red_s", "Green shirt 2" = "shirt_green_s",
"Tiedye shirt" = "shirt_tiedye_s", "Green sport shirt" = "greenshirtsport_s", "Red sport shirt" = "redshirtsport_s",
"Blue striped shirt" = "shirt_stripes_s", "Blue sport shirt" = "blueshirtsport_s", "None")
//Socks
var/global/list/socks_t = list(
"White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee",
"White thigh" = "white_thigh", "Black normal" = "black_norm", "Black short" = "black_short",
"Black knee" = "black_knee", "Black thigh" = "black_thigh", "Thin knee" = "thin_knee",
"Thin thigh" = "thin_thigh", "Pantyhose" = "pantyhose", "Striped thigh" = "striped_thigh",
"Striped knee" = "striped_knee", "Rainbow knee" = "rainbow_knee", "Rainbow thigh" = "rainbow_thigh",
"Fishnets" = "fishnet", "Thin white thigh" = "thinwhite_thigh", "Thin white knee" = "thinwhite_knee",
"Green striped thigh" = "gstriped_thigh", "Green striped knee" = "gstriped_knee",
"Purple striped thigh" = "pstriped_thigh", "Purple striped knee" = "pstriped_knee",
"Blue striped thigh" = "bstriped_thigh", "Blue striped knee" = "bstriped_knee",
"Yellow striped thigh" = "ystriped_thigh", "Yellow striped knee" = "ystriped_knee",
"Red striped thigh" = "rstriped_thigh", "Red striped knee" = "rstriped_knee",
"Orange striped thigh" = "ostriped_thigh", "Orange striped knee" = "ostriped_knee", "None")
var/datum/category_collection/underwear/global_underwear = new()
//Backpacks
var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt")
@@ -137,6 +102,14 @@ var/global/list/string_slot_flags = list(
"holster" = SLOT_HOLSTER
)
/proc/get_mannequin(var/ckey)
if(!mannequins_)
mannequins_ = new()
. = mannequins_[ckey]
if(!.)
. = new/mob/living/carbon/human/dummy/mannequin()
mannequins_[ckey] = .
//////////////////////////
/////Initial Building/////
//////////////////////////
@@ -231,3 +204,5 @@ var/global/list/string_slot_flags = list(
. += " has: [t]\n"
world << .
*/
//Hexidecimal numbers
var/global/list/hexNums = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")

View File

@@ -602,13 +602,13 @@ proc/dd_sortedTextList(list/incoming)
/datum/alarm/dd_SortValue()
return "[sanitize_old(last_name)]"
/proc/subtypes(prototype)
/proc/subtypesof(prototype)
return (typesof(prototype) - prototype)
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L)) L = list()
for(var/path in subtypes(prototype))
for(var/path in subtypesof(prototype))
L += new path()
return L

View File

@@ -25,7 +25,6 @@
if (config.log_admin)
diary << "\[[time_stamp()]]ADMIN: [text][log_end]"
/proc/log_debug(text)
if (config.log_debug)
diary << "\[[time_stamp()]]DEBUG: [text][log_end]"
@@ -34,7 +33,6 @@
if(C.is_preference_enabled(/datum/client_preference/debug/show_debug_logs))
C << "DEBUG: [text]"
/proc/log_game(text)
if (config.log_game)
diary << "\[[time_stamp()]]GAME: [text][log_end]"
@@ -79,6 +77,11 @@
if (config.log_pda)
diary << "\[[time_stamp()]]PDA: [text][log_end]"
/proc/log_to_dd(text)
world.log << text //this comes before the config check because it can't possibly runtime
if(config.log_world_output)
diary << "\[[time_stamp()]]DD_OUTPUT: [text][log_end]"
/proc/log_misc(text)
diary << "\[[time_stamp()]]MISC: [text][log_end]"

View File

@@ -1039,10 +1039,9 @@ proc/get_mob_with_client_list()
//gets the turf the atom is located in (or itself, if it is a turf).
//returns null if the atom is not in a turf.
/proc/get_turf(atom/A)
if(!istype(A)) return
for(A, A && !isturf(A), A=A.loc);
return A
/proc/get_turf(atom/movable/A)
if(isturf(A)) return A
if(A && A.locs.len) return A.locs[1]
/proc/get(atom/loc, type)
while(loc)
@@ -1258,7 +1257,7 @@ var/list/WALLITEMS = list(
arglist = list2params(arglist)
return "<a href='?src=\ref[D];[arglist]'>[content]</a>"
/proc/get_random_colour(var/simple, var/lower, var/upper)
/proc/get_random_colour(var/simple, var/lower=0, var/upper=255)
var/colour
if(simple)
colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))

View File

@@ -36,3 +36,7 @@
#define issilicon(A) istype(A, /mob/living/silicon)
#define isslime(A) istype(A, /mob/living/carbon/slime)
#define isxeno(A) istype(A, /mob/living/simple_animal/xeno)
#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")

View File

@@ -0,0 +1 @@
#define CLICKCATCHER_PLANE -99

View File

@@ -321,11 +321,19 @@
facedir(direction)
/obj/screen/click_catcher
icon = 'icons/mob/screen1_full.dmi'
icon_state = "passage0"
layer = 0
icon = 'icons/mob/screen_gen.dmi'
icon_state = "click_catcher"
plane = CLICKCATCHER_PLANE
mouse_opacity = 2
screen_loc = "1,1"
screen_loc = "CENTER-7,CENTER-7"
/obj/screen/click_catcher/proc/MakeGreed()
. = list()
for(var/i = 0, i<15, i++)
for(var/j = 0, j<15, j++)
var/obj/screen/click_catcher/CC = new()
CC.screen_loc = "NORTH-[i],EAST-[j]"
. += CC
/obj/screen/click_catcher/Click(location, control, params)
var/list/modifiers = params2list(params)
@@ -333,6 +341,6 @@
var/mob/living/carbon/C = usr
C.swap_hand()
else
var/turf/T = screen_loc2turf(modifiers["screen-loc"], get_turf(usr))
var/turf/T = screen_loc2turf("screen-loc", get_turf(usr))
T.Click(location, control, params)
return 1
. = 1

View File

@@ -21,20 +21,6 @@
mymob.healths.name = "health"
mymob.healths.screen_loc = ui_alien_health
mymob.blind = new /obj/screen()
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
mymob.blind.icon_state = "blackimageoverlay"
mymob.blind.name = " "
mymob.blind.screen_loc = "1,1"
mymob.blind.layer = 0
mymob.flash = new /obj/screen()
mymob.flash.icon = 'icons/mob/screen1_alien.dmi'
mymob.flash.icon_state = "blank"
mymob.flash.name = "flash"
mymob.flash.screen_loc = ui_entire_screen
mymob.flash.layer = 17
mymob.fire = new /obj/screen()
mymob.fire.icon = 'icons/mob/screen1_alien.dmi'
mymob.fire.icon_state = "fire0"
@@ -42,6 +28,6 @@
mymob.fire.screen_loc = ui_fire
mymob.client.screen = list()
mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach )
mymob.client.screen += list( mymob.healths, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach )
mymob.client.screen += src.adding + src.other
mymob.client.screen += mymob.client.void

View File

@@ -0,0 +1,118 @@
#define FULLSCREEN_LAYER 18
#define DAMAGE_LAYER FULLSCREEN_LAYER + 0.1
#define BLIND_LAYER DAMAGE_LAYER + 0.1
#define CRIT_LAYER BLIND_LAYER + 0.1
/mob
var/list/screens = list()
/mob/proc/set_fullscreen(condition, screen_name, screen_type, arg)
condition ? overlay_fullscreen(screen_name, screen_type, arg) : clear_fullscreen(screen_name)
/mob/proc/overlay_fullscreen(category, type, severity)
var/obj/screen/fullscreen/screen = screens[category]
if(screen)
if(screen.type != type)
clear_fullscreen(category, FALSE)
screen = null
else if(!severity || severity == screen.severity)
return null
if(!screen)
screen = PoolOrNew(type)
screen.icon_state = "[initial(screen.icon_state)][severity]"
screen.severity = severity
screens[category] = screen
if(client && stat != DEAD)
client.screen += screen
return screen
/mob/proc/clear_fullscreen(category, animated = 10)
var/obj/screen/fullscreen/screen = screens[category]
if(!screen)
return
screens -= category
if(animated)
spawn(0)
animate(screen, alpha = 0, time = animated)
sleep(animated)
if(client)
client.screen -= screen
qdel(screen)
else
if(client)
client.screen -= screen
qdel(screen)
/mob/proc/clear_fullscreens()
for(var/category in screens)
clear_fullscreen(category)
/mob/proc/hide_fullscreens()
if(client)
for(var/category in screens)
client.screen -= screens[category]
/mob/proc/reload_fullscreen()
if(client && stat != DEAD) //dead mob do not see any of the fullscreen overlays that he has.
for(var/category in screens)
client.screen |= screens[category]
/obj/screen/fullscreen
icon = 'icons/mob/screen_full.dmi'
icon_state = "default"
screen_loc = "CENTER-7,CENTER-7"
layer = FULLSCREEN_LAYER
mouse_opacity = 0
var/severity = 0
/obj/screen/fullscreen/Destroy()
severity = 0
return ..()
/obj/screen/fullscreen/brute
icon_state = "brutedamageoverlay"
layer = DAMAGE_LAYER
/obj/screen/fullscreen/oxy
icon_state = "oxydamageoverlay"
layer = DAMAGE_LAYER
/obj/screen/fullscreen/crit
icon_state = "passage"
layer = CRIT_LAYER
/obj/screen/fullscreen/blind
icon_state = "blackimageoverlay"
layer = BLIND_LAYER
/obj/screen/fullscreen/impaired
icon_state = "impairedoverlay"
/obj/screen/fullscreen/blurry
icon = 'icons/mob/screen1.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "blurry"
/obj/screen/fullscreen/flash
icon = 'icons/mob/screen1.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
/obj/screen/fullscreen/flash/noise
icon_state = "noise"
/obj/screen/fullscreen/high
icon = 'icons/mob/screen1.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "druggy"
#undef FULLSCREEN_LAYER
#undef BLIND_LAYER
#undef DAMAGE_LAYER
#undef CRIT_LAYER

View File

@@ -6,12 +6,14 @@ var/datum/global_hud/global_hud = new()
var/list/global_huds = list(
global_hud.druggy,
global_hud.blurry,
global_hud.whitense,
global_hud.vimpaired,
global_hud.darkMask,
global_hud.nvg,
global_hud.thermal,
global_hud.meson,
global_hud.science)
global_hud.science
)
/datum/hud/var/obj/screen/grab_intent
/datum/hud/var/obj/screen/hurt_intent
@@ -21,6 +23,7 @@ var/list/global_huds = list(
/datum/global_hud
var/obj/screen/druggy
var/obj/screen/blurry
var/obj/screen/whitense
var/list/vimpaired
var/list/darkMask
var/obj/screen/nvg
@@ -53,6 +56,14 @@ var/list/global_huds = list(
blurry.layer = 17
blurry.mouse_opacity = 0
//static overlay effect for cameras and the like
whitense = new /obj/screen()
whitense.screen_loc = ui_entire_screen
whitense.icon = 'icons/effects/static.dmi'
whitense.icon_state = "1 light"
whitense.layer = 17
whitense.mouse_opacity = 0
nvg = setup_overlay("nvg_hud")
thermal = setup_overlay("thermal_hud")
meson = setup_overlay("meson_hud")
@@ -258,7 +269,7 @@ datum/hud/New(mob/owner)
else if(isrobot(mymob))
robot_hud(ui_style, ui_color, ui_alpha, mymob)
else if(isbrain(mymob))
brain_hud(ui_style)
mymob.instantiate_hud(src)
else if(isalien(mymob))
larva_hud()
else if(isslime(mymob))
@@ -371,3 +382,9 @@ datum/hud/New(mob/owner)
hud_used.hidden_inventory_update()
hud_used.persistant_inventory_update()
update_action_buttons()
/mob/proc/add_click_catcher()
client.screen += client.void
/mob/new_player/add_click_catcher()
return

View File

@@ -303,32 +303,6 @@
mymob.ling_chem_display.icon_state = "ling_chems"
hud_elements |= mymob.ling_chem_display
mymob.blind = new /obj/screen()
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
mymob.blind.icon_state = "blackimageoverlay"
mymob.blind.name = " "
mymob.blind.screen_loc = "1,1"
mymob.blind.mouse_opacity = 0
mymob.blind.layer = 0
hud_elements |= mymob.blind
mymob.damageoverlay = new /obj/screen()
mymob.damageoverlay.icon = 'icons/mob/screen1_full.dmi'
mymob.damageoverlay.icon_state = "oxydamageoverlay0"
mymob.damageoverlay.name = "dmg"
mymob.damageoverlay.screen_loc = "1,1"
mymob.damageoverlay.mouse_opacity = 0
mymob.damageoverlay.layer = 18.1 //The black screen overlay sets layer to 18 to display it, this one has to be just on top.
hud_elements |= mymob.damageoverlay
mymob.flash = new /obj/screen()
mymob.flash.icon = ui_style
mymob.flash.icon_state = "blank"
mymob.flash.name = "flash"
mymob.flash.screen_loc = ui_entire_screen
mymob.flash.layer = 17
hud_elements |= mymob.flash
mymob.pain = new /obj/screen( null )
mymob.zone_sel = new /obj/screen/zone_sel( null )
@@ -366,7 +340,7 @@
mymob.client.screen += hud_elements
mymob.client.screen += src.adding + src.hotkeybuttons
mymob.client.screen += mymob.client.void
inventory_shown = 0;
inventory_shown = 0
return
@@ -388,10 +362,7 @@
f_style = "Shaved"
if(dna.species == "Human") //no more xenos losing ears/tentacles
h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3")
undershirt = null
underwear_top = null
underwear_bottom = null
socks = null
all_underwear.Cut()
regenerate_icons()
/obj/screen/ling

View File

@@ -5,14 +5,6 @@
/datum/hud/proc/ghost_hud()
return
/datum/hud/proc/brain_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
mymob.blind = new /obj/screen()
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
mymob.blind.icon_state = "blackimageoverlay"
mymob.blind.name = " "
mymob.blind.screen_loc = "1,1"
mymob.blind.layer = 0
/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
blobpwrdisplay = new /obj/screen()
@@ -116,13 +108,6 @@
else if(istype(mymob,/mob/living/simple_animal/construct/harvester))
constructtype = "harvester"
mymob.flash = new /obj/screen()
mymob.flash.icon = 'icons/mob/screen1.dmi'
mymob.flash.icon_state = "blank"
mymob.flash.name = "flash"
mymob.flash.screen_loc = ui_entire_screen
mymob.flash.layer = 17
if(constructtype)
mymob.fire = new /obj/screen()
mymob.fire.icon = 'icons/mob/screen1_construct.dmi'
@@ -155,5 +140,5 @@
mymob.client.screen = list()
mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged, mymob.flash)
mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged)
mymob.client.screen += mymob.client.void

View File

@@ -173,21 +173,6 @@ var/obj/screen/robot_inventory
mymob.pullin.screen_loc = ui_borg_pull
src.other += mymob.pullin
mymob.blind = new /obj/screen()
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
mymob.blind.icon_state = "blackimageoverlay"
mymob.blind.name = " "
mymob.blind.screen_loc = "1,1"
mymob.blind.layer = 0
mymob.flash = new /obj/screen()
mymob.flash.icon = ui_style
mymob.flash.icon_state = "blank"
mymob.flash.name = "flash"
mymob.flash.screen_loc = ui_entire_screen
mymob.flash.layer = 17
src.other += mymob.flash
mymob.zone_sel = new /obj/screen/zone_sel()
mymob.zone_sel.icon = ui_style
mymob.zone_sel.alpha = ui_alpha
@@ -210,7 +195,7 @@ var/obj/screen/robot_inventory
mymob.client.screen = list()
mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, robot_inventory, mymob.gun_setting_icon)
mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, robot_inventory, mymob.gun_setting_icon)
mymob.client.screen += src.adding + src.other
mymob.client.screen += mymob.client.void

View File

@@ -1,40 +1,59 @@
/*
=== Item Click Call Sequences ===
These are the default click code call sequences used when clicking on stuff with an item.
Atoms:
mob/ClickOn() calls the item's resolve_attackby() proc.
item/resolve_attackby() calls the target atom's attackby() proc.
Mobs:
mob/living/attackby() after checking for surgery, calls the item's attack() proc.
item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself.
mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit.
Item Hit Effects:
item/apply_hit_effect() can be overriden to do whatever you want. However "standard" physical damage based weapons should make use of the target mob's hit_with_weapon() proc to
avoid code duplication. This includes items that may sometimes act as a standard weapon in addition to having other effects (e.g. stunbatons on harm intent).
*/
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
/obj/item/proc/attack_self(mob/user)
return
//I would prefer to rename this to attack(), but that would involve touching hundreds of files.
/obj/item/proc/resolve_attackby(atom/A, mob/user)
add_fingerprint(user)
return A.attackby(src, user)
// No comment
/atom/proc/attackby(obj/item/W, mob/user)
return
/atom/movable/attackby(obj/item/W, mob/user)
if(!(W.flags&NOBLUDGEON))
if(!(W.flags & NOBLUDGEON))
visible_message("<span class='danger'>[src] has been hit by [user] with [W].</span>")
/mob/living/attackby(obj/item/I, mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(I) && ismob(user))
I.attack(src, user)
if(!ismob(user))
return 0
if(can_operate(src) && I.do_surgery(src,user)) //Surgery
return 1
return I.attack(src, user, user.zone_sel.selecting)
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
return
//TODO: refactor mob attack code.
/*
Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here.
leave attackby() as handling the general case of "using an item on a mob"
attackby() will decide to call attacked_by() or not.
attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm"
attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing.
attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now).
*/
/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0
//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files.
/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone)
if(!force || (flags & NOBLUDGEON))
return 0
if(M == user && user.a_intent != I_HURT)
return 0
/////////////////////////
user.lastattacked = M
@@ -46,50 +65,22 @@ attacked_by() will handle hitting/missing/logging as it does now, and will call
msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
/////////////////////////
// Attacking someone with a weapon while they are neck-grabbed
if(user.a_intent == I_HURT)
for(var/obj/item/weapon/grab/G in M.grabbed_by)
if(G.assailant == user && G.state >= GRAB_NECK)
M.attack_throat(src, G, user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
user.do_attack_animation(M)
var/hit_zone = M.resolve_item_attack(src, user, target_zone)
if(hit_zone)
apply_hit_effect(M, user, hit_zone)
return 1
//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result
/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
if(hitsound)
playsound(loc, hitsound, 50, 1, -1)
var/power = force
if(HULK in user.mutations)
power *= 2
return target.hit_with_weapon(src, user, power, hit_zone)
// TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z
user.do_attack_animation(M)
user.break_cloak()
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
// Handle striking to cripple.
var/dislocation_str
if(user.a_intent == I_DISARM)
dislocation_str = H.attack_joint(src, user, def_zone)
if(H.attacked_by(src, user, def_zone) && hitsound)
playsound(loc, hitsound, 50, 1, -1)
spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves.
if(dislocation_str) user.visible_message("<span class='danger'>[dislocation_str]</span>")
return 1
return 0
else
if(attack_verb.len)
user.visible_message("<span class='danger'>[M] has been [pick(attack_verb)] with [src] by [user]!</span>")
else
user.visible_message("<span class='danger'>[M] has been attacked with [src] by [user]!</span>")
if (hitsound)
playsound(loc, hitsound, 50, 1, -1)
switch(damtype)
if("brute")
M.take_organ_damage(power)
if(prob(33)) // Added blood for whacking non-humans too
var/turf/simulated/location = get_turf(M)
if(istype(location)) location.add_blood_floor(M)
if("fire")
if (!(COLD_RESISTANCE in M.mutations))
M.take_organ_damage(0, power)
M << "Aargh it burns!"
M.updatehealth()
add_fingerprint(user)
return 1

View File

@@ -1,32 +0,0 @@
// DM Environment file for ProcessScheduler.dme.
// All manual changes should be made outside the BEGIN_ and END_ blocks.
// New source code should be placed in .dm files: choose File/New --> Code File.
// BEGIN_INTERNALS
// END_INTERNALS
// BEGIN_FILE_DIR
#define FILE_DIR .
// END_FILE_DIR
// BEGIN_PREFERENCES
// END_PREFERENCES
// BEGIN_INCLUDE
#include "core\_define.dm"
#include "core\_stubs.dm"
#include "core\process.dm"
#include "core\processScheduler.dm"
#include "core\updateQueue.dm"
#include "core\updateQueueWorker.dm"
#include "test\processSchedulerView.dm"
#include "test\testDyingUpdateQueueProcess.dm"
#include "test\testHarness.dm"
#include "test\testHungProcess.dm"
#include "test\testNiceProcess.dm"
#include "test\testSlowProcess.dm"
#include "test\testUpdateQueue.dm"
#include "test\testUpdateQueueProcess.dm"
#include "test\testZombieProcess.dm"
// END_INCLUDE

View File

@@ -4,15 +4,7 @@
* This file contains constructs that the process scheduler expects to exist
* in a standard ss13 fork.
*/
/*
/**
* message_admins
*
* sends a message to admins
*/
/proc/message_admins(msg)
world << msg
*/
/**
* logTheThing
*
@@ -22,17 +14,6 @@
*/
/proc/logTheThing(type, source, target, text, diaryType)
if(diaryType)
world << "Diary: \[[diaryType]:[type]] [text]"
log_debug("Diary: \[[diaryType]:[type]] [text]")
else
world << "Log: \[[type]] [text]"
/**
* var/disposed
*
* In goonstation, disposed is set to 1 after an object enters the delete queue
* or the object is placed in an object pool (effectively out-of-play so to speak)
*/
/datum/var/disposed
// Garbage collection (controller).
/datum/var/gcDestroyed
/datum/var/timeDestroyed
log_debug("Log: \[[type]] [text]")

View File

@@ -48,7 +48,7 @@
// This controls how often the process will yield (call sleep(0)) while it is running.
// Every concurrent process should sleep periodically while running in order to allow other
// processes to execute concurrently.
var/tmp/sleep_interval = PROCESS_DEFAULT_SLEEP_INTERVAL
var/tmp/sleep_interval
// hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window
var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME
@@ -59,20 +59,20 @@
// hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process.
var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME
// cpu_threshold - if world.cpu >= cpu_threshold, scheck() will call sleep(1) to defer further work until the next tick. This keeps a process from driving a tick into overtime (causing perceptible lag)
var/tmp/cpu_threshold = PROCESS_DEFAULT_CPU_THRESHOLD
// How many times in the current run has the process deferred work till the next tick?
var/tmp/cpu_defer_count = 0
// How many SCHECKs have been skipped (to limit btime calls)
var/tmp/calls_since_last_scheck = 0
/**
* recordkeeping vars
*/
// Records the time (server ticks) at which the process last finished sleeping
// Records the time (1/10s timeofday) at which the process last finished sleeping
var/tmp/last_slept = 0
// Records the time (s-ticks) at which the process last began running
// Records the time (1/10s timeofday) at which the process last began running
var/tmp/run_start = 0
// Records the number of times this process has been killed and restarted
@@ -85,26 +85,33 @@
var/tmp/last_object
datum/controller/process/New(var/datum/controller/processScheduler/scheduler)
// Counts the number of times an exception has occurred; gets reset after 10
var/tmp/list/exceptions = list()
// Number of deciseconds to delay before starting the process
var/start_delay = 0
/datum/controller/process/New(var/datum/controller/processScheduler/scheduler)
..()
main = scheduler
previousStatus = "idle"
idle()
name = "process"
schedule_interval = 50
sleep_interval = 2
sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL
last_slept = 0
run_start = 0
ticks = 0
last_task = 0
last_object = null
datum/controller/process/proc/started()
/datum/controller/process/proc/started()
var/timeofhour = TimeOfHour
// Initialize last_slept so we can know when to sleep
last_slept = world.timeofday
last_slept = timeofhour
// Initialize run_start so we can detect hung processes.
run_start = world.timeofday
run_start = timeofhour
// Initialize defer count
cpu_defer_count = 0
@@ -114,65 +121,65 @@ datum/controller/process/proc/started()
onStart()
datum/controller/process/proc/finished()
/datum/controller/process/proc/finished()
ticks++
idle()
main.processFinished(src)
onFinish()
datum/controller/process/proc/doWork()
/datum/controller/process/proc/doWork()
datum/controller/process/proc/setup()
/datum/controller/process/proc/setup()
datum/controller/process/proc/process()
/datum/controller/process/proc/process()
started()
doWork()
finished()
datum/controller/process/proc/running()
/datum/controller/process/proc/running()
idle = 0
queued = 0
running = 1
hung = 0
setStatus(PROCESS_STATUS_RUNNING)
datum/controller/process/proc/idle()
/datum/controller/process/proc/idle()
queued = 0
running = 0
idle = 1
hung = 0
setStatus(PROCESS_STATUS_IDLE)
datum/controller/process/proc/queued()
/datum/controller/process/proc/queued()
idle = 0
running = 0
queued = 1
hung = 0
setStatus(PROCESS_STATUS_QUEUED)
datum/controller/process/proc/hung()
/datum/controller/process/proc/hung()
hung = 1
setStatus(PROCESS_STATUS_HUNG)
datum/controller/process/proc/handleHung()
/datum/controller/process/proc/handleHung()
var/timeofhour = TimeOfHour
var/datum/lastObj = last_object
var/lastObjType = "null"
if(istype(lastObj))
lastObjType = lastObj.type
// If world.timeofday has rolled over, then we need to adjust.
if (world.timeofday < run_start)
run_start -= 864000
var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(world.timeofday - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]"
// If timeofhour has rolled over, then we need to adjust.
if (timeofhour < run_start)
run_start -= 36000
var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(timeofhour - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]"
logTheThing("debug", null, null, msg)
logTheThing("diary", null, null, msg, "debug")
message_admins(msg)
main.restartProcess(src.name)
datum/controller/process/proc/kill()
/datum/controller/process/proc/kill()
if (!killed)
var/msg = "[name] process was killed at tick #[ticks]."
logTheThing("debug", null, null, msg)
@@ -182,59 +189,68 @@ datum/controller/process/proc/kill()
// Allow inheritors to clean up if needed
onKill()
killed = TRUE
// This should del
del(src)
del(src) // This should del
datum/controller/process/proc/scheck(var/tickId = 0)
// Do not call this directly - use SHECK or SCHECK_EVERY
/datum/controller/process/proc/sleepCheck(var/tickId = 0)
calls_since_last_scheck = 0
if (killed)
// The kill proc is the only place where killed is set.
// The kill proc should have deleted this datum, and all sleeping procs that are
// owned by it.
CRASH("A killed process is still running somehow...")
if (hung)
// This will only really help if the doWork proc ends up in an infinite loop.
handleHung()
CRASH("Process [name] hung and was restarted.")
// For each tick the process defers, it increments the cpu_defer_count so we don't
// defer indefinitely
if (world.cpu >= cpu_threshold + cpu_defer_count * 10)
sleep(1)
if (main.getCurrentTickElapsedTime() > main.timeAllowance)
sleep(world.tick_lag)
cpu_defer_count++
last_slept = world.timeofday
last_slept = TimeOfHour
else
// If world.timeofday has rolled over, then we need to adjust.
if (world.timeofday < last_slept)
last_slept -= 864000
var/timeofhour = TimeOfHour
// If timeofhour has rolled over, then we need to adjust.
if (timeofhour < last_slept)
last_slept -= 36000
if (world.timeofday > last_slept + sleep_interval)
// If we haven't slept in sleep_interval ticks, sleep to allow other work to proceed.
if (timeofhour > last_slept + sleep_interval)
// If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed.
sleep(0)
last_slept = world.timeofday
last_slept = TimeOfHour
datum/controller/process/proc/update()
/datum/controller/process/proc/update()
// Clear delta
if(previousStatus != status)
setStatus(status)
var/elapsedTime = getElapsedTime()
if (elapsedTime > hang_restart_time)
if (hung)
handleHung()
return
else if (elapsedTime > hang_restart_time)
hung()
else if (elapsedTime > hang_alert_time)
setStatus(PROCESS_STATUS_PROBABLY_HUNG)
else if (elapsedTime > hang_warning_time)
setStatus(PROCESS_STATUS_MAYBE_HUNG)
datum/controller/process/proc/getElapsedTime()
if (world.timeofday < run_start)
return world.timeofday - (run_start - 864000)
return world.timeofday - run_start
datum/controller/process/proc/tickDetail()
/datum/controller/process/proc/getElapsedTime()
var/timeofhour = TimeOfHour
if (timeofhour < run_start)
return timeofhour - (run_start - 36000)
return timeofhour - run_start
/datum/controller/process/proc/tickDetail()
return
datum/controller/process/proc/getContext()
/datum/controller/process/proc/getContext()
return "<tr><td>[name]</td><td>[main.averageRunTime(src)]</td><td>[main.last_run_time[src]]</td><td>[main.highest_run_time[src]]</td><td>[ticks]</td></tr>\n"
datum/controller/process/proc/getContextData()
/datum/controller/process/proc/getContextData()
return list(
"name" = name,
"averageRunTime" = main.averageRunTime(src),
@@ -246,10 +262,10 @@ datum/controller/process/proc/getContextData()
"disabled" = disabled
)
datum/controller/process/proc/getStatus()
/datum/controller/process/proc/getStatus()
return status
datum/controller/process/proc/getStatusText(var/s = 0)
/datum/controller/process/proc/getStatusText(var/s = 0)
if(!s)
s = status
switch(s)
@@ -268,21 +284,21 @@ datum/controller/process/proc/getStatusText(var/s = 0)
else
return "UNKNOWN"
datum/controller/process/proc/getPreviousStatus()
/datum/controller/process/proc/getPreviousStatus()
return previousStatus
datum/controller/process/proc/getPreviousStatusText()
/datum/controller/process/proc/getPreviousStatusText()
return getStatusText(previousStatus)
datum/controller/process/proc/setStatus(var/newStatus)
/datum/controller/process/proc/setStatus(var/newStatus)
previousStatus = status
status = newStatus
datum/controller/process/proc/setLastTask(var/task, var/object)
/datum/controller/process/proc/setLastTask(var/task, var/object)
last_task = task
last_object = object
datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target)
/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target)
main = target.main
name = target.name
schedule_interval = target.schedule_interval
@@ -295,28 +311,62 @@ datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target
last_object = target.last_object
copyStateFrom(target)
datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target)
/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target)
datum/controller/process/proc/onKill()
/datum/controller/process/proc/onKill()
datum/controller/process/proc/onStart()
/datum/controller/process/proc/onStart()
datum/controller/process/proc/onFinish()
/datum/controller/process/proc/onFinish()
datum/controller/process/proc/disable()
/datum/controller/process/proc/disable()
disabled = 1
datum/controller/process/proc/enable()
/datum/controller/process/proc/enable()
disabled = 0
/datum/controller/process/proc/getAverageRunTime()
return main.averageRunTime(src)
/datum/controller/process/proc/getLastRunTime()
return main.getProcessLastRunTime(src)
/datum/controller/process/proc/getHighestRunTime()
return main.getProcessHighestRunTime(src)
/datum/controller/process/proc/getTicks()
return ticks
/datum/controller/process/proc/getStatName()
return name
/datum/controller/process/proc/statProcess()
var/averageRunTime = round(getAverageRunTime(), 0.1)/10
var/lastRunTime = round(getLastRunTime(), 0.1)/10
var/highestRunTime = round(getHighestRunTime(), 0.1)/10
stat("[name]", "T#[getTicks()] | AR [averageRunTime] | LR [lastRunTime] | HR [highestRunTime] | D [cpu_defer_count]")
/datum/controller/process/proc/getTickTime()
return "#[getTicks()]\t- [getLastRunTime()]"
/datum/controller/process/proc/catchException(var/exception/e, var/thrower)
var/etext = "[e]"
var/eid = "[e]" // Exception ID, for tracking repeated exceptions
var/ptext = "" // "processing..." text, for what was being processed (if known)
if(istype(e))
etext += " in [e.file], line [e.line]"
eid = "[e.file]:[e.line]"
if(eid in exceptions)
if(exceptions[eid]++ >= 10)
return
else
exceptions[eid] = 1
if(istype(thrower, /datum))
var/datum/D = thrower
ptext = " processing [D.type]"
if(istype(thrower, /atom))
var/atom/A = thrower
ptext += " ([A]) ([A.x],[A.y],[A.z])"
log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]")
if(exceptions[eid] >= 10)
log_to_dd("This exception will now be ignored for ten minutes.")
spawn(6000)
exceptions[eid] = 0
/datum/controller/process/proc/catchBadType(var/datum/caught)
if(isnull(caught) || !istype(caught) || !isnull(caught.gcDestroyed))
return // Only bother with types we can identify and that don't belong
catchException("Type [caught.type] does not belong in process' queue")

View File

@@ -17,7 +17,10 @@ var/global/datum/controller/processScheduler/processScheduler
// Process name -> process object map
var/tmp/datum/controller/process/list/nameToProcessMap = new
// Process last start times
// Process last queued times (world time)
var/tmp/datum/controller/process/list/last_queued = new
// Process last start times (real time)
var/tmp/datum/controller/process/list/last_start = new
// Process last run durations
@@ -29,8 +32,8 @@ var/global/datum/controller/processScheduler/processScheduler
// Process highest run time
var/tmp/datum/controller/process/list/highest_run_time = new
// Sleep 1 tick -- This may be too aggressive.
var/tmp/scheduler_sleep_interval = 1
// How long to sleep between runs (set to tick_lag in New)
var/tmp/scheduler_sleep_interval
// Controls whether the scheduler is running or not
var/tmp/isRunning = 0
@@ -38,6 +41,25 @@ var/global/datum/controller/processScheduler/processScheduler
// Setup for these processes will be deferred until all the other processes are set up.
var/tmp/list/deferredSetupList = new
var/tmp/currentTick = 0
var/tmp/currentTickStart = 0
var/tmp/timeAllowance = 0
var/tmp/cpuAverage = 0
var/tmp/timeAllowanceMax = 0
/datum/controller/processScheduler/New()
..()
// When the process scheduler is first new'd, tick_lag may be wrong, so these
// get re-initialized when the process scheduler is started.
// (These are kept here for any processes that decide to process before round start)
scheduler_sleep_interval = world.tick_lag
timeAllowance = world.tick_lag * 0.5
timeAllowanceMax = world.tick_lag
/**
* deferSetupFor
* @param path processPath
@@ -57,7 +79,7 @@ var/global/datum/controller/processScheduler/processScheduler
var/process
// Add all the processes we can find, except for the ticker
for (process in typesof(/datum/controller/process) - /datum/controller/process)
for (process in subtypesof(/datum/controller/process))
if (!(process in deferredSetupList))
addProcess(new process(src))
@@ -66,11 +88,22 @@ var/global/datum/controller/processScheduler/processScheduler
/datum/controller/processScheduler/proc/start()
isRunning = 1
// tick_lag will have been set by now, so re-initialize these
scheduler_sleep_interval = world.tick_lag
timeAllowance = world.tick_lag * 0.5
timeAllowanceMax = world.tick_lag
updateStartDelays()
spawn(0)
process()
/datum/controller/processScheduler/proc/process()
updateCurrentTickData()
for(var/i=world.tick_lag,i<world.tick_lag*50,i+=world.tick_lag)
spawn(i) updateCurrentTickData()
while(isRunning)
// Hopefully spawning this for 50 ticks in the future will make it the first thing in the queue.
spawn(world.tick_lag*50) updateCurrentTickData()
checkRunningProcesses()
queueProcesses()
runQueuedProcesses()
@@ -92,15 +125,11 @@ var/global/datum/controller/processScheduler/processScheduler
// Check status changes
if(status != previousStatus)
//Status changed.
switch(status)
if(PROCESS_STATUS_MAYBE_HUNG)
message_admins("Process '[p.name]' is [p.getStatusText(status)].")
if(PROCESS_STATUS_PROBABLY_HUNG)
message_admins("Process '[p.name]' is [p.getStatusText(status)].")
message_admins("Process '[p.name]' may be hung.")
if(PROCESS_STATUS_HUNG)
message_admins("Process '[p.name]' is [p.getStatusText(status)].")
p.handleHung()
message_admins("Process '[p.name]' is hung and will be restarted.")
/datum/controller/processScheduler/proc/queueProcesses()
for(var/datum/controller/process/p in processes)
@@ -108,12 +137,8 @@ var/global/datum/controller/processScheduler/processScheduler
if (p.disabled || p.running || p.queued || !p.idle)
continue
// If world.timeofday has rolled over, then we need to adjust.
if (world.timeofday < last_start[p])
last_start[p] -= 864000
// If the process should be running by now, go ahead and queue it
if (world.timeofday > last_start[p] + p.schedule_interval)
if (world.time >= last_queued[p] + p.schedule_interval)
setQueuedProcessState(p)
/datum/controller/processScheduler/proc/runQueuedProcesses()
@@ -176,6 +201,10 @@ var/global/datum/controller/processScheduler/processScheduler
nameToProcessMap[newProcess.name] = newProcess
/datum/controller/processScheduler/proc/updateStartDelays()
for(var/datum/controller/process/p in processes)
if(p.start_delay)
last_queued[p] = world.time - p.start_delay
/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process)
spawn(0)
@@ -197,8 +226,6 @@ var/global/datum/controller/processScheduler/processScheduler
if (!(process in idle))
idle += process
process.idle()
/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process)
if (process in running)
running -= process
@@ -218,21 +245,22 @@ var/global/datum/controller/processScheduler/processScheduler
if (!(process in running))
running += process
process.running()
/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null)
if (isnull(time))
time = world.timeofday
last_start[process] = time
time = TimeOfHour
last_queued[process] = world.time
last_start[process] = time
else
last_queued[process] = (time == 0 ? 0 : world.time)
last_start[process] = time
/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null)
if (isnull(time))
time = world.timeofday
time = TimeOfHour
// If world.timeofday has rolled over, then we need to adjust.
if (time < last_start[process])
last_start[process] -= 864000
last_start[process] -= 36000
var/lastRunTime = time - last_start[process]
@@ -273,6 +301,12 @@ var/global/datum/controller/processScheduler/processScheduler
return t / c
return c
/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process)
return last_run_time[process]
/datum/controller/processScheduler/proc/getProcessHighestRunTime(var/datum/controller/process/process)
return highest_run_time[process]
/datum/controller/processScheduler/proc/getStatusData()
var/list/data = new
@@ -310,11 +344,39 @@ var/global/datum/controller/processScheduler/processScheduler
var/datum/controller/process/process = nameToProcessMap[processName]
process.disable()
/datum/controller/processScheduler/proc/getProcess(var/name)
return nameToProcessMap[name]
/datum/controller/processScheduler/proc/getCurrentTickElapsedTime()
if (world.time > currentTick)
updateCurrentTickData()
return 0
else
return TimeOfHour - currentTickStart
/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process)
return last_run_time[process]
/datum/controller/processScheduler/proc/updateCurrentTickData()
if (world.time > currentTick)
// New tick!
currentTick = world.time
currentTickStart = TimeOfHour
updateTimeAllowance()
cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3
/datum/controller/processScheduler/proc/getIsRunning()
return isRunning
/datum/controller/processScheduler/proc/updateTimeAllowance()
// Time allowance goes down linearly with world.cpu.
var/tmp/error = cpuAverage - 100
var/tmp/timeAllowanceDelta = sign(error) * -0.5 * world.tick_lag * max(0, 0.001 * abs(error))
//timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1))
timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta))
/datum/controller/processScheduler/proc/sign(var/x)
if (x == 0)
return 1
return x / abs(x)
/datum/controller/processScheduler/proc/statProcesses()
if(!isRunning)
stat("Processes", "Scheduler not running")
return
stat("Processes", "[processes.len] (R [running.len] / Q [queued.len] / I [idle.len])")
stat(null, "[round(cpuAverage, 0.1)] CPU, [round(timeAllowance, 0.1)/10] TA")
for(var/datum/controller/process/p in processes)
p.statProcess()

View File

@@ -1,127 +0,0 @@
/**
* updateQueue.dm
*/
#ifdef UPDATE_QUEUE_DEBUG
#define uq_dbg(text) world << text
#else
#define uq_dbg(text)
#endif
/datum/updateQueue
var/tmp/list/objects
var/tmp/previousStart
var/tmp/procName
var/tmp/list/arguments
var/tmp/datum/updateQueueWorker/currentWorker
var/tmp/workerTimeout
var/tmp/adjustedWorkerTimeout
var/tmp/currentKillCount
var/tmp/totalKillCount
/datum/updateQueue/New(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0)
..()
uq_dbg("Update queue created.")
// Init proc allows for recycling the worker.
init(objects = objects, procName = procName, arguments = arguments, workerTimeout = workerTimeout, inplace = inplace)
/**
* init
* @param list objects objects to update
* @param text procName the proc to call on each item in the object list
* @param list arguments optional arguments to pass to the update proc
* @param number workerTimeout number of ticks to wait for an update to
finish before forking a new update worker
* @param bool inplace whether the updateQueue should make a copy of objects.
the internal list will be modified, so it is usually
a good idea to leave this alone. Default behavior is to
copy.
*/
/datum/updateQueue/proc/init(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0)
uq_dbg("Update queue initialization started.")
if (!inplace)
// Make an internal copy of the list so we're not modifying the original.
initList(objects)
else
src.objects = objects
// Init vars
src.procName = procName
src.arguments = arguments
src.workerTimeout = workerTimeout
adjustedWorkerTimeout = workerTimeout
currentKillCount = 0
totalKillCount = 0
uq_dbg("Update queue initialization finished. procName = '[procName]'")
/datum/updateQueue/proc/initList(list/toCopy)
/**
* We will copy the list in reverse order, as our doWork proc
* will access them by popping an element off the end of the list.
* This ends up being quite a lot faster than taking elements off
* the head of the list.
*/
objects = new
uq_dbg("Copying [toCopy.len] items for processing.")
for(var/i=toCopy.len,i>0,)
objects.len++
objects[objects.len] = toCopy[i--]
/datum/updateQueue/proc/Run()
uq_dbg("Starting run...")
startWorker()
while (istype(currentWorker) && !currentWorker.finished)
sleep(2)
checkWorker()
uq_dbg("UpdateQueue completed run.")
/datum/updateQueue/proc/checkWorker()
if(istype(currentWorker))
// If world.timeofday has rolled over, then we need to adjust.
if(world.timeofday < currentWorker.lastStart)
currentWorker.lastStart -= 864000
if(world.timeofday - currentWorker.lastStart > adjustedWorkerTimeout)
// This worker is a bit slow, let's spawn a new one and kill the old one.
uq_dbg("Current worker is lagging... starting a new one.")
killWorker()
startWorker()
else // No worker!
uq_dbg("update queue ended up without a worker... starting a new one...")
startWorker()
/datum/updateQueue/proc/startWorker()
// only run the worker if we have objects to work on
if(objects.len)
uq_dbg("Starting worker process.")
// No need to create a fresh worker if we already have one...
if (istype(currentWorker))
currentWorker.init(objects, procName, arguments)
else
currentWorker = new(objects, procName, arguments)
currentWorker.start()
else
uq_dbg("Queue is empty. No worker was started.")
currentWorker = null
/datum/updateQueue/proc/killWorker()
// Kill the worker
currentWorker.kill()
currentWorker = null
// After we kill a worker, yield so that if the worker's been tying up the cpu, other stuff can immediately resume
sleep(-1)
currentKillCount++
totalKillCount++
if (currentKillCount >= 3)
uq_dbg("[currentKillCount] workers have been killed with a timeout of [adjustedWorkerTimeout]. Increasing worker timeout to compensate.")
adjustedWorkerTimeout++
currentKillCount = 0

View File

@@ -1,83 +0,0 @@
datum/updateQueueWorker
var/tmp/list/objects
var/tmp/killed
var/tmp/finished
var/tmp/procName
var/tmp/list/arguments
var/tmp/lastStart
var/tmp/cpuThreshold
datum/updateQueueWorker/New(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90)
..()
uq_dbg("updateQueueWorker created.")
init(objects, procName, arguments, cpuThreshold)
datum/updateQueueWorker/proc/init(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90)
src.objects = objects
src.procName = procName
src.arguments = arguments
src.cpuThreshold = cpuThreshold
killed = 0
finished = 0
datum/updateQueueWorker/proc/doWork()
// If there's nothing left to execute or we were killed, mark finished and return.
if (!objects || !objects.len) return finished()
lastStart = world.timeofday // Absolute number of ticks since the world started up
var/datum/object = objects[objects.len] // Pull out the object
objects.len-- // Remove the object from the list
if (istype(object) && !isturf(object) && !object.disposed && isnull(object.gcDestroyed)) // We only work with real objects
call(object, procName)(arglist(arguments))
// If there's nothing left to execute
// or we were killed while running the above code, mark finished and return.
if (!objects || !objects.len) return finished()
if (world.cpu > cpuThreshold)
// We don't want to force a tick into overtime!
// If the tick is about to go overtime, spawn the next update to go
// in the next tick.
uq_dbg("tick went into overtime with world.cpu = [world.cpu], deferred next update to next tick [1+(world.time / world.tick_lag)]")
spawn(1)
doWork()
else
spawn(0) // Execute anonymous function immediately as if we were in a while loop...
doWork()
datum/updateQueueWorker/proc/finished()
uq_dbg("updateQueueWorker finished.")
/**
* If the worker was killed while it was working on something, it
* should delete itself when it finally finishes working on it.
* Meanwhile, the updateQueue will have proceeded on with the rest of
* the queue. This will also terminate the spawned function that was
* created in the kill() proc.
*/
if(killed)
del(src)
finished = 1
datum/updateQueueWorker/proc/kill()
uq_dbg("updateQueueWorker killed.")
killed = 1
objects = null
/**
* If the worker is not done in 30 seconds after it's killed,
* we'll forcibly delete it, causing the anonymous function it was
* running to be terminated. Hasta la vista, baby.
*/
spawn(300)
del(src)
datum/updateQueueWorker/proc/start()
uq_dbg("updateQueueWorker started.")
spawn(0)
doWork()

View File

@@ -1,94 +0,0 @@
/datum/processSchedulerView
/datum/processSchedulerView/Topic(href, href_list)
if (!href_list["action"])
return
switch (href_list["action"])
if ("kill")
var/toKill = href_list["name"]
processScheduler.killProcess(toKill)
refreshProcessTable()
if ("enable")
var/toEnable = href_list["name"]
processScheduler.enableProcess(toEnable)
refreshProcessTable()
if ("disable")
var/toDisable = href_list["name"]
processScheduler.disableProcess(toDisable)
refreshProcessTable()
if ("refresh")
refreshProcessTable()
/datum/processSchedulerView/proc/refreshProcessTable()
windowCall("handleRefresh", getProcessTable())
/datum/processSchedulerView/proc/windowCall(var/function, var/data = null)
usr << output(data, "processSchedulerContext.browser:[function]")
/datum/processSchedulerView/proc/getProcessTable()
var/text = "<table class=\"table table-striped\"><thead><tr><td>Name</td><td>Avg(s)</td><td>Last(s)</td><td>Highest(s)</td><td>Tickcount</td><td>Tickrate</td><td>State</td><td>Action</td></tr></thead><tbody>"
// and the context of each
for (var/list/data in processScheduler.getStatusData())
text += "<tr>"
text += "<td>[data["name"]]</td>"
text += "<td>[num2text(data["averageRunTime"]/10,3)]</td>"
text += "<td>[num2text(data["lastRunTime"]/10,3)]</td>"
text += "<td>[num2text(data["highestRunTime"]/10,3)]</td>"
text += "<td>[num2text(data["ticks"],4)]</td>"
text += "<td>[data["schedule"]]</td>"
text += "<td>[data["status"]]</td>"
text += "<td><button class=\"btn kill-btn\" data-process-name=\"[data["name"]]\" id=\"kill-[data["name"]]\">Kill</button>"
if (data["disabled"])
text += "<button class=\"btn enable-btn\" data-process-name=\"[data["name"]]\" id=\"enable-[data["name"]]\">Enable</button>"
else
text += "<button class=\"btn disable-btn\" data-process-name=\"[data["name"]]\" id=\"disable-[data["name"]]\">Disable</button>"
text += "</td>"
text += "</tr>"
text += "</tbody></table>"
return text
/**
* getContext
* Outputs an interface showing stats for all processes.
*/
/datum/processSchedulerView/proc/getContext()
bootstrap_browse()
usr << browse('processScheduler.js', "file=processScheduler.js;display=0")
var/text = {"<html><head>
<title>Process Scheduler Detail</title>
<script type="text/javascript">var ref = '\ref[src]';</script>
[bootstrap_includes()]
<script type="text/javascript" src="processScheduler.js"></script>
</head>
<body>
<h2>Process Scheduler</h2>
<div class="btn-group">
<button id="btn-refresh" class="btn">Refresh</button>
</div>
<h3>The process scheduler controls [processScheduler.getProcessCount()] loops.<h3>"}
text += "<div id=\"processTable\">"
text += getProcessTable()
text += "</div></body></html>"
usr << browse(text, "window=processSchedulerContext;size=800x600")
/datum/processSchedulerView/proc/bootstrap_browse()
usr << browse('bower_components/jquery/dist/jquery.min.js', "file=jquery.min.js;display=0")
usr << browse('bower_components/bootstrap2.3.2/bootstrap/js/bootstrap.min.js', "file=bootstrap.min.js;display=0")
usr << browse('bower_components/bootstrap2.3.2/bootstrap/css/bootstrap.min.css', "file=bootstrap.min.css;display=0")
usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings-white.png', "file=glyphicons-halflings-white.png;display=0")
usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings.png', "file=glyphicons-halflings.png;display=0")
usr << browse('bower_components/json2/json2.js', "file=json2.js;display=0")
/datum/processSchedulerView/proc/bootstrap_includes()
return {"
<link rel="stylesheet" href="bootstrap.min.css" />
<script type="text/javascript" src="json2.js"></script>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="bootstrap.js"></script>
"}

View File

@@ -1,27 +0,0 @@
/**
* testDyingUpdateQueueProcess
* This process is an example of a process using an updateQueue.
* The datums updated by this process behave badly and block the update loop
* by sleeping. If you #define UPDATE_QUEUE_DEBUG, you will see the updateQueue
* killing off its worker processes and spawning new ones to work around slow
* updates. This means that if you have a code path that sleeps for a long time
* in mob.Life once in a blue moon, the mob update loop will not hang.
*/
/datum/slowTestDatum/proc/wackyUpdateProcessName()
sleep(rand(0,20)) // Randomly REALLY slow :|
/datum/controller/process/testDyingUpdateQueueProcess
var/tmp/datum/updateQueue/updateQueueInstance
var/tmp/list/testDatums = list()
/datum/controller/process/testDyingUpdateQueueProcess/setup()
name = "Dying UpdateQueue Process"
schedule_interval = 30 // every 3 seconds
updateQueueInstance = new
for(var/i = 1, i < 30, i++)
testDatums.Add(new /datum/slowTestDatum)
/datum/controller/process/testDyingUpdateQueueProcess/doWork()
updateQueueInstance.init(testDatums, "wackyUpdateProcessName")
updateQueueInstance.Run()

View File

@@ -1,35 +0,0 @@
/*
These are simple defaults for your project.
*/
#define DEBUG
var/global/datum/processSchedulerView/processSchedulerView
world
loop_checks = 0
New()
..()
processScheduler = new
processSchedulerView = new
mob
step_size = 8
New()
..()
verb
startProcessScheduler()
set name = "Start Process Scheduler"
processScheduler.setup()
processScheduler.start()
getProcessSchedulerContext()
set name = "Get Process Scheduler Status Panel"
processSchedulerView.getContext()
runUpdateQueueTests()
set name = "Run Update Queue Testsuite"
var/datum/updateQueueTests/t = new
t.runTests()

View File

@@ -1,15 +0,0 @@
/**
* testHungProcess
* This process is an example of a simple update loop process that hangs.
*/
/datum/controller/process/testHungProcess/setup()
name = "Hung Process"
schedule_interval = 30 // every 3 seconds
/datum/controller/process/testHungProcess/doWork()
sleep(1000) // FUCK
// scheck is also responsible for handling hung processes. If a process
// hangs, and later resumes, but has already been killed by the scheduler,
// scheck will force the process to bail out.
scheck()

View File

@@ -1,13 +0,0 @@
/**
* testNiceProcess
* This process is an example of a simple update loop process that is
* relatively fast.
*/
/datum/controller/process/testNiceProcess/setup()
name = "Nice Process"
schedule_interval = 10 // every second
/datum/controller/process/testNiceProcess/doWork()
sleep(rand(1,5)) // Just to pretend we're doing something

View File

@@ -1,28 +0,0 @@
/**
* testSlowProcess
* This process is an example of a simple update loop process that is slow.
* The update loop here sleeps inside to provide an example, but if you had
* a computationally intensive loop process that is simply slow, you can use
* scheck() inside the loop to force it to yield periodically according to
* the sleep_interval var. By default, scheck will cause a loop to sleep every
* 2 ticks.
*/
/datum/controller/process/testSlowProcess/setup()
name = "Slow Process"
schedule_interval = 30 // every 3 seconds
/datum/controller/process/testSlowProcess/doWork()
// set background = 1 will cause loop constructs to sleep periodically,
// whenever the BYOND scheduler deems it productive to do so.
// This behavior is not always sufficient, nor is it always consistent.
// Rather than leaving it up to the BYOND scheduler, we can control it
// ourselves and leave nothing to the black box.
set background = 1
for(var/i=1,i<30,i++)
// Just to pretend we're doing something here
sleep(rand(3, 5))
// Forces this loop to yield(sleep) periodically.
scheck()

View File

@@ -1,209 +0,0 @@
var/global/list/updateQueueTestCount = list()
/datum/updateQueueTests
var/start
proc
runTests()
world << "<b>Running 9 tests...</b>"
testUpdateQueuePerformance()
sleep(1)
testInplace()
sleep(1)
testInplaceUpdateQueuePerformance()
sleep(1)
testUpdateQueueReinit()
sleep(1)
testCrashingQueue()
sleep(1)
testEmptyQueue()
sleep(1)
testManySlowItemsInQueue()
sleep(1)
testVariableWorkerTimeout()
sleep(1)
testReallySlowItemInQueue()
sleep(1)
world << "<b>Finished!</b>"
beginTiming()
start = world.time
endTiming(text)
var/time = (world.time - start) / world.tick_lag
world << {"<b><font color="blue">Performance - [text] - <font color="green">[time]</font> ticks</font></b>"}
getCount()
return updateQueueTestCount[updateQueueTestCount.len]
incrementTestCount()
updateQueueTestCount.len++
updateQueueTestCount[updateQueueTestCount.len] = 0
assertCountEquals(count, text)
assertThat(getCount() == count, text)
assertCountLessThan(count, text)
assertThat(getCount() < count, text)
assertCountGreaterThan(count, text)
assertThat(getCount() > count, text)
assertThat(condition, text)
if (condition)
world << {"<font color="green"><b>PASS</b></font>: [text]"}
else
world << {"<b><font color="red">FAIL</font>: [text]</b>"}
testUpdateQueuePerformance()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=100000,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs)
beginTiming()
uq.Run()
endTiming("updating 100000 simple objects")
assertCountEquals(100000, "test that update queue updates all objects expected")
del(objs)
del(uq)
testUpdateQueueReinit()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=100,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs)
uq.Run()
objs = new
for(var/i=1,i<=100,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
uq.init(objs)
uq.Run()
assertCountEquals(200, "test that update queue reinitializes properly and updates all objects as expected.")
del(objs)
del(uq)
testInplace()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=100,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objects = objs, inplace = 1)
uq.Run()
assertThat(objs.len == 0, "test that update queue inplace option really works inplace")
assertCountEquals(100, "test that inplace update queue updates the right number of objects")
del(objs)
del(uq)
testInplaceUpdateQueuePerformance()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=100000,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs)
beginTiming()
uq.Run()
endTiming("updating 100000 simple objects in place")
del(objs)
del(uq)
testCrashingQueue()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=10,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
objs.Add(new /datum/uqTestDatum/crasher(updateQueueTestCount.len))
for(var/i=1,i<=10,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs)
uq.Run()
assertCountEquals(20, "test that update queue handles crashed update procs OK")
del(objs)
del(uq)
testEmptyQueue()
incrementTestCount()
var/list/objs = new
var/datum/updateQueue/uq = new(objs)
uq.Run()
assertCountEquals(0, "test that update queue doesn't barf on empty lists")
del(objs)
del(uq)
testManySlowItemsInQueue()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=30,i++)
objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs)
uq.Run()
assertCountEquals(30, "test that update queue slows down execution if too many objects are slow to update")
del(objs)
del(uq)
testVariableWorkerTimeout()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=20,i++)
objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs, workerTimeout=6)
uq.Run()
assertCountEquals(20, "test that variable worker timeout works properly")
del(objs)
del(uq)
testReallySlowItemInQueue()
incrementTestCount()
var/list/objs = new
for(var/i=1,i<=10,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
objs.Add(new /datum/uqTestDatum/reallySlow(updateQueueTestCount.len))
for(var/i=1,i<=10,i++)
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
var/datum/updateQueue/uq = new(objs)
uq.Run()
assertCountEquals(20, "test that update queue skips objects that are too slow to update")
del(objs)
del(uq)
datum/uqTestDatum
var/testNum
New(testNum)
..()
src.testNum = testNum
proc/update()
updateQueueTestCount[testNum]++
proc/lag(cycles)
set background = 1
for(var/i=0,i<cycles,)
i++
datum/uqTestDatum/fast
datum/uqTestDatum/slow
update()
set background = 1
var/start = world.timeofday
while(world.timeofday - start < 5) // lag 4 deciseconds
..()
datum/uqTestDatum/reallySlow
update()
set background = 1
var/start = world.timeofday
while(world.timeofday - start < 300) // lag 30 seconds
..()
datum/uqTestDatum/crasher
update()
CRASH("I crashed! (I am supposed to crash XD)")
..() // This should do nothing lol

View File

@@ -1,24 +0,0 @@
/**
* testUpdateQueueProcess
* This process is an example of a process using an updateQueue.
* The datums updated by this process behave nicely and do not block.
*/
/datum/fastTestDatum/proc/wackyUpdateProcessName()
sleep(prob(10)) // Pretty quick, usually instant
/datum/controller/process/testUpdateQueueProcess
var/tmp/datum/updateQueue/updateQueueInstance
var/tmp/list/testDatums = list()
/datum/controller/process/testUpdateQueueProcess/setup()
name = "UpdateQueue Process"
schedule_interval = 20 // every 2 seconds
updateQueueInstance = new
for(var/i = 1, i < 30, i++)
testDatums.Add(new /datum/fastTestDatum)
/datum/controller/process/testUpdateQueueProcess/doWork()
updateQueueInstance.init(testDatums, "wackyUpdateProcessName")
updateQueueInstance.Run()

View File

@@ -1,13 +0,0 @@
/**
* testBadZombieProcess
* This process is an example of a simple update loop process that hangs.
*/
/datum/controller/process/testZombieProcess/setup()
name = "Zombie Process"
schedule_interval = 30 // every 3 seconds
/datum/controller/process/testZombieProcess/doWork()
for (var/i = 0, i < 1000, i++)
sleep(1)
scheck()

View File

@@ -1,6 +1,7 @@
/datum/controller/process/air/setup()
name = "air"
schedule_interval = 20 // every 2 seconds
start_delay = 4
if(!air_master)
air_master = new

View File

@@ -1,10 +1,42 @@
// We manually initialize the alarm handlers instead of looping over all existing types
// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof.
/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
/var/global/datum/alarm_handler/camera/camera_alarm = new()
/var/global/datum/alarm_handler/fire/fire_alarm = new()
/var/global/datum/alarm_handler/motion/motion_alarm = new()
/var/global/datum/alarm_handler/power/power_alarm = new()
// Alarm Manager, the manager for alarms.
var/datum/controller/process/alarm/alarm_manager
/datum/controller/process/alarm
var/list/datum/alarm/all_handlers
/datum/controller/process/alarm/setup()
name = "alarm"
schedule_interval = 20 // every 2 seconds
all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm)
alarm_manager = src
/datum/controller/process/alarm/doWork()
alarm_manager.fire()
for(last_object in all_handlers)
var/datum/alarm_handler/AH = last_object
AH.process()
SCHECK
/datum/controller/process/alarm/getStatName()
var/list/alarms = alarm_manager.active_alarms()
return ..()+"([alarms.len])"
/datum/controller/process/alarm/proc/active_alarms()
var/list/all_alarms = new
for(var/datum/alarm_handler/AH in all_handlers)
var/list/alarms = AH.alarms
all_alarms += alarms
return all_alarms
/datum/controller/process/alarm/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len
/datum/controller/process/alarm/statProcess()
..()
stat(null, "[number_of_active_alarms()] alarm\s")

View File

@@ -1,7 +1,6 @@
var/datum/controller/process/chemistry/chemistryProcess
/datum/controller/process/chemistry
var/tmp/datum/updateQueue/updateQueueInstance
var/list/active_holders
var/list/chemical_reactions
var/list/chemical_reagents
@@ -9,23 +8,24 @@ var/datum/controller/process/chemistry/chemistryProcess
/datum/controller/process/chemistry/setup()
name = "chemistry"
schedule_interval = 20 // every 2 seconds
updateQueueInstance = new
chemistryProcess = src
active_holders = list()
chemical_reactions = chemical_reactions_list
chemical_reagents = chemical_reagents_list
/datum/controller/process/chemistry/getStatName()
return ..()+"([active_holders.len])"
/datum/controller/process/chemistry/statProcess()
..()
stat(null, "[active_holders.len] reagent holder\s")
/datum/controller/process/chemistry/doWork()
for(var/datum/reagents/holder in active_holders)
for(last_object in active_holders)
var/datum/reagents/holder = last_object
if(!holder.process_reactions())
active_holders -= holder
scheck()
SCHECK
/datum/controller/process/chemistry/proc/mark_for_update(var/datum/reagents/holder)
if(holder in active_holders)
if(holder in active_holders)
return
//Process once, right away. If we still need to continue then add to the active_holders list and continue later

View File

@@ -1,14 +0,0 @@
/datum/controller/process/disease
var/tmp/datum/updateQueue/updateQueueInstance
/datum/controller/process/disease/setup()
name = "disease"
schedule_interval = 20 // every 2 seconds
updateQueueInstance = new
/datum/controller/process/disease/doWork()
updateQueueInstance.init(active_diseases, "process")
updateQueueInstance.Run()
/datum/controller/process/disease/getStatName()
return ..()+"([active_diseases.len])"

View File

@@ -1,13 +1,18 @@
// The time a datum was destroyed by the GC, or null if it hasn't been
/datum/var/gcDestroyed
#define GC_COLLECTIONS_PER_RUN 300
#define GC_COLLECTION_TIMEOUT (30 SECONDS)
#define GC_FORCE_DEL_PER_RUN 30
var/datum/controller/process/garbage_collector/garbage_collector
var/list/delayed_garbage = list()
/datum/controller/process/garbage_collector
var/garbage_collect = 1 // Whether or not to actually do work
var/collection_timeout = 300 //deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
var/max_checks_multiplier = 5 //multiplier (per-decisecond) for calculating max number of tests per tick. These tests check if our GC'd objects are actually GC'd
var/max_forcedel_multiplier = 1 //multiplier (per-decisecond) for calculating max number of force del() calls per tick.
var/dels = 0 // number of del()'s we've done this tick
var/total_dels = 0 // number of total del()'s
var/tick_dels = 0 // number of del()'s we've done this tick
var/soft_dels = 0
var/hard_dels = 0 // number of hard dels in total
var/list/destroyed = list() // list of refID's of things that should be garbage collected
// refID's are associated with the time at which they time out and need to be manually del()
@@ -18,7 +23,8 @@ var/list/delayed_garbage = list()
/datum/controller/process/garbage_collector/setup()
name = "garbage"
schedule_interval = 2 SECONDS
schedule_interval = 5 SECONDS
start_delay = 3
if(!garbage_collector)
garbage_collector = src
@@ -36,38 +42,14 @@ world/loop_checks = 0
if(!garbage_collect)
return
dels = 0
var/time_to_kill = world.time - collection_timeout // Anything qdel() but not GC'd BEFORE this time needs to be manually del()
var/checkRemain = max_checks_multiplier * schedule_interval
var/maxDels = max_forcedel_multiplier * schedule_interval
tick_dels = 0
var/time_to_kill = world.time - GC_COLLECTION_TIMEOUT
var/checkRemain = GC_COLLECTIONS_PER_RUN
var/remaining_force_dels = GC_FORCE_DEL_PER_RUN
#ifdef GC_FINDREF
var/list/searching = list()
for(var/refID in destroyed) // Reference search - before all deletions and for all at once
var/GCd_at_time = destroyed[refID]
if(GCd_at_time > time_to_kill)
break
var/atom/A = locate(refID)
if(A && A.gcDestroyed == GCd_at_time)
searching += A
if(searching.len >= checkRemain)
break
for(var/atom/A in searching)
testing("GC: Searching references for [A] | [A.type]")
if(A.loc != null)
testing("GC: [A] | [A.type] is located in [A.loc] instead of null")
if(A.contents.len)
testing("GC: [A] | [A.type] has contents: [jointext(A.contents)]")
if(searching.len)
for(var/atom/D in world)
LookForRefs(D, searching)
for(var/datum/D)
LookForRefs(D, searching)
#endif
while(destroyed.len && --checkRemain >= 0)
if(dels >= maxDels)
if(remaining_force_dels <= 0)
#ifdef GC_DEBUG
testing("GC: Reached max force dels per tick [dels] vs [maxDels]")
#endif
@@ -88,13 +70,22 @@ world/loop_checks = 0
testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --")
logging["[A.type]"]++
del(A)
++dels
++hard_dels
#ifdef GC_DEBUG
hard_dels++
remaining_force_dels--
else
#ifdef GC_DEBUG
testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]")
#endif
#endif
soft_dels++
tick_dels++
total_dels++
destroyed.Cut(1, 2)
SCHECK
#undef GC_FORCE_DEL_PER_TICK
#undef GC_COLLECTION_TIMEOUT
#undef GC_COLLECTIONS_PER_TICK
#ifdef GC_FINDREF
/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ)
@@ -132,8 +123,11 @@ world/loop_checks = 0
destroyed -= "\ref[A]" // Removing any previous references that were GC'd so that the current object will be at the end of the list.
destroyed["\ref[A]"] = world.time
/datum/controller/process/garbage_collector/getStatName()
return ..()+"([garbage_collector.destroyed.len]/[garbage_collector.dels]/[garbage_collector.hard_dels])"
/datum/controller/process/garbage_collector/statProcess()
..()
stat(null, "[garbage_collect ? "On" : "Off"], [destroyed.len] queued")
stat(null, "Dels: [total_dels], [soft_dels] soft, [hard_dels] hard, [tick_dels] last run")
// Tests if an atom has been deleted.
/proc/deleted(atom/A)
@@ -149,7 +143,7 @@ world/loop_checks = 0
crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.")
del(A)
if(garbage_collector)
garbage_collector.dels++
garbage_collector.total_dels++
garbage_collector.hard_dels++
else if(isnull(A.gcDestroyed))
// Let our friend know they're about to get collected
@@ -263,4 +257,4 @@ world/loop_checks = 0
#ifdef GC_FINDREF
#undef GC_FINDREF
#endif
#endif

View File

@@ -4,10 +4,11 @@
/datum/controller/process/inactivity/doWork()
if(config.kick_inactive)
for(var/client/C in clients)
for(last_object in clients)
var/client/C = last_object
if(!C.holder && C.is_afk(config.kick_inactive MINUTES))
if(!istype(C.mob, /mob/observer/dead))
log_access("AFK: [key_name(C)]")
C << "<SPAN CLASS='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</SPAN>"
del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients.
scheck()
SCHECK

View File

@@ -3,6 +3,7 @@
/datum/controller/process/machinery/setup()
name = "machinery"
schedule_interval = 20 // every 2 seconds
start_delay = 12
/datum/controller/process/machinery/doWork()
internal_sort()
@@ -17,12 +18,9 @@
machines = dd_sortedObjectList(machines)
/datum/controller/process/machinery/proc/internal_process_machinery()
for(var/obj/machinery/M in machines)
for(last_object in machines)
var/obj/machinery/M = last_object
if(M && !M.gcDestroyed)
#ifdef PROFILE_MACHINES
var/time_start = world.timeofday
#endif
if(M.process() == PROCESS_KILL)
//M.inMachineList = 0 We don't use this debugging function
machines.Remove(M)
@@ -31,41 +29,39 @@
if(M && M.use_power)
M.auto_use_power()
#ifdef PROFILE_MACHINES
var/time_end = world.timeofday
if(!(M.type in machine_profiling))
machine_profiling[M.type] = 0
machine_profiling[M.type] += (time_end - time_start)
#endif
scheck()
SCHECK
/datum/controller/process/machinery/proc/internal_process_power()
for(var/datum/powernet/powerNetwork in powernets)
if(istype(powerNetwork) && !powerNetwork.disposed)
for(last_object in powernets)
var/datum/powernet/powerNetwork = last_object
if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed))
powerNetwork.reset()
scheck()
SCHECK
continue
powernets.Remove(powerNetwork)
/datum/controller/process/machinery/proc/internal_process_power_drain()
// Currently only used by powersinks. These items get priority processed before machinery
for(var/obj/item/I in processing_power_items)
for(last_object in processing_power_items)
var/obj/item/I = last_object
if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list.
processing_power_items.Remove(I)
scheck()
SCHECK
/datum/controller/process/machinery/proc/internal_process_pipenets()
for(var/datum/pipe_network/pipeNetwork in pipe_networks)
if(istype(pipeNetwork) && !pipeNetwork.disposed)
for(last_object in pipe_networks)
var/datum/pipe_network/pipeNetwork = last_object
if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed))
pipeNetwork.process()
scheck()
SCHECK
continue
pipe_networks.Remove(pipeNetwork)
/datum/controller/process/machinery/getStatName()
return ..()+"(MCH:[machines.len] PWR:[powernets.len] PIP:[pipe_networks.len])"
/datum/controller/process/machinery/statProcess()
..()
stat(null, "[machines.len] machines")
stat(null, "[powernets.len] powernets")
stat(null, "[pipe_networks.len] pipenets")
stat(null, "[processing_power_items.len] power item\s")

View File

@@ -4,20 +4,26 @@
/datum/controller/process/mob/setup()
name = "mob"
schedule_interval = 20 // every 2 seconds
updateQueueInstance = new
start_delay = 16
/datum/controller/process/mob/started()
..()
if(!updateQueueInstance)
if(!mob_list)
mob_list = list()
else if(mob_list.len)
updateQueueInstance = new
if(!mob_list)
mob_list = list()
/datum/controller/process/mob/doWork()
if(updateQueueInstance)
updateQueueInstance.init(mob_list, "Life")
updateQueueInstance.Run()
for(last_object in mob_list)
var/mob/M = last_object
if(isnull(M.gcDestroyed))
try
M.Life()
catch(var/exception/e)
catchException(e, M)
SCHECK
else
catchBadType(M)
mob_list -= M
/datum/controller/process/mob/getStatName()
return ..()+"([mob_list.len])"
/datum/controller/process/mob/statProcess()
..()
stat(null, "[mob_list.len] mobs")

View File

@@ -1,14 +1,19 @@
/datum/controller/process/nanoui
var/tmp/datum/updateQueue/updateQueueInstance
/datum/controller/process/nanoui/setup()
name = "nanoui"
schedule_interval = 10 // every 1 second
updateQueueInstance = new
schedule_interval = 20 // every 2 seconds
/datum/controller/process/nanoui/statProcess()
..()
stat(null, "[nanomanager.processing_uis.len] UIs")
/datum/controller/process/nanoui/doWork()
updateQueueInstance.init(nanomanager.processing_uis, "process")
updateQueueInstance.Run()
/datum/controller/process/nanoui/getStatName()
return ..()+"([nanomanager.processing_uis.len])"
for(last_object in nanomanager.processing_uis)
var/datum/nanoui/NUI = last_object
if(istype(NUI) && isnull(NUI.gcDestroyed))
try
NUI.process()
catch(var/exception/e)
catchException(e, NUI)
else
catchBadType(NUI)
nanomanager.processing_uis -= NUI

View File

@@ -1,24 +1,26 @@
var/global/list/object_profiling = list()
/datum/controller/process/obj
var/tmp/datum/updateQueue/updateQueueInstance
/datum/controller/process/obj/setup()
name = "obj"
schedule_interval = 20 // every 2 seconds
updateQueueInstance = new
start_delay = 8
/datum/controller/process/obj/started()
..()
if(!updateQueueInstance)
if(!processing_objects)
processing_objects = list()
else if(processing_objects.len)
updateQueueInstance = new
if(!processing_objects)
processing_objects = list()
/datum/controller/process/obj/doWork()
if(updateQueueInstance)
updateQueueInstance.init(processing_objects, "process")
updateQueueInstance.Run()
for(last_object in processing_objects)
var/datum/O = last_object
if(isnull(O.gcDestroyed))
try
O:process()
catch(var/exception/e)
catchException(e, O)
SCHECK
else
catchBadType(O)
processing_objects -= O
/datum/controller/process/obj/getStatName()
return ..()+"([processing_objects.len])"
/datum/controller/process/obj/statProcess()
..()
stat(null, "[processing_objects.len] objects")

View File

@@ -0,0 +1,133 @@
/var/datum/controller/process/scheduler/scheduler
/************
* Scheduler *
************/
/datum/controller/process/scheduler
var/list/scheduled_tasks
/datum/controller/process/scheduler/setup()
name = "scheduler"
schedule_interval = 3 SECONDS
scheduled_tasks = list()
scheduler = src
/datum/controller/process/scheduler/doWork()
for(last_object in scheduled_tasks)
var/datum/scheduled_task/scheduled_task = last_object
try
if(world.time > scheduled_task.trigger_time)
unschedule(scheduled_task)
scheduled_task.pre_process()
scheduled_task.process()
scheduled_task.post_process()
catch(var/exception/e)
catchException(e, last_object)
SCHECK
/datum/controller/process/scheduler/statProcess()
..()
stat(null, "[scheduled_tasks.len] task\s")
/datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st)
scheduled_tasks += st
destroyed_event.register(st, src, /datum/controller/process/scheduler/proc/unschedule)
/datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st)
if(st in scheduled_tasks)
scheduled_tasks -= st
destroyed_event.unregister(st, src)
/**********
* Helpers *
**********/
/proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list())
return schedule_task(world.time + in_time, procedure, arguments)
/proc/schedule_task_with_source_in(var/in_time, var/source, var/procedure, var/list/arguments = list())
return schedule_task_with_source(world.time + in_time, source, procedure, arguments)
/proc/schedule_task(var/trigger_time, var/procedure, var/list/arguments)
var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/destroy_scheduled_task, list())
scheduler.schedule(st)
return st
/proc/schedule_task_with_source(var/trigger_time, var/source, var/procedure, var/list/arguments)
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/destroy_scheduled_task, list())
scheduler.schedule(st)
return st
/proc/schedule_repeating_task(var/trigger_time, var/repeat_interval, var/procedure, var/list/arguments)
var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
scheduler.schedule(st)
return st
/proc/schedule_repeating_task_with_source(var/trigger_time, var/repeat_interval, var/source, var/procedure, var/list/arguments)
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
scheduler.schedule(st)
return st
/*************
* Task Datum *
*************/
/datum/scheduled_task
var/trigger_time
var/procedure
var/list/arguments
var/task_after_process
var/list/task_after_process_args
/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
..()
src.trigger_time = trigger_time
src.procedure = procedure
src.arguments = arguments ? arguments : list()
src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task
src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list()
task_after_process_args += src
/datum/scheduled_task/Destroy()
procedure = null
arguments.Cut()
task_after_process = null
task_after_process_args.Cut()
return ..()
/datum/scheduled_task/proc/pre_process()
task_triggered_event.raise_event(list(src))
/datum/scheduled_task/proc/process()
if(procedure)
call(procedure)(arglist(arguments))
/datum/scheduled_task/proc/post_process()
call(task_after_process)(arglist(task_after_process_args))
// Resets the trigger time, has no effect if the task has already triggered
/datum/scheduled_task/proc/trigger_task_in(var/trigger_in)
src.trigger_time = world.time + trigger_in
/datum/scheduled_task/source
var/datum/source
/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
src.source = source
destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
/datum/scheduled_task/source/Destroy()
source = null
return ..()
/datum/scheduled_task/source/process()
call(source, procedure)(arglist(arguments))
/datum/scheduled_task/source/proc/source_destroyed()
qdel(src)
/proc/destroy_scheduled_task(var/datum/scheduled_task/st)
qdel(st)
/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st)
st.trigger_time = world.time + trigger_delay
scheduler.schedule(st)

View File

@@ -5,10 +5,12 @@ var/global/list/turf/processing_turfs = list()
schedule_interval = 20 // every 2 seconds
/datum/controller/process/turf/doWork()
for(var/turf/T in processing_turfs)
for(last_object in processing_turfs)
var/turf/T = last_object
if(T.process() == PROCESS_KILL)
processing_turfs.Remove(T)
scheck()
SCHECK
/datum/controller/process/turf/getStatName()
return ..()+"([processing_turfs.len])"
/datum/controller/process/turf/statProcess()
..()
stat(null, "[processing_turfs.len] turf\s")

View File

@@ -21,6 +21,7 @@ var/list/gamemode_cache = list()
var/log_pda = 0 // log pda messages
var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
var/log_runtime = 0 // logs world.log to a file
var/log_world_output = 0 // log world.log << messages
var/sql_enabled = 0 // for sql switching
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
var/allow_vote_restart = 0 // allow votes to restart
@@ -327,6 +328,9 @@ var/list/gamemode_cache = list()
if ("log_pda")
config.log_pda = 1
if ("log_world_output")
config.log_world_output = 1
if ("log_hrefs")
config.log_hrefs = 1

View File

@@ -47,7 +47,8 @@ datum/controller/game_controller/proc/setup_objects()
admin_notice("<span class='danger'>Initializing objects</span>", R_DEBUG)
sleep(-1)
for(var/atom/movable/object in world)
object.initialize()
if(isnull(object.gcDestroyed))
object.initialize()
admin_notice("<span class='danger'>Initializing areas</span>", R_DEBUG)
sleep(-1)

View File

@@ -1,28 +0,0 @@
/*
#define OBSERVER_EVENT_DESTROY "OnDestroy"
/datum
var/list/observer_events
/datum/Destroy()
for(var/list/listeners in observer_events)
listeners.Cut()
return ..()
/datum/proc/register(var/event, var/procOwner, var/proc_call)
var/list/listeners = get_listener_list_from_event(event)
listeners[procOwner] = proc_call
/datum/proc/unregister(var/event, var/procOwner)
var/list/listeners = get_listener_list_from_event(event)
listeners -= procOwner
/datum/proc/get_listener_list_from_event(var/observer_event)
if(!observer_events) observer_events = list()
var/list/listeners = observer_events[observer_event]
if(!listeners)
listeners = list()
observer_events[observer_event] = listeners
return listeners
*/

View File

@@ -1,30 +0,0 @@
// We manually initialize the alarm handlers instead of looping over all existing types
// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof.
/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
/var/global/datum/alarm_handler/camera/camera_alarm = new()
/var/global/datum/alarm_handler/fire/fire_alarm = new()
/var/global/datum/alarm_handler/motion/motion_alarm = new()
/var/global/datum/alarm_handler/power/power_alarm = new()
/datum/subsystem/alarm
name = "Alarm"
var/list/datum/alarm/all_handlers
/datum/subsystem/alarm/New()
all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm)
/datum/subsystem/alarm/fire()
for(var/datum/alarm_handler/AH in all_handlers)
AH.process()
/datum/subsystem/alarm/proc/active_alarms()
var/list/all_alarms = new
for(var/datum/alarm_handler/AH in all_handlers)
var/list/alarms = AH.alarms
all_alarms += alarms
return all_alarms
/datum/subsystem/alarm/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len

View File

@@ -25,7 +25,7 @@
usr.client.debug_variables(antag)
message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.")
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote"))
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote","Xenobio"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -95,5 +95,8 @@
if("Vote")
debug_variables(vote)
feedback_add_details("admin_verb", "DVote")
if("Xenobio")
debug_variables(xenobio_controller)
feedback_add_details("admin_verb", "DXenobio")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return

View File

@@ -28,6 +28,9 @@
height = nheight
if (nref)
ref = nref
// If a client exists, but they have disabled fancy windowing, disable it!
if(user && user.client && !user.client.is_preference_enabled(/datum/client_preference/browser_style))
return
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
/datum/browser/proc/set_title(ntitle)
@@ -178,4 +181,4 @@
if(src && src.mob)
//world << "[src] was [src.mob.machine], setting to null"
src.mob.unset_machine()
return
return

View File

@@ -2,17 +2,20 @@
* Category Collection *
**********************/
/datum/category_collection
var/category_group_type // The type of categories to initialize
var/list/datum/category_group/categories // The list of initialized categories
var/category_group_type // Type of categories to initialize
var/list/datum/category_group/categories // List of initialized categories
var/list/datum/category_group/categories_by_name // Associative list of initialized categories, keyed by name
/datum/category_collection/New()
..()
categories = new()
categories_by_name = new()
for(var/category_type in typesof(category_group_type))
var/datum/category_group/category = category_type
if(initial(category.name))
category = new category(src)
categories += category
categories_by_name[category.name] = category
categories = dd_sortedObjectList(categories)
/datum/category_collection/Destroy()
@@ -26,20 +29,23 @@
******************/
/datum/category_group
var/name = ""
var/category_item_type // The type of items to initialize
var/list/datum/category_item/items // The list of initialized items
var/datum/category_collection/collection // The collection this group belongs to
var/category_item_type // Type of items to initialize
var/list/datum/category_item/items // List of initialized items
var/list/datum/category_item/items_by_name // Associative list of initialized items, by name
var/datum/category_collection/collection // The collection this group belongs to
/datum/category_group/New(var/datum/category_collection/cc)
..()
collection = cc
items = new()
items_by_name = new()
for(var/item_type in typesof(category_item_type))
var/datum/category_item/item = item_type
if(initial(item.name))
item = new item(src)
items += item
items_by_name[item.name] = item
// For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order
// If you change this, confirm that character setup doesn't become completely unordered.

View File

@@ -28,7 +28,6 @@ var/global/datum/getrev/revdata = new()
world.log << branch
world.log << date
world.log << revision
return
client/verb/showrevinfo()
set category = "OOC"
@@ -43,4 +42,3 @@ client/verb/showrevinfo()
src << revdata.revision
else
src << "Revision unknown"
return

View File

@@ -71,6 +71,7 @@
/datum/mind/New(var/key)
src.key = key
..()
/datum/mind/proc/transfer_to(mob/living/new_character)
if(!istype(new_character))

View File

@@ -0,0 +1,11 @@
/****************
* Debug Support *
****************/
var/datum/all_observable_events/all_observable_events = new()
/datum/all_observable_events
var/list/events
/datum/all_observable_events/New()
events = list()
..()

View File

@@ -0,0 +1 @@
#define CANCEL_MOVE_EVENT -55

View File

@@ -0,0 +1,15 @@
// Observer Pattern Implementation: Destroyed
// Registration type: /datum
//
// Raised when: A /datum instance is destroyed.
//
// Arguments that the called proc should expect:
// /datum/destroyed_instance: The instance that was destroyed.
var/decl/observ/destroyed/destroyed_event = new()
/decl/observ/destroyed
name = "Destroyed"
/datum/Destroy()
destroyed_event.raise_event(src)
. = ..()

View File

@@ -0,0 +1,35 @@
// Observer Pattern Implementation: Direction Set
// Registration type: /atom
//
// Raised when: An /atom changes dir using the set_dir() proc.
//
// Arguments that the called proc should expect:
// /atom/dir_changer: The instance that changed direction
// /old_dir: The dir before the change.
// /new_dir: The dir after the change.
var/decl/observ/dir_set/dir_set_event = new()
/decl/observ/dir_set
name = "Direction Set"
expected_type = /atom
/decl/observ/dir_set/register(var/atom/dir_changer, var/datum/listener, var/proc_call)
. = ..()
// Listen to the parent if possible.
if(. && istype(dir_changer.loc, /atom/movable)) // We don't care about registering to turfs.
register(dir_changer.loc, dir_changer, /atom/proc/recursive_dir_set)
/*********************
* Direction Handling *
*********************/
/atom/movable/Entered(var/atom/movable/am, atom/old_loc)
. = ..()
if(. != CANCEL_MOVE_EVENT && dir_set_event.has_listeners(am))
dir_set_event.register(src, am, /atom/proc/recursive_dir_set)
/atom/movable/Exited(var/atom/movable/am, atom/old_loc)
. = ..()
dir_set_event.unregister(src, am, /atom/proc/recursive_dir_set)

View File

@@ -0,0 +1,38 @@
// Observer Pattern Implementation: Equipped
// Registration type: /mob
//
// Raised when: A mob equips an item.
//
// Arguments that the called proc should expect:
// /mob/equipper: The mob that equipped the item.
// /obj/item/item: The equipped item.
// slot: The slot equipped to.
var/decl/observ/mob_equipped/mob_equipped_event = new()
/decl/observ/mob_equipped
name = "Mob Equipped"
expected_type = /mob
// Observer Pattern Implementation: Equipped
// Registration type: /obj/item
//
// Raised when: A mob equips an item.
//
// Arguments that the called proc should expect:
// /obj/item/item: The equipped item.
// /mob/equipper: The mob that equipped the item.
// slot: The slot equipped to.
var/decl/observ/item_equipped/item_equipped_event = new()
/decl/observ/item_equipped
name = "Item Equipped"
expected_type = /obj/item
/********************
* Equipped Handling *
********************/
/obj/item/equipped(var/mob/user, var/slot)
. = ..()
mob_equipped_event.raise_event(user, src, slot)
item_equipped_event.raise_event(src, user, slot)

View File

@@ -0,0 +1,18 @@
/atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc)
moved_event.raise_event(src, old_loc, new_loc)
/atom/movable/proc/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T && T != loc)
forceMove(T)
/atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir)
set_dir(new_dir)
/proc/register_all_movement(var/event_source, var/listener)
moved_event.register(event_source, listener, /atom/movable/proc/recursive_move)
dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set)
/proc/unregister_all_movement(var/event_source, var/listener)
moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move)
dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set)

View File

@@ -0,0 +1,21 @@
// Observer Pattern Implementation: Logged in
// Registration type: /mob
//
// Raised when: A mob logs in (not client)
//
// Arguments that the called proc should expect:
// /mob/joiner: The mob that has logged in
var/decl/observ/logged_in/logged_in_event = new()
/decl/observ/logged_in
name = "Logged In"
expected_type = /mob
/*****************
* Login Handling *
*****************/
/mob/Login()
..()
logged_in_event.raise_event(src)

View File

@@ -0,0 +1,52 @@
// Observer Pattern Implementation: Moved
// Registration type: /atom/movable
//
// Raised when: An /atom/movable instance has moved using Move() or forceMove().
//
// Arguments that the called proc should expect:
// /atom/movable/moving_instance: The instance that moved
// /atom/old_loc: The loc before the move.
// /atom/new_loc: The loc after the move.
var/decl/observ/moved/moved_event = new()
/decl/observ/moved
name = "Moved"
expected_type = /atom/movable
/decl/observ/moved/register(var/atom/movable/mover, var/datum/listener, var/proc_call)
. = ..()
// Listen to the parent if possible.
if(. && istype(mover.loc, expected_type))
register(mover.loc, mover, /atom/movable/proc/recursive_move)
/********************
* Movement Handling *
********************/
/atom/Entered(var/atom/movable/am, var/atom/old_loc)
. = ..()
moved_event.raise_event(am, old_loc, am.loc)
/atom/movable/Entered(var/atom/movable/am, atom/old_loc)
. = ..()
if(moved_event.has_listeners(am))
moved_event.register(src, am, /atom/movable/proc/recursive_move)
/atom/movable/Exited(var/atom/movable/am, atom/old_loc)
. = ..()
moved_event.unregister(src, am, /atom/movable/proc/recursive_move)
// Entered() typically lifts the moved event, but in the case of null-space we'll have to handle it.
/atom/movable/Move()
var/old_loc = loc
. = ..()
if(. && !loc)
moved_event.raise_event(src, old_loc, null)
/atom/movable/forceMove(atom/destination)
var/old_loc = loc
. = ..()
if(. && !loc)
moved_event.raise_event(src, old_loc, null)

View File

@@ -0,0 +1,238 @@
//
// Observer Pattern Implementation
//
// Implements a basic observer pattern with the following main procs:
//
// /decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call)
// event_source: The instance which is generating events.
// listener: The instance which may be listening to events by event_source
// proc_call: Optional. The specific proc to call when the event is raised.
//
// Returns true if listener is listening for events by event_source, and proc_call supplied is either null or one of the proc that will be called when an event is raised.
//
// /decl/observ/proc/has_listeners(var/event_source)
// event_source: The instance which is generating events.
//
// Returns true if the given event_source has any listeners at all, globally or to specific event sources.
//
// /decl/observ/proc/register(var/event_source, var/datum/listener, var/proc_call)
// event_source: The instance you wish to receive events from.
// listener: The instance/owner of the proc to call when an event is raised by the event_source.
// proc_call: The proc to call when an event is raised.
//
// It is possible to register the same listener to the same event_source multiple times as long as it is using different proc_calls.
// Registering again using the same event_source, listener, and proc_call that has been registered previously will have no additional effect.
// I.e.: The proc_call will still only be called once per raised event. That particular proc_call will only have to be unregistered once.
//
// When proc_call is called the first argument is always the source of the event (event_source).
// Additional arguments may or may not be supplied, see individual event definition files (destroyed.dm, moved.dm, etc.) for details.
//
// The instance making the register() call is also responsible for calling unregister(), see below for additonal details, including when event_source is destroyed.
// This can be handled by listening to the event_source's destroyed event, unregistering in the listener's Destroy() proc, etc.
//
// /decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call)
// event_source: The instance you wish to stop receiving events from.
// listener: The instance which will no longer receive the events.
// proc_call: Optional: The proc_call to unregister.
//
// Unregisters the listener from the event_source.
// If a proc_call has been supplied only that particular proc_call will be unregistered. If the proc_call isn't currently registered there will be no effect.
// If no proc_call has been supplied, the listener will have all registrations made to the given event_source undone.
//
// /decl/observ/proc/register_global(var/datum/listener, var/proc_call)
// listener: The instance/owner of the proc to call when an event is raised by any and all sources.
// proc_call: The proc to call when an event is raised.
//
// Works very much the same as register(), only the listener/proc_call will receive all relevant events from all event sources.
// Global registrations can overlap with registrations made to specific event sources and these will not affect each other.
//
// /decl/observ/proc/unregister_global(var/datum/listener, var/proc_call)
// listener: The instance/owner of the proc which will no longer receive the events.
// proc_call: Optional: The proc_call to unregister.
//
// Works very much the same as unregister(), only it undoes global registrations instead.
//
// /decl/observ/proc/raise_event(src, ...)
// Should never be called unless implementing a new event type.
// The first argument shall always be the event_source belonging to the event. Beyond that there are no restrictions.
/decl/observ
var/name = "Unnamed Event" // The name of this event, used mainly for debug/VV purposes. The list of event managers can be reached through the "Debug Controller" verb, selecting the "Observation" entry.
var/expected_type = /datum // The expected event source for this event. register() will CRASH() if it receives an unexpected type.
var/list/event_sources = list() // Associative list of event sources, each with their own associative list. This associative list contains an instance/list of procs to call when the event is raised.
var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call.
/decl/observ/New()
all_observable_events.events += src
. = ..()
/decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call)
// Return whether there are global listeners unless the event source is given.
if (!event_source)
return !!global_listeners.len
// Return whether anything is listening to a source, if no listener is given.
if (!listener)
return global_listeners.len || (event_source in event_sources)
// Return false if nothing is associated with that source.
if (!(event_source in event_sources))
return FALSE
// Get and check the listeners for the reuqested event.
var/listeners = event_sources[event_source]
if (!(listener in listeners))
return FALSE
// Return true unless a specific callback needs checked.
if (!proc_call)
return TRUE
// Check if the specific callback exists.
var/list/callback = listeners[listener]
if (!callback)
return FALSE
return (proc_call in callback)
/decl/observ/proc/has_listeners(var/event_source)
return is_listening(event_source)
/decl/observ/proc/register(var/datum/event_source, var/datum/listener, var/proc_call)
// Sanity checking.
if (!(event_source && listener && proc_call))
return FALSE
if (istype(event_source, /decl/observ))
return FALSE
// Crash if the event source is the wrong type.
if (!istype(event_source, expected_type))
CRASH("Unexpected type. Expected [expected_type], was [event_source.type]")
// Setup the listeners for this source if needed.
var/list/listeners = event_sources[event_source]
if (!listeners)
listeners = list()
event_sources[event_source] = listeners
// Make sure the callbacks are a list.
var/list/callbacks = listeners[listener]
if (!callbacks)
callbacks = list()
listeners[listener] = callbacks
// If the proc_call is already registered skip
if(proc_call in callbacks)
return FALSE
// Add the callback, and return true.
callbacks += proc_call
return TRUE
/decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call)
// Sanity.
if (!(event_source && listener && (event_source in event_sources)))
return FALSE
// Return false if nothing is listening for this event.
var/list/listeners = event_sources[event_source]
if (!listeners)
return FALSE
// Remove all callbacks if no specific one is given.
if (!proc_call)
if(listeners.Remove(listener))
// Perform some cleanup and return true.
if (!listeners.len)
event_sources -= event_source
return TRUE
return FALSE
// See if the listener is registered.
var/list/callbacks = listeners[listener]
if (!callbacks)
return FALSE
// See if the callback exists.
if(!callbacks.Remove(proc_call))
return FALSE
if (!callbacks.len)
listeners -= listener
if (!listeners.len)
event_sources -= event_source
return TRUE
/decl/observ/proc/register_global(var/datum/listener, var/proc_call)
// Sanity.
if (!(listener && proc_call))
return FALSE
// Make sure the callbacks are setup.
var/list/callbacks = global_listeners[listener]
if (!callbacks)
callbacks = list()
global_listeners[listener] = callbacks
// Add the callback and return true.
callbacks |= proc_call
return TRUE
/decl/observ/proc/unregister_global(var/datum/listener, var/proc_call)
// Return false unless the listener is set as a global listener.
if (!(listener && (listener in global_listeners)))
return FALSE
// Remove all callbacks if no specific one is given.
if (!proc_call)
global_listeners -= listener
return TRUE
// See if the listener is registered.
var/list/callbacks = global_listeners[listener]
if (!callbacks)
return FALSE
// See if the callback exists.
if(!callbacks.Remove(proc_call))
return FALSE
if (!callbacks.len)
global_listeners -= listener
return TRUE
/decl/observ/proc/raise_event()
// Sanity
if (!args.len)
return FALSE
// Call the global listeners.
for (var/datum/listener in global_listeners)
var/list/callbacks = global_listeners[listener]
for (var/proc_call in callbacks)
// If the callback crashes, record the error and remove it.
try
call(listener, proc_call)(arglist(args))
catch (var/exception/e)
error("[e.name] - [e.file] - [e.line]")
error(e.desc)
unregister_global(listener, proc_call)
// Call the listeners for this specific event source, if they exist.
var/source = args[1]
if (source in event_sources)
var/list/listeners = event_sources[source]
for (var/datum/listener in listeners)
var/list/callbacks = listeners[listener]
for (var/proc_call in callbacks)
// If the callback crashes, record the error and remove it.
try
call(listener, proc_call)(arglist(args))
catch (var/exception/e)
error("[e.name] - [e.file] - [e.line]")
error(e.desc)
unregister(source, listener, proc_call)
return TRUE

View File

@@ -0,0 +1,13 @@
//
// Observer Pattern Implementation: Scheduled task triggered
// Registration type: /datum/scheduled_task
//
// Raised when: When a scheduled task reaches its trigger time.
//
// Arguments that the called proc should expect:
// /datum/scheduled_task/task: The task that reached its trigger time.
var/decl/observ/task_triggered/task_triggered_event = new()
/decl/observ/task_triggered
name = "Task Triggered"
expected_type = /datum/scheduled_task

View File

@@ -0,0 +1,38 @@
// Observer Pattern Implementation: Unequipped (dropped)
// Registration type: /mob
//
// Raised when: A mob unequips/drops an item.
//
// Arguments that the called proc should expect:
// /mob/equipped: The mob that unequipped/dropped the item.
// /obj/item/item: The unequipped item.
var/decl/observ/mob_unequipped/mob_unequipped_event = new()
/decl/observ/mob_unequipped
name = "Mob Unequipped"
expected_type = /mob
// Observer Pattern Implementation: Unequipped (dropped)
// Registration type: /obj/item
//
// Raised when: A mob unequips/drops an item.
//
// Arguments that the called proc should expect:
// /obj/item/item: The unequipped item.
// /mob/equipped: The mob that unequipped/dropped the item.
var/decl/observ/item_unequipped/item_unequipped_event = new()
/decl/observ/item_unequipped
name = "Item Unequipped"
expected_type = /obj/item
/**********************
* Unequipped Handling *
**********************/
/obj/item/dropped(var/mob/user)
..()
mob_unequipped_event.raise_event(user, src)
item_unequipped_event.raise_event(src, user)

View File

@@ -0,0 +1,70 @@
var/list/global_listen_count = list()
var/list/event_sources_count = list()
var/list/event_listen_count = list()
/decl/observ/destroyed/raise_event()
. = ..()
if(!.)
return
var/source = args[1]
if(global_listen_count[source])
cleanup_global_listener(source, global_listen_count[source])
if(event_sources_count[source])
cleanup_source_listeners(source, event_sources_count[source])
if(event_listen_count[source])
cleanup_event_listener(source, event_listen_count[source])
/decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call)
. = ..()
if(.)
event_sources_count[event_source] += 1
event_listen_count[listener] += 1
/decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call)
. = ..()
if(.)
event_sources_count[event_source] -= 1
event_listen_count[listener] -= 1
/decl/observ/register_global(var/datum/listener, var/proc_call)
. = ..()
if(.)
global_listen_count[listener] += 1
/decl/observ/unregister_global(var/datum/listener, var/proc_call)
. = ..()
if(.)
global_listen_count[listener] -= 1
/decl/observ/destroyed/proc/cleanup_global_listener(listener, listen_count)
global_listen_count -= listener
for(var/entry in all_observable_events.events)
var/decl/observ/event = entry
if(event.unregister_global(listener))
log_debug("[event] - [listener] was deleted while still registered to global events.")
if(!(--listen_count))
return
/decl/observ/destroyed/proc/cleanup_source_listeners(event_source, source_listener_count)
event_sources_count -= event_source
for(var/entry in all_observable_events.events)
var/decl/observ/event = entry
var/proc_owners = event.event_sources[event_source]
if(proc_owners)
for(var/proc_owner in proc_owners)
if(event.unregister(event_source, proc_owner))
log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].")
if(!(--source_listener_count))
return
/decl/observ/destroyed/proc/cleanup_event_listener(listener, listener_count)
event_listen_count -= listener
for(var/entry in all_observable_events.events)
var/decl/observ/event = entry
for(var/event_source in event.event_sources)
if(event.unregister(event_source, listener))
log_debug("[event] - [listener] was deleted while still listening to [event_source].")
if(!(--listener_count))
return

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
/*
* Here is where any supply packs related
* to being atmospherics tasks live.
*/
/datum/supply_packs/atmos
group = "Atmospherics"
/datum/supply_packs/atmos/inflatable
name = "Inflatable barriers"
contains = list(/obj/item/weapon/storage/briefcase/inflatable = 3)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Inflatable Barrier Crate"
/datum/supply_packs/atmos/canister_empty
name = "Empty gas canister"
cost = 7
containername = "Empty gas canister crate"
containertype = /obj/structure/largecrate
contains = list(/obj/machinery/portable_atmospherics/canister)
/datum/supply_packs/atmos/canister_air
name = "Air canister"
cost = 10
containername = "Air canister crate"
containertype = /obj/structure/largecrate
contains = list(/obj/machinery/portable_atmospherics/canister/air)
/datum/supply_packs/atmos/canister_oxygen
name = "Oxygen canister"
cost = 15
containername = "Oxygen canister crate"
containertype = /obj/structure/largecrate
contains = list(/obj/machinery/portable_atmospherics/canister/oxygen)
/datum/supply_packs/atmos/canister_nitrogen
name = "Nitrogen canister"
cost = 10
containername = "Nitrogen canister crate"
containertype = /obj/structure/largecrate
contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen)
/datum/supply_packs/atmos/canister_phoron
name = "Phoron gas canister"
cost = 60
containername = "Phoron gas canister crate"
containertype = /obj/structure/closet/crate/secure/large
access = access_atmospherics
contains = list(/obj/machinery/portable_atmospherics/canister/phoron)
/datum/supply_packs/atmos/canister_sleeping_agent
name = "N2O gas canister"
cost = 40
containername = "N2O gas canister crate"
containertype = /obj/structure/closet/crate/secure/large
access = access_atmospherics
contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent)
/datum/supply_packs/atmos/canister_carbon_dioxide
name = "Carbon dioxide gas canister"
cost = 40
containername = "CO2 canister crate"
containertype = /obj/structure/closet/crate/secure/large
access = access_atmospherics
contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide)
/datum/supply_packs/atmos/air_dispenser
contains = list(/obj/machinery/pipedispenser/orderable)
name = "Pipe Dispenser"
cost = 35
containertype = /obj/structure/closet/crate/secure/large
containername = "Pipe Dispenser Crate"
access = access_atmospherics
/datum/supply_packs/atmos/disposals_dispenser
contains = list(/obj/machinery/pipedispenser/disposal/orderable)
name = "Disposals Pipe Dispenser"
cost = 35
containertype = /obj/structure/closet/crate/secure/large
containername = "Disposal Dispenser Crate"
access = access_atmospherics

View File

@@ -0,0 +1,45 @@
/*
* Here is where any supply packs that may or may not be legal
* and require modification of the supply controller live.
*/
/datum/supply_packs/randomised/contraband
num_contained = 5
contains = list(
/obj/item/seeds/bloodtomatoseed,
/obj/item/weapon/storage/pill_bottle/zoom,
/obj/item/weapon/storage/pill_bottle/happy,
/obj/item/weapon/reagent_containers/food/drinks/bottle/pwine
)
name = "Contraband crate"
cost = 30
containertype = /obj/structure/closet/crate
containername = "Unlabeled crate"
contraband = 1
group = "Supplies"
/datum/supply_packs/security/specialops
name = "Special Ops supplies"
contains = list(
/obj/item/weapon/storage/box/emps,
/obj/item/weapon/grenade/smokebomb = 3,
/obj/item/weapon/pen/reagent/paralysis,
/obj/item/weapon/grenade/chem_grenade/incendiary
)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Special Ops crate"
hidden = 1
/datum/supply_packs/security/bolt_rifles_mosin
name = "Surplus militia rifles"
contains = list(
/obj/item/weapon/gun/projectile/shotgun/pump/rifle/mosin = 3,
/obj/item/ammo_magazine/clip/a762 = 6
)
cost = 50
hidden = 1
containertype = /obj/structure/closet/crate/secure/weapon
containername = "Weapons crate"

View File

@@ -0,0 +1,165 @@
/*
* Here is where any supply packs
* related to weapons live.
*/
/datum/supply_packs/costumes
group = "Costumes"
/datum/supply_packs/randomised/costumes
group = "Costumes"
/datum/supply_packs/costumes/wizard
name = "Wizard costume"
contains = list(
/obj/item/weapon/staff,
/obj/item/clothing/suit/wizrobe/fake,
/obj/item/clothing/shoes/sandal,
/obj/item/clothing/head/wizard/fake
)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Wizard costume crate"
/datum/supply_packs/randomised/costumes/hats
num_contained = 4
contains = list(
/obj/item/clothing/head/collectable/chef,
/obj/item/clothing/head/collectable/paper,
/obj/item/clothing/head/collectable/tophat,
/obj/item/clothing/head/collectable/captain,
/obj/item/clothing/head/collectable/beret,
/obj/item/clothing/head/collectable/welding,
/obj/item/clothing/head/collectable/flatcap,
/obj/item/clothing/head/collectable/pirate,
/obj/item/clothing/head/collectable/kitty,
/obj/item/clothing/head/collectable/rabbitears,
/obj/item/clothing/head/collectable/wizard,
/obj/item/clothing/head/collectable/hardhat,
/obj/item/clothing/head/collectable/HoS,
/obj/item/clothing/head/collectable/thunderdome,
/obj/item/clothing/head/collectable/swat,
/obj/item/clothing/head/collectable/slime,
/obj/item/clothing/head/collectable/police,
/obj/item/clothing/head/collectable/slime,
/obj/item/clothing/head/collectable/xenom,
/obj/item/clothing/head/collectable/petehat
)
name = "Collectable hat crate!"
cost = 200
containertype = /obj/structure/closet/crate
containername = "Collectable hats crate! Brought to you by Bass.inc!"
/datum/supply_packs/randomised/costumes/costume
num_contained = 3
contains = list(
/obj/item/clothing/suit/pirate,
/obj/item/clothing/suit/judgerobe,
/obj/item/clothing/suit/wcoat,
/obj/item/clothing/suit/hastur,
/obj/item/clothing/suit/holidaypriest,
/obj/item/clothing/suit/nun,
/obj/item/clothing/suit/imperium_monk,
/obj/item/clothing/suit/ianshirt,
/obj/item/clothing/under/gimmick/rank/captain/suit,
/obj/item/clothing/under/gimmick/rank/head_of_personnel/suit,
/obj/item/clothing/under/lawyer/purpsuit,
/obj/item/clothing/under/rank/mailman,
/obj/item/clothing/under/dress/dress_saloon,
/obj/item/clothing/suit/suspenders,
/obj/item/clothing/suit/storage/toggle/labcoat/mad,
/obj/item/clothing/suit/bio_suit/plaguedoctorsuit,
/obj/item/clothing/under/schoolgirl,
/obj/item/clothing/under/owl,
/obj/item/clothing/under/waiter,
/obj/item/clothing/under/gladiator,
/obj/item/clothing/under/soviet,
/obj/item/clothing/under/scratch,
/obj/item/clothing/under/wedding/bride_white,
/obj/item/clothing/suit/chef,
/obj/item/clothing/suit/apron/overalls,
/obj/item/clothing/under/redcoat,
/obj/item/clothing/under/kilt
)
name = "Costumes crate"
cost = 10
containertype = /obj/structure/closet/crate
containername = "Actor Costumes"
/datum/supply_packs/costumes/formal_wear
contains = list(
/obj/item/clothing/head/bowler,
/obj/item/clothing/head/that,
/obj/item/clothing/suit/storage/toggle/internalaffairs,
/obj/item/clothing/suit/storage/toggle/lawyer/bluejacket,
/obj/item/clothing/suit/storage/toggle/lawyer/purpjacket,
/obj/item/clothing/under/suit_jacket,
/obj/item/clothing/under/suit_jacket/female,
/obj/item/clothing/under/suit_jacket/really_black,
/obj/item/clothing/under/suit_jacket/red,
/obj/item/clothing/under/lawyer/bluesuit,
/obj/item/clothing/under/lawyer/purpsuit,
/obj/item/clothing/shoes/black = 2,
/obj/item/clothing/shoes/leather,
/obj/item/clothing/suit/wcoat
)
name = "Formalwear closet"
cost = 30
containertype = /obj/structure/closet
containername = "Formalwear for the best occasions."
datum/supply_packs/costumes/witch
name = "Witch costume"
containername = "Witch costume"
containertype = /obj/structure/closet
cost = 20
contains = list(
/obj/item/clothing/suit/wizrobe/marisa/fake,
/obj/item/clothing/shoes/sandal,
/obj/item/clothing/head/wizard/marisa/fake,
/obj/item/weapon/staff/broom
)
/datum/supply_packs/randomised/costumes/costume_hats
name = "Costume hats"
containername = "Actor hats crate"
containertype = /obj/structure/closet
cost = 10
num_contained = 3
contains = list(
/obj/item/clothing/head/redcoat,
/obj/item/clothing/head/mailman,
/obj/item/clothing/head/plaguedoctorhat,
/obj/item/clothing/head/pirate,
/obj/item/clothing/head/hasturhood,
/obj/item/clothing/head/powdered_wig,
/obj/item/clothing/head/hairflower,
/obj/item/clothing/head/hairflower/yellow,
/obj/item/clothing/head/hairflower/blue,
/obj/item/clothing/head/hairflower/pink,
/obj/item/clothing/mask/gas/owl_mask,
/obj/item/clothing/mask/gas/monkeymask,
/obj/item/clothing/head/helmet/gladiator,
/obj/item/clothing/head/ushanka
)
/datum/supply_packs/randomised/costumes/dresses
name = "Womens formal dress locker"
containername = "Pretty dress locker"
containertype = /obj/structure/closet
cost = 15
num_contained = 3
contains = list(
/obj/item/clothing/under/wedding/bride_orange,
/obj/item/clothing/under/wedding/bride_purple,
/obj/item/clothing/under/wedding/bride_blue,
/obj/item/clothing/under/wedding/bride_red,
/obj/item/clothing/under/wedding/bride_white,
/obj/item/clothing/under/sundress,
/obj/item/clothing/under/dress/dress_green,
/obj/item/clothing/under/dress/dress_pink,
/obj/item/clothing/under/dress/dress_orange,
/obj/item/clothing/under/dress/dress_yellow,
/obj/item/clothing/under/dress/dress_saloon
)

View File

@@ -0,0 +1,192 @@
/*
* Here is where any supply packs
* related to engineering tasks live.
*/
/datum/supply_packs/eng
group = "Engineering"
/datum/supply_packs/eng/lightbulbs
name = "Replacement lights"
contains = list(/obj/item/weapon/storage/box/lights/mixed = 3)
cost = 10
containertype = /obj/structure/closet/crate
containername = "Replacement lights"
/datum/supply_packs/eng/smescoil
name = "Superconducting Magnetic Coil"
contains = list(/obj/item/weapon/smes_coil)
cost = 75
containertype = /obj/structure/closet/crate
containername = "Superconducting Magnetic Coil crate"
/datum/supply_packs/eng/electrical
name = "Electrical maintenance crate"
contains = list(
/obj/item/weapon/storage/toolbox/electrical = 2,
/obj/item/clothing/gloves/yellow = 2,
/obj/item/weapon/cell = 2,
/obj/item/weapon/cell/high = 2
)
cost = 15
containertype = /obj/structure/closet/crate
containername = "Electrical maintenance crate"
/datum/supply_packs/eng/mechanical
name = "Mechanical maintenance crate"
contains = list(
/obj/item/weapon/storage/belt/utility/full = 3,
/obj/item/clothing/suit/storage/hazardvest = 3,
/obj/item/clothing/head/welding = 2,
/obj/item/clothing/head/hardhat
)
cost = 10
containertype = /obj/structure/closet/crate
containername = "Mechanical maintenance crate"
/datum/supply_packs/eng/fueltank
name = "Fuel tank crate"
contains = list(/obj/structure/reagent_dispensers/fueltank)
cost = 8
containertype = /obj/structure/largecrate
containername = "fuel tank crate"
/datum/supply_packs/eng/solar
name = "Solar Pack crate"
contains = list(
/obj/item/solar_assembly = 21,
/obj/item/weapon/circuitboard/solar_control,
/obj/item/weapon/tracker_electronics,
/obj/item/weapon/paper/solar
)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Solar pack crate"
/datum/supply_packs/eng/engine
name = "Emitter crate"
contains = list(/obj/machinery/power/emitter = 2)
cost = 10
containertype = /obj/structure/closet/crate/secure
containername = "Emitter crate"
access = access_ce
/datum/supply_packs/engine/eng/field_gen
name = "Field Generator crate"
contains = list(/obj/machinery/field_generator = 2)
containertype = /obj/structure/closet/crate/secure
containername = "Field Generator crate"
access = access_ce
/datum/supply_packs/eng/engine/sing_gen
name = "Singularity Generator crate"
contains = list(/obj/machinery/the_singularitygen)
containertype = /obj/structure/closet/crate/secure
containername = "Singularity Generator crate"
access = access_ce
/datum/supply_packs/eng/engine/collector
name = "Collector crate"
contains = list(/obj/machinery/power/rad_collector = 3)
containername = "Collector crate"
/datum/supply_packs/eng/engine/PA
name = "Particle Accelerator crate"
cost = 40
contains = list(
/obj/structure/particle_accelerator/fuel_chamber,
/obj/machinery/particle_accelerator/control_box,
/obj/structure/particle_accelerator/particle_emitter/center,
/obj/structure/particle_accelerator/particle_emitter/left,
/obj/structure/particle_accelerator/particle_emitter/right,
/obj/structure/particle_accelerator/power_box,
/obj/structure/particle_accelerator/end_cap
)
containertype = /obj/structure/closet/crate/secure
containername = "Particle Accelerator crate"
access = access_ce
/datum/supply_packs/eng/shield_gen
contains = list(/obj/item/weapon/circuitboard/shield_gen)
name = "Bubble shield generator circuitry"
cost = 50
containertype = /obj/structure/closet/crate/secure
containername = "bubble shield generator circuitry crate"
access = access_ce
/datum/supply_packs/eng/shield_gen_ex
contains = list(/obj/item/weapon/circuitboard/shield_gen_ex)
name = "Hull shield generator circuitry"
cost = 50
containertype = /obj/structure/closet/crate/secure
containername = "hull shield generator circuitry crate"
access = access_ce
/datum/supply_packs/eng/shield_cap
contains = list(/obj/item/weapon/circuitboard/shield_cap)
name = "Bubble shield capacitor circuitry"
cost = 50
containertype = /obj/structure/closet/crate/secure
containername = "shield capacitor circuitry crate"
access = access_ce
/datum/supply_packs/eng/smbig
name = "Supermatter Core"
contains = list(/obj/machinery/power/supermatter)
cost = 150
containertype = /obj/structure/closet/crate/secure/phoron
containername = "Supermatter crate (CAUTION)"
access = access_ce
/datum/supply_packs/eng/teg
contains = list(/obj/machinery/power/generator)
name = "Mark I Thermoelectric Generator"
cost = 75
containertype = /obj/structure/closet/crate/secure/large
containername = "Mk1 TEG crate"
access = access_engine
/datum/supply_packs/eng/circulator
contains = list(/obj/machinery/atmospherics/binary/circulator)
name = "Binary atmospheric circulator"
cost = 60
containertype = /obj/structure/closet/crate/secure/large
containername = "Atmospheric circulator crate"
access = access_engine
/datum/supply_packs/eng/radsuit
contains = list(
/obj/item/clothing/suit/radiation = 3,
/obj/item/clothing/head/radiation = 3
)
name = "Radiation suits package"
cost = 20
containertype = /obj/structure/closet/radiation
containername = "Radiation suit locker"
/datum/supply_packs/eng/pacman_parts
name = "P.A.C.M.A.N. portable generator parts"
cost = 45
containername = "P.A.C.M.A.N. Portable Generator Construction Kit"
containertype = /obj/structure/closet/crate/secure
access = access_tech_storage
contains = list(
/obj/item/weapon/stock_parts/micro_laser,
/obj/item/weapon/stock_parts/capacitor,
/obj/item/weapon/stock_parts/matter_bin,
/obj/item/weapon/circuitboard/pacman
)
/datum/supply_packs/eng/super_pacman_parts
name = "Super P.A.C.M.A.N. portable generator parts"
cost = 55
containername = "Super P.A.C.M.A.N. portable generator construction kit"
containertype = /obj/structure/closet/crate/secure
access = access_tech_storage
contains = list(
/obj/item/weapon/stock_parts/micro_laser,
/obj/item/weapon/stock_parts/capacitor,
/obj/item/weapon/stock_parts/matter_bin,
/obj/item/weapon/circuitboard/pacman/super
)

View File

@@ -0,0 +1,62 @@
/*
* Here is where any supply packs related
* to being hospitable tasks live
*/
/datum/supply_packs/hospitality
group = "Hospitality"
/datum/supply_packs/hospitality/party
name = "Party equipment"
contains = list(
/obj/item/weapon/storage/box/mixedglasses = 2,
/obj/item/weapon/storage/box/glasses/square,
/obj/item/weapon/reagent_containers/food/drinks/shaker,
/obj/item/weapon/reagent_containers/food/drinks/flask/barflask,
/obj/item/weapon/reagent_containers/food/drinks/bottle/patron,
/obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager,
/obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey,
/obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
/obj/item/weapon/lipstick/random,
/obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale = 2,
/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 4,
)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Party equipment"
/datum/supply_packs/hospitality/barsupplies
name = "Bar supplies"
contains = list(
/obj/item/weapon/storage/box/glasses/cocktail,
/obj/item/weapon/storage/box/glasses/rocks,
/obj/item/weapon/storage/box/glasses/square,
/obj/item/weapon/storage/box/glasses/pint,
/obj/item/weapon/storage/box/glasses/wine,
/obj/item/weapon/storage/box/glasses/shake,
/obj/item/weapon/storage/box/glasses/shot,
/obj/item/weapon/storage/box/glasses/mug,
/obj/item/weapon/reagent_containers/food/drinks/shaker,
/obj/item/weapon/storage/box/glass_extras/straws,
/obj/item/weapon/storage/box/glass_extras/sticks
)
cost = 10
containertype = /obj/structure/closet/crate
containername = "crate of bar supplies"
/datum/supply_packs/randomised/hospitality/
group = "Hospitality"
/datum/supply_packs/randomised/hospitality/pizza
num_contained = 5
contains = list(
/obj/item/pizzabox/margherita,
/obj/item/pizzabox/mushroom,
/obj/item/pizzabox/meat,
/obj/item/pizzabox/vegetable
)
name = "Surprise pack of five pizzas"
cost = 15
containertype = /obj/structure/closet/crate/freezer
containername = "Pizza crate"

View File

@@ -0,0 +1,149 @@
/*
* Here is where any supply packs
* related to hydroponics tasks live.
*/
/datum/supply_packs/hydro
group = "Hydroponics"
/datum/supply_packs/hydro/monkey
name = "Monkey crate"
contains = list (/obj/item/weapon/storage/box/monkeycubes)
cost = 20
containertype = /obj/structure/closet/crate/freezer
containername = "Monkey crate"
/datum/supply_packs/hydro/farwa
name = "Farwa crate"
contains = list (/obj/item/weapon/storage/box/monkeycubes/farwacubes)
cost = 30
containertype = /obj/structure/closet/crate/freezer
containername = "Farwa crate"
/datum/supply_packs/hydro/neara
name = "Neaera crate"
contains = list (/obj/item/weapon/storage/box/monkeycubes/neaeracubes)
cost = 30
containertype = /obj/structure/closet/crate/freezer
containername = "Neaera crate"
/datum/supply_packs/hydro/stok
name = "Stok crate"
contains = list (/obj/item/weapon/storage/box/monkeycubes/stokcubes)
cost = 30
containertype = /obj/structure/closet/crate/freezer
containername = "Stok crate"
/datum/supply_packs/hydro/lisa
name = "Corgi Crate"
contains = list()
cost = 50
containertype = /obj/structure/largecrate/animal/corgi
containername = "Corgi Crate"
/datum/supply_packs/hydro/hydroponics
name = "Hydroponics Supply Crate"
contains = list(
/obj/item/weapon/reagent_containers/spray/plantbgone = 4,
/obj/item/weapon/reagent_containers/glass/bottle/ammonia = 2,
/obj/item/weapon/material/hatchet,
/obj/item/weapon/material/minihoe,
/obj/item/device/analyzer/plant_analyzer,
/obj/item/clothing/gloves/botanic_leather,
/obj/item/clothing/suit/apron,
/obj/item/weapon/material/minihoe,
/obj/item/weapon/storage/box/botanydisk
)
cost = 15
containertype = /obj/structure/closet/crate/hydroponics
containername = "Hydroponics crate"
access = access_hydroponics
/datum/supply_packs/hydro/cow
name = "Cow crate"
cost = 30
containertype = /obj/structure/largecrate/animal/cow
containername = "Cow crate"
access = access_hydroponics
/datum/supply_packs/hydro/goat
name = "Goat crate"
cost = 25
containertype = /obj/structure/largecrate/animal/goat
containername = "Goat crate"
access = access_hydroponics
/datum/supply_packs/hydro/chicken
name = "Chicken crate"
cost = 20
containertype = /obj/structure/largecrate/animal/chick
containername = "Chicken crate"
access = access_hydroponics
/datum/supply_packs/hydro/seeds
name = "Seeds crate"
contains = list(
/obj/item/seeds/chiliseed,
/obj/item/seeds/berryseed,
/obj/item/seeds/cornseed,
/obj/item/seeds/eggplantseed,
/obj/item/seeds/tomatoseed,
/obj/item/seeds/appleseed,
/obj/item/seeds/soyaseed,
/obj/item/seeds/wheatseed,
/obj/item/seeds/carrotseed,
/obj/item/seeds/harebell,
/obj/item/seeds/lemonseed,
/obj/item/seeds/orangeseed,
/obj/item/seeds/grassseed,
/obj/item/seeds/sunflowerseed,
/obj/item/seeds/chantermycelium,
/obj/item/seeds/potatoseed,
/obj/item/seeds/sugarcaneseed
)
cost = 10
containertype = /obj/structure/closet/crate/hydroponics
containername = "Seeds crate"
access = access_hydroponics
/datum/supply_packs/hydro/weedcontrol
name = "Weed control crate"
contains = list(
/obj/item/weapon/material/hatchet = 2,
/obj/item/weapon/reagent_containers/spray/plantbgone = 4,
/obj/item/clothing/mask/gas = 2,
/obj/item/weapon/grenade/chem_grenade/antiweed = 2
)
cost = 25
containertype = /obj/structure/closet/crate/hydroponics
containername = "Weed control crate"
access = access_hydroponics
/datum/supply_packs/hydro/watertank
name = "Water tank crate"
contains = list(/obj/structure/reagent_dispensers/watertank)
cost = 8
containertype = /obj/structure/largecrate
containername = "water tank crate"
/datum/supply_packs/hydro/bee_keeper
name = "Beekeeping crate"
contains = list(
/obj/item/beehive_assembly,
/obj/item/bee_smoker,
/obj/item/honey_frame = 5,
/obj/item/bee_pack
)
cost = 40
containertype = /obj/structure/closet/crate/hydroponics
containername = "Beekeeping crate"
access = access_hydroponics
/datum/supply_packs/hydro/tray
name = "Empty hydroponics tray"
cost = 30
containertype = /obj/structure/closet/crate/hydroponics
containername = "Hydroponics tray crate"
contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0})
access = access_hydroponics

View File

@@ -0,0 +1,68 @@
/*
* Here is where any supply packs
* related to materials live.
*/
/datum/supply_packs/materials
group = "Materials"
/datum/supply_packs/materials/metal50
name = "50 metal sheets"
contains = list(/obj/item/stack/material/steel)
amount = 50
cost = 10
containertype = /obj/structure/closet/crate
containername = "Metal sheets crate"
/datum/supply_packs/materials/glass50
name = "50 glass sheets"
contains = list(/obj/item/stack/material/glass)
amount = 50
cost = 10
containertype = /obj/structure/closet/crate
containername = "Glass sheets crate"
/datum/supply_packs/materials/wood50
name = "50 wooden planks"
contains = list(/obj/item/stack/material/wood)
amount = 50
cost = 10
containertype = /obj/structure/closet/crate
containername = "Wooden planks crate"
/datum/supply_packs/materials/plastic50
name = "50 plastic sheets"
contains = list(/obj/item/stack/material/plastic)
amount = 50
cost = 10
containertype = /obj/structure/closet/crate
containername = "Plastic sheets crate"
/datum/supply_packs/materials/cardboard_sheets
contains = list(/obj/item/stack/material/cardboard)
name = "50 cardboard sheets"
amount = 50
cost = 10
containertype = /obj/structure/closet/crate
containername = "Cardboard sheets crate"
/datum/supply_packs/materials/carpet
name = "Imported carpet"
containertype = /obj/structure/closet/crate
containername = "Imported carpet crate"
cost = 15
contains = list(
/obj/item/stack/tile/carpet,
/obj/item/stack/tile/carpet/blue
)
amount = 50
/datum/supply_packs/misc/linoleum
name = "Linoleum"
containertype = /obj/structure/closet/crate
containername = "Linoleum crate"
cost = 15
contains = list(/obj/item/stack/tile/linoleum)
amount = 50

View File

@@ -0,0 +1,309 @@
/*
* Here is where any supply packs
* related to medical tasks live.
*/
/datum/supply_packs/med
group = "Medical"
/datum/supply_packs/med/medical
name = "Medical crate"
contains = list(
/obj/item/weapon/storage/firstaid/regular,
/obj/item/weapon/storage/firstaid/fire,
/obj/item/weapon/storage/firstaid/toxin,
/obj/item/weapon/storage/firstaid/o2,
/obj/item/weapon/storage/firstaid/adv,
/obj/item/weapon/reagent_containers/glass/bottle/antitoxin,
/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline,
/obj/item/weapon/reagent_containers/glass/bottle/stoxin,
/obj/item/weapon/storage/box/syringes,
/obj/item/weapon/storage/box/autoinjectors
)
cost = 10
containertype = /obj/structure/closet/crate/medical
containername = "Medical crate"
/datum/supply_packs/med/bloodpack
name = "BloodPack crate"
contains = list(/obj/item/weapon/storage/box/bloodpacks = 3)
cost = 10
containertype = /obj/structure/closet/crate/medical
containername = "BloodPack crate"
/datum/supply_packs/med/bodybag
name = "Body bag crate"
contains = list(/obj/item/weapon/storage/box/bodybags = 3)
cost = 10
containertype = /obj/structure/closet/crate/medical
containername = "Body bag crate"
/datum/supply_packs/med/cryobag
name = "Stasis bag crate"
contains = list(/obj/item/bodybag/cryobag = 3)
cost = 50
containertype = /obj/structure/closet/crate/medical
containername = "Stasis bag crate"
/datum/supply_packs/med/surgery
name = "Surgery crate"
contains = list(
/obj/item/weapon/cautery,
/obj/item/weapon/surgicaldrill,
/obj/item/clothing/mask/breath/medical,
/obj/item/weapon/tank/anesthetic,
/obj/item/weapon/FixOVein,
/obj/item/weapon/hemostat,
/obj/item/weapon/scalpel,
/obj/item/weapon/bonegel,
/obj/item/weapon/retractor,
/obj/item/weapon/bonesetter,
/obj/item/weapon/circular_saw
)
cost = 25
containertype = "/obj/structure/closet/crate/secure"
containername = "Surgery crate"
access = access_medical
/datum/supply_packs/med/sterile
name = "Sterile equipment crate"
contains = list(
/obj/item/clothing/under/rank/medical/green = 2,
/obj/item/clothing/head/surgery/green = 2,
/obj/item/weapon/storage/box/masks,
/obj/item/weapon/storage/box/gloves,
/obj/item/weapon/storage/belt/medical = 3
)
cost = 15
containertype = "/obj/structure/closet/crate"
containername = "Sterile equipment crate"
/datum/supply_packs/med/extragear
name = "Medical surplus equipment"
contains = list(
/obj/item/weapon/storage/belt/medical = 3,
/obj/item/clothing/glasses/hud/health = 3,
/obj/item/device/radio/headset/headset_med/alt = 3,
/obj/item/clothing/suit/storage/hooded/wintercoat/medical = 3
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Medical surplus equipment"
access = access_medical
/datum/supply_packs/med/cmogear
name = "Chief medical officer equipment"
contains = list(
/obj/item/weapon/storage/belt/medical,
/obj/item/device/radio/headset/heads/cmo,
/obj/item/clothing/under/rank/chief_medical_officer,
/obj/item/weapon/reagent_containers/hypospray,
/obj/item/clothing/accessory/stethoscope,
/obj/item/clothing/glasses/hud/health,
/obj/item/clothing/suit/storage/toggle/labcoat/cmo,
/obj/item/clothing/suit/storage/toggle/labcoat/cmoalt,
/obj/item/clothing/mask/surgical,
/obj/item/clothing/shoes/white,
/obj/item/weapon/cartridge/cmo,
/obj/item/clothing/gloves/latex,
/obj/item/device/healthanalyzer,
/obj/item/device/flashlight/pen,
/obj/item/weapon/reagent_containers/syringe
)
cost = 60
containertype = "/obj/structure/closet/crate/secure"
containername = "Chief medical officer equipment"
access = access_cmo
/datum/supply_packs/med/doctorgear
name = "Medical Doctor equipment"
contains = list(
/obj/item/weapon/storage/belt/medical,
/obj/item/device/radio/headset/headset_med,
/obj/item/clothing/under/rank/medical,
/obj/item/clothing/accessory/stethoscope,
/obj/item/clothing/glasses/hud/health,
/obj/item/clothing/suit/storage/toggle/labcoat,
/obj/item/clothing/mask/surgical,
/obj/item/weapon/storage/firstaid/adv,
/obj/item/clothing/shoes/white,
/obj/item/weapon/cartridge/medical,
/obj/item/clothing/gloves/latex,
/obj/item/device/healthanalyzer,
/obj/item/device/flashlight/pen,
/obj/item/weapon/reagent_containers/syringe
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Medical Doctor equipment"
access = access_medical_equip
/datum/supply_packs/med/chemistgear
name = "Chemist equipment"
contains = list(
/obj/item/weapon/storage/box/beakers,
/obj/item/device/radio/headset/headset_med,
/obj/item/weapon/storage/box/autoinjectors,
/obj/item/clothing/under/rank/chemist,
/obj/item/clothing/glasses/science,
/obj/item/clothing/suit/storage/toggle/labcoat/chemist,
/obj/item/clothing/mask/surgical,
/obj/item/clothing/shoes/white,
/obj/item/weapon/cartridge/chemistry,
/obj/item/clothing/gloves/latex,
/obj/item/weapon/reagent_containers/dropper,
/obj/item/device/healthanalyzer,
/obj/item/weapon/storage/box/pillbottles,
/obj/item/weapon/reagent_containers/syringe
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Chemist equipment"
access = access_chemistry
/datum/supply_packs/med/paramedicgear
name = "Paramedic equipment"
contains = list(
/obj/item/weapon/storage/belt/medical/emt,
/obj/item/device/radio/headset/headset_med,
/obj/item/clothing/under/rank/medical/black,
/obj/item/clothing/accessory/armband/medgreen,
/obj/item/clothing/glasses/hud/health,
/obj/item/clothing/suit/storage/toggle/labcoat/emt,
/obj/item/clothing/under/rank/medical/paramedic,
/obj/item/clothing/suit/storage/toggle/fr_jacket,
/obj/item/clothing/mask/gas,
/obj/item/clothing/under/rank/medical/paramedic,
/obj/item/clothing/accessory/stethoscope,
/obj/item/weapon/storage/firstaid/adv,
/obj/item/clothing/shoes/jackboots,
/obj/item/clothing/gloves/latex,
/obj/item/device/healthanalyzer,
/obj/item/weapon/cartridge/medical,
/obj/item/device/flashlight/pen,
/obj/item/weapon/reagent_containers/syringe,
/obj/item/clothing/accessory/storage/white_vest
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Paramedic equipment"
access = access_medical_equip
/datum/supply_packs/med/psychiatristgear
name = "Psychiatrist equipment"
contains = list(
/obj/item/clothing/under/rank/psych,
/obj/item/device/radio/headset/headset_med,
/obj/item/clothing/under/rank/psych/turtleneck,
/obj/item/clothing/shoes/laceup,
/obj/item/clothing/suit/storage/toggle/labcoat,
/obj/item/clothing/shoes/white,
/obj/item/weapon/clipboard,
/obj/item/weapon/folder/white,
/obj/item/weapon/pen,
/obj/item/weapon/cartridge/medical
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Psychiatrist equipment"
access = access_psychiatrist
/datum/supply_packs/med/medicalscrubs
name = "Medical scrubs"
contains = list(
/obj/item/clothing/shoes/white = 3,,
/obj/item/clothing/under/rank/medical/blue = 3,
/obj/item/clothing/under/rank/medical/green = 3,
/obj/item/clothing/under/rank/medical/purple = 3,
/obj/item/clothing/under/rank/medical/black = 3,
/obj/item/clothing/head/surgery = 3,
/obj/item/clothing/head/surgery/purple = 3,
/obj/item/clothing/head/surgery/blue = 3,
/obj/item/clothing/head/surgery/green = 3,
/obj/item/clothing/head/surgery/black = 3,
/obj/item/weapon/storage/box/masks,
/obj/item/weapon/storage/box/gloves
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Medical scrubs crate"
access = access_medical_equip
/datum/supply_packs/med/autopsy
name = "Autopsy equipment"
contains = list(
/obj/item/weapon/folder/white,
/obj/item/device/camera,
/obj/item/device/camera_film = 2,
/obj/item/weapon/autopsy_scanner,
/obj/item/weapon/scalpel,
/obj/item/weapon/storage/box/masks,
/obj/item/weapon/storage/box/gloves,
/obj/item/weapon/pen
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Autopsy equipment crate"
access = access_morgue
/datum/supply_packs/med/medicaluniforms
name = "Medical uniforms"
contains = list(
/obj/item/clothing/shoes/white = 3,
/obj/item/clothing/under/rank/chief_medical_officer,
/obj/item/clothing/under/rank/geneticist,
/obj/item/clothing/under/rank/virologist,
/obj/item/clothing/under/rank/nursesuit,
/obj/item/clothing/under/rank/nurse,
/obj/item/clothing/under/rank/orderly,
/obj/item/clothing/under/rank/medical = 3,
/obj/item/clothing/under/rank/medical/paramedic = 3,
/obj/item/clothing/suit/storage/toggle/labcoat = 3,
/obj/item/clothing/suit/storage/toggle/labcoat/cmo,
/obj/item/clothing/suit/storage/toggle/labcoat/emt,
/obj/item/clothing/suit/storage/toggle/labcoat/cmoalt,
/obj/item/clothing/suit/storage/toggle/labcoat/genetics,
/obj/item/clothing/suit/storage/toggle/labcoat/virologist,
/obj/item/clothing/suit/storage/toggle/labcoat/chemist,
/obj/item/weapon/storage/box/masks,
/obj/item/weapon/storage/box/gloves
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Medical uniform crate"
access = access_medical_equip
/datum/supply_packs/med/medicalbiosuits
name = "Medical biohazard gear"
contains = list(
/obj/item/clothing/head/bio_hood = 3,
/obj/item/clothing/suit/bio_suit = 3,
/obj/item/clothing/head/bio_hood/virology = 2,
/obj/item/clothing/suit/bio_suit/cmo,
/obj/item/clothing/head/bio_hood/cmo,
/obj/item/clothing/mask/gas = 5,
/obj/item/weapon/tank/oxygen = 5,
/obj/item/weapon/storage/box/masks,
/obj/item/weapon/storage/box/gloves
)
cost = 50
containertype = "/obj/structure/closet/crate/secure"
containername = "Medical biohazard equipment"
access = access_medical_equip
/datum/supply_packs/med/portablefreezers
name = "Portable freezers crate"
contains = list(/obj/item/weapon/storage/box/freezer = 7)
cost = 25
containertype = "/obj/structure/closet/crate/secure"
containername = "Portable freezers"
access = access_medical_equip
/datum/supply_packs/med/virus
name = "Virus sample crate"
contains = list(/obj/item/weapon/virusdish/random = 4)
cost = 25
containertype = "/obj/structure/closet/crate/secure"
containername = "Virus sample crate"
access = access_cmo

View File

@@ -0,0 +1,97 @@
/*
* Here is where any supply packs
* that don't belong elsewhere live.
*/
/datum/supply_packs/misc
group = "Miscellaneous"
/datum/supply_packs/randomised/misc
group = "Miscellaneous"
/datum/supply_packs/randomised/misc/card_packs
num_contained = 5
contains = list(
/obj/item/weapon/pack/cardemon,
/obj/item/weapon/pack/spaceball,
/obj/item/weapon/deck/holder
)
name = "Trading Card Crate"
cost = 10
containertype = /obj/structure/closet/crate
containername = "cards crate"
/datum/supply_packs/misc/eftpos
contains = list(/obj/item/device/eftpos)
name = "EFTPOS scanner"
cost = 10
containertype = /obj/structure/closet/crate
containername = "EFTPOS crate"
/datum/supply_packs/misc/chaplaingear
name = "Chaplain equipment"
contains = list(
/obj/item/clothing/under/rank/chaplain,
/obj/item/clothing/shoes/black,
/obj/item/clothing/suit/nun,
/obj/item/clothing/head/nun_hood,
/obj/item/clothing/suit/chaplain_hoodie,
/obj/item/clothing/head/chaplain_hood,
/obj/item/clothing/suit/holidaypriest,
/obj/item/clothing/under/wedding/bride_white,
/obj/item/weapon/storage/backpack/cultpack,
/obj/item/weapon/storage/fancy/candle_box = 3
)
cost = 10
containertype = "/obj/structure/closet/crate"
containername = "Chaplain equipment crate"
/datum/supply_packs/misc/hoverpod
name = "Hoverpod Shipment"
contains = list()
cost = 80
containertype = /obj/structure/largecrate/hoverpod
containername = "Hoverpod Crate"
/datum/supply_packs/randomised/misc/webbing
name = "Webbing crate"
num_contained = 4
contains = list(
/obj/item/clothing/accessory/storage/black_vest,
/obj/item/clothing/accessory/storage/brown_vest,
/obj/item/clothing/accessory/storage/white_vest,
/obj/item/clothing/accessory/storage/black_drop_pouches,
/obj/item/clothing/accessory/storage/brown_drop_pouches,
/obj/item/clothing/accessory/storage/white_drop_pouches,
/obj/item/clothing/accessory/storage/webbing
)
cost = 15
containertype = "/obj/structure/closet/crate"
containername = "Webbing crate"
/datum/supply_packs/atmos/internals
name = "Internals crate"
contains = list(
/obj/item/clothing/mask/gas = 3,
/obj/item/weapon/tank/air = 3
)
cost = 10
containertype = /obj/structure/closet/crate/internals
containername = "Internals crate"
/datum/supply_packs/atmos/evacuation
name = "Emergency equipment"
contains = list(
/obj/item/weapon/storage/toolbox/emergency = 2,
/obj/item/clothing/suit/storage/hazardvest = 2,
/obj/item/clothing/suit/storage/vest = 2,
/obj/item/weapon/tank/emergency_oxygen/engi = 4,
/obj/item/clothing/suit/space/emergency = 4,
/obj/item/clothing/head/helmet/space/emergency = 4,
/obj/item/clothing/mask/gas = 4
)
cost = 45
containertype = /obj/structure/closet/crate/internals
containername = "Emergency crate"

View File

@@ -0,0 +1,151 @@
/*
* Here is where any supply packs
* related to weapons live.
*/
/datum/supply_packs/munitions
group = "Munitions"
/datum/supply_packs/randomised/munitions
group = "Munitions"
access = access_security
/datum/supply_packs/munitions/weapons
name = "Weapons crate"
contains = list(
/obj/item/weapon/melee/baton = 2,
/obj/item/weapon/gun/energy/gun = 2,
/obj/item/weapon/gun/energy/taser = 2,
/obj/item/weapon/gun/projectile/colt/detective = 2,
/obj/item/weapon/storage/box/flashbangs = 2
)
cost = 40
containertype = /obj/structure/closet/crate/secure/weapon
containername = "Weapons crate"
/datum/supply_packs/munitions/flareguns
name = "Flare guns crate"
contains = list(
/obj/item/weapon/gun/projectile/sec/flash,
/obj/item/ammo_magazine/c45m/flash,
/obj/item/weapon/gun/projectile/shotgun/doublebarrel/flare,
/obj/item/weapon/storage/box/flashshells
)
cost = 25
containertype = /obj/structure/closet/crate/secure/weapon
containername = "Flare gun crate"
/datum/supply_packs/munitions/eweapons
name = "Experimental weapons crate"
contains = list(
/obj/item/weapon/gun/energy/xray = 2,
/obj/item/weapon/shield/energy = 2)
cost = 125
containertype = /obj/structure/closet/crate/secure/weapon
containername = "Experimental weapons crate"
access = access_armory
/datum/supply_packs/munitions/energyweapons
name = "Energy weapons crate"
contains = list(/obj/item/weapon/gun/energy/laser = 3)
cost = 50
containertype = /obj/structure/closet/crate/secure
containername = "energy weapons crate"
access = access_armory
/datum/supply_packs/munitions/shotgun
name = "Shotgun crate"
contains = list(
/obj/item/weapon/storage/box/shotgunammo,
/obj/item/weapon/storage/box/shotgunshells,
/obj/item/weapon/gun/projectile/shotgun/pump/combat = 2
)
cost = 65
containertype = /obj/structure/closet/crate/secure
containername = "Shotgun crate"
access = access_armory
/datum/supply_packs/munitions/erifle
name = "Energy marksman crate"
contains = list(/obj/item/weapon/gun/energy/sniperrifle = 2)
cost = 90
containertype = /obj/structure/closet/crate/secure
containername = "Energy marksman crate"
access = access_armory
/datum/supply_packs/munitions/ionweapons
name = "Electromagnetic weapons crate"
contains = list(
/obj/item/weapon/gun/energy/ionrifle = 2,
/obj/item/weapon/storage/box/emps
)
cost = 50
containertype = /obj/structure/closet/crate/secure
containername = "electromagnetic weapons crate"
access = access_armory
/datum/supply_packs/randomised/munitions/automatic
name = "Automatic weapon crate"
num_contained = 2
contains = list(
/obj/item/weapon/gun/projectile/automatic/wt550,
/obj/item/weapon/gun/projectile/automatic/z8
)
cost = 90
containertype = /obj/structure/closet/crate/secure
containername = "Automatic weapon crate"
access = access_armory
/datum/supply_packs/munitions/energy_guns
name = "energy guns crate"
contains = list(/obj/item/weapon/gun/energy/gun = 2)
cost = 50
containertype = /obj/structure/closet/crate/secure
containername = "energy guns crate"
access = access_armory
/datum/supply_packs/munitions/bolt_rifles_competitive
name = "Competitive shooting crate"
contains = list(
/obj/item/device/assembly/timer,
/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice = 2,
/obj/item/ammo_magazine/clip/a762/practice = 4,
/obj/item/target = 2,
/obj/item/target/alien = 2,
/obj/item/target/syndicate = 2
)
cost = 40
containertype = /obj/structure/closet/crate/secure/weapon
containername = "Weapons crate"
/datum/supply_packs/munitions/shotgunammo
name = "Ballistic ammunition crate"
contains = list(
/obj/item/weapon/storage/box/shotgunammo = 2,
/obj/item/weapon/storage/box/shotgunshells = 2
)
cost = 60
containertype = /obj/structure/closet/crate/secure
containername = "ballistic ammunition crate"
access = access_armory
/datum/supply_packs/randomised/munitions/autoammo
name = "Automatic weapon ammunition crate"
num_contained = 6
contains = list(
/obj/item/ammo_magazine/mc9mmt,
/obj/item/ammo_magazine/mc9mmt/rubber,
/obj/item/ammo_magazine/a556
)
cost = 20
containertype = /obj/structure/closet/crate/secure
containername = "Automatic weapon ammunition crate"
access = access_armory
/datum/supply_packs/munitions/beanbagammo
name = "Beanbag shells"
contains = list(/obj/item/weapon/storage/box/beanbags = 3)
cost = 30
containertype = /obj/structure/closet/crate
containername = "Beanbag shells"
access = null

View File

@@ -0,0 +1,69 @@
/*
* Here is where any supply packs
* related to recreation live.
*/
/datum/supply_packs/recreation
group = "Recreation"
/datum/supply_packs/randomised/recreation
group = "Recreation"
access = access_security
/datum/supply_packs/recreation/foam_weapons
name = "Foam Weapon Crate"
contains = list(
/obj/item/weapon/material/sword/foam = 2,
/obj/item/weapon/material/twohanded/baseballbat/foam = 2,
/obj/item/weapon/material/twohanded/spear/foam = 2,
/obj/item/weapon/material/twohanded/fireaxe/foam = 2
)
cost = 80
containertype = /obj/structure/closet/crate
containername = "foam weapon crate"
/datum/supply_packs/recreation/lasertag
name = "Lasertag equipment"
contains = list(
/obj/item/weapon/gun/energy/lasertag/red,
/obj/item/clothing/suit/redtag,
/obj/item/weapon/gun/energy/lasertag/blue,
/obj/item/clothing/suit/bluetag
)
containertype = /obj/structure/closet
containername = "Lasertag Closet"
cost = 20
/datum/supply_packs/recreation/artscrafts
name = "Arts and Crafts supplies"
contains = list(
/obj/item/weapon/storage/fancy/crayons,
/obj/item/device/camera,
/obj/item/device/camera_film = 2,
/obj/item/weapon/storage/photo_album,
/obj/item/weapon/packageWrap,
/obj/item/weapon/reagent_containers/glass/paint/red,
/obj/item/weapon/reagent_containers/glass/paint/green,
/obj/item/weapon/reagent_containers/glass/paint/blue,
/obj/item/weapon/reagent_containers/glass/paint/yellow,
/obj/item/weapon/reagent_containers/glass/paint/purple,
/obj/item/weapon/reagent_containers/glass/paint/black,
/obj/item/weapon/reagent_containers/glass/paint/white,
/obj/item/weapon/contraband/poster,
/obj/item/weapon/wrapping_paper = 3
)
cost = 10
containertype = "/obj/structure/closet/crate"
containername = "Arts and Crafts crate"
/datum/supply_packs/recreation/painters
name = "Station Painting Supplies"
cost = 10
containername = "station painting supplies crate"
containertype = /obj/structure/closet/crate
contains = list(
/obj/item/device/pipe_painter = 2,
/obj/item/device/floor_painter = 2,
/obj/item/device/closet_painter = 2
)

View File

@@ -0,0 +1,104 @@
/*
* Here is where any supply packs
* related to robotics tasks live.
*/
/datum/supply_packs/robotics
group = "Robotics"
/datum/supply_packs/randomised/robotics
group = "Robotics"
access = access_robotics
/datum/supply_packs/eng/robotics
name = "Robotics assembly crate"
contains = list(
/obj/item/device/assembly/prox_sensor = 3,
/obj/item/weapon/storage/toolbox/electrical,
/obj/item/device/flash = 4,
/obj/item/weapon/cell/high = 2
)
cost = 10
containertype = /obj/structure/closet/crate/secure/gear
containername = "Robotics assembly"
access = access_robotics
/datum/supply_packs/robotics/robolimbs_basic
name = "Basic robolimb blueprints"
contains = list(
/obj/item/weapon/disk/limb/morpheus,
/obj/item/weapon/disk/limb/xion
)
cost = 15
containertype = /obj/structure/closet/crate/secure/gear
containername = "Robolimb blueprints (basic)"
access = access_robotics
/datum/supply_packs/robotics/robolimbs_adv
name = "All robolimb blueprints"
contains = list(
/obj/item/weapon/disk/limb/bishop,
/obj/item/weapon/disk/limb/hesphiastos,
/obj/item/weapon/disk/limb/morpheus,
/obj/item/weapon/disk/limb/veymed,
/obj/item/weapon/disk/limb/wardtakahashi,
/obj/item/weapon/disk/limb/xion,
/obj/item/weapon/disk/limb/zenghu,
)
cost = 40
containertype = /obj/structure/closet/crate/secure/gear
containername = "Robolimb blueprints (adv)"
access = access_robotics
/datum/supply_packs/robotics/mecha_ripley
name = "Circuit Crate (\"Ripley\" APLU)"
contains = list(
/obj/item/weapon/book/manual/ripley_build_and_repair,
/obj/item/weapon/circuitboard/mecha/ripley/main,
/obj/item/weapon/circuitboard/mecha/ripley/peripherals
)
cost = 30
containertype = /obj/structure/closet/crate/secure
containername = "APLU \"Ripley\" Circuit Crate"
access = access_robotics
/datum/supply_packs/robotics/mecha_odysseus
name = "Circuit Crate (\"Odysseus\")"
contains = list(
/obj/item/weapon/circuitboard/mecha/odysseus/peripherals,
/obj/item/weapon/circuitboard/mecha/odysseus/main
)
cost = 25
containertype = /obj/structure/closet/crate/secure
containername = "\"Odysseus\" Circuit Crate"
access = access_robotics
/datum/supply_packs/randomised/robotics/exosuit_mod
num_contained = 1
contains = list(
/obj/item/device/kit/paint/ripley,
/obj/item/device/kit/paint/ripley/death,
/obj/item/device/kit/paint/ripley/flames_red,
/obj/item/device/kit/paint/ripley/flames_blue
)
name = "Random APLU modkit"
cost = 200
containertype = /obj/structure/closet/crate
containername = "heavy crate"
/datum/supply_packs/randomised/robotics/exosuit_mod/durand
contains = list(
/obj/item/device/kit/paint/durand,
/obj/item/device/kit/paint/durand/seraph,
/obj/item/device/kit/paint/durand/phazon
)
name = "Random Durand exosuit modkit"
/datum/supply_packs/randomised/robotics/exosuit_mod/gygax
contains = list(
/obj/item/device/kit/paint/gygax,
/obj/item/device/kit/paint/gygax/darkgygax,
/obj/item/device/kit/paint/gygax/recitence
)
name = "Random Gygax exosuit modkit"

View File

@@ -0,0 +1,41 @@
/*
* Here is where any supply packs
* related to security tasks live
*/
/datum/supply_packs/sci
group = "Science"
/datum/supply_packs/sci/coolanttank
name = "Coolant tank crate"
contains = list(/obj/structure/reagent_dispensers/coolanttank)
cost = 16
containertype = /obj/structure/largecrate
containername = "coolant tank crate"
/datum/supply_packs/sci/phoron
name = "Phoron assembly crate"
contains = list(
/obj/item/weapon/tank/phoron = 3,
/obj/item/device/assembly/igniter = 3,
/obj/item/device/assembly/prox_sensor = 3,
/obj/item/device/assembly/timer = 3
)
cost = 10
containertype = /obj/structure/closet/crate/secure/phoron
containername = "Phoron assembly crate"
access = access_tox_storage
/datum/supply_packs/sci/exoticseeds
name = "Exotic seeds crate"
contains = list(
/obj/item/seeds/replicapod = 2,
/obj/item/seeds/libertymycelium,
/obj/item/seeds/reishimycelium,
/obj/item/seeds/random = 6,
/obj/item/seeds/kudzuseed
)
cost = 15
containertype = /obj/structure/closet/crate/hydroponics
containername = "Exotic Seeds crate"
access = access_hydroponics

View File

@@ -0,0 +1,375 @@
/*
* Here is where any supply packs
* related to security tasks live
*/
/datum/supply_packs/security
group = "Security"
access = access_security
/datum/supply_packs/randomised/security
group = "Security"
access = access_security
/datum/supply_packs/randomised/security/armor
num_contained = 5
contains = list(
/obj/item/clothing/suit/storage/vest,
/obj/item/clothing/suit/storage/vest/officer,
/obj/item/clothing/suit/storage/vest/warden,
/obj/item/clothing/suit/storage/vest/hos,
/obj/item/clothing/suit/storage/vest/pcrc,
/obj/item/clothing/suit/storage/vest/detective,
/obj/item/clothing/suit/storage/vest/heavy,
/obj/item/clothing/suit/storage/vest/heavy/officer,
/obj/item/clothing/suit/storage/vest/heavy/warden,
/obj/item/clothing/suit/storage/vest/heavy/hos,
/obj/item/clothing/suit/storage/vest/heavy/pcrc
)
name = "Armor crate"
cost = 40
containertype = /obj/structure/closet/crate/secure
containername = "Armor crate"
/datum/supply_packs/security/riot_gear
name = "Riot gear crate"
contains = list(
/obj/item/weapon/melee/baton = 3,
/obj/item/weapon/shield/riot = 3,
/obj/item/weapon/handcuffs = 3,
/obj/item/weapon/storage/box/flashbangs,
/obj/item/weapon/storage/box/beanbags,
/obj/item/weapon/storage/box/handcuffs
)
cost = 40
containertype = /obj/structure/closet/crate/secure
containername = "riot gear crate"
access = access_armory
/datum/supply_packs/security/riot_armor
name = "Riot armor set crate"
contains = list(
/obj/item/clothing/head/helmet/riot,
/obj/item/clothing/suit/armor/riot,
/obj/item/clothing/gloves/arm_guard/riot,
/obj/item/clothing/shoes/leg_guard/riot
)
cost = 30
containertype = /obj/structure/closet/crate/secure
containername = "riot armor set crate"
access = access_armory
/datum/supply_packs/security/ablative_armor
name = "Ablative armor set crate"
contains = list(
/obj/item/clothing/head/helmet/laserproof,
/obj/item/clothing/suit/armor/laserproof,
/obj/item/clothing/gloves/arm_guard/laserproof,
/obj/item/clothing/shoes/leg_guard/laserproof
)
cost = 40
containertype = /obj/structure/closet/crate/secure
containername = "ablative armor set crate"
access = access_armory
/datum/supply_packs/security/bullet_resistant_armor
name = "Bullet resistant armor set crate"
contains = list(
/obj/item/clothing/head/helmet/bulletproof,
/obj/item/clothing/suit/armor/bulletproof,
/obj/item/clothing/gloves/arm_guard/bulletproof,
/obj/item/clothing/shoes/leg_guard/bulletproof
)
cost = 35
containertype = /obj/structure/closet/crate/secure
containername = "bullet resistant armor set crate"
access = access_armory
/datum/supply_packs/security/combat_armor
name = "Combat armor set crate"
contains = list(
/obj/item/clothing/head/helmet/combat,
/obj/item/clothing/suit/armor/combat,
/obj/item/clothing/gloves/arm_guard/combat,
/obj/item/clothing/shoes/leg_guard/combat
)
cost = 40
containertype = /obj/structure/closet/crate/secure
containername = "combat armor set crate"
access = access_armory
/datum/supply_packs/security/tactical
name = "Tactical suits"
containertype = /obj/structure/closet/crate/secure
containername = "Tactical Suit Locker"
cost = 60
access = access_armory
contains = list(
/obj/item/clothing/under/tactical,
/obj/item/clothing/suit/armor/tactical,
/obj/item/clothing/head/helmet/tactical,
/obj/item/clothing/mask/balaclava/tactical,
/obj/item/clothing/glasses/sunglasses/sechud/tactical,
/obj/item/weapon/storage/belt/security/tactical,
/obj/item/clothing/shoes/jackboots,
/obj/item/clothing/gloves/black,
/obj/item/clothing/under/tactical,
/obj/item/clothing/suit/armor/tactical,
/obj/item/clothing/head/helmet/tactical,
/obj/item/clothing/mask/balaclava/tactical,
/obj/item/clothing/glasses/sunglasses/sechud/tactical,
/obj/item/weapon/storage/belt/security/tactical,
/obj/item/clothing/shoes/jackboots,
/obj/item/clothing/gloves/black
)
/datum/supply_packs/security/securitybarriers
name = "Security barrier crate"
contains = list(/obj/machinery/deployable/barrier = 4)
cost = 20
containertype = /obj/structure/closet/crate/secure/gear
containername = "Security barrier crate"
access = null
/datum/supply_packs/security/securityshieldgen
name = "Wall shield Generators"
contains = list(/obj/machinery/shieldwallgen = 4)
cost = 20
containertype = /obj/structure/closet/crate/secure
containername = "wall shield generators crate"
access = access_teleporter
/datum/supply_packs/randomised/security/holster
name = "Holster crate"
num_contained = 4
contains = list(
/obj/item/clothing/accessory/holster,
/obj/item/clothing/accessory/holster/armpit,
/obj/item/clothing/accessory/holster/waist,
/obj/item/clothing/accessory/holster/hip
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Holster crate"
/datum/supply_packs/security/extragear
name = "Security surplus equipment"
contains = list(
/obj/item/weapon/storage/belt/security = 3,
/obj/item/clothing/glasses/sunglasses/sechud = 3,
/obj/item/device/radio/headset/headset_sec/alt = 3,
/obj/item/clothing/suit/storage/hooded/wintercoat/security = 3
)
cost = 25
containertype = "/obj/structure/closet/crate/secure"
containername = "Security surplus equipment"
access = null
/datum/supply_packs/security/detectivegear
name = "Forensic investigation equipment"
contains = list(
/obj/item/weapon/storage/box/evidence = 2,
/obj/item/clothing/suit/storage/vest/detective,
/obj/item/weapon/cartridge/detective,
/obj/item/device/radio/headset/headset_sec,
/obj/item/taperoll/police,
/obj/item/clothing/glasses/sunglasses,
/obj/item/device/camera,
/obj/item/weapon/folder/red,
/obj/item/weapon/folder/blue,
/obj/item/weapon/storage/belt/detective,
/obj/item/clothing/gloves/black,
/obj/item/device/taperecorder,
/obj/item/device/mass_spectrometer,
/obj/item/device/camera_film = 2,
/obj/item/weapon/storage/photo_album,
/obj/item/device/reagent_scanner,
/obj/item/device/flashlight/maglight,
/obj/item/weapon/storage/briefcase/crimekit
)
cost = 40
containertype = "/obj/structure/closet/crate/secure"
containername = "Forensic equipment"
access = access_forensics_lockers
/datum/supply_packs/security/detectiveclothes
name = "Investigation apparel"
contains = list(
/obj/item/clothing/under/det/black = 2,
/obj/item/clothing/under/det/grey = 2,
/obj/item/clothing/head/det/grey = 2,
/obj/item/clothing/under/det = 2,
/obj/item/clothing/head/det = 2,
/obj/item/clothing/suit/storage/det_trench,
/obj/item/clothing/suit/storage/det_trench/grey,
/obj/item/clothing/suit/storage/forensics/red,
/obj/item/clothing/suit/storage/forensics/blue,
/obj/item/clothing/under/det/corporate = 2,
/obj/item/clothing/accessory/badge/holo/detective = 2,
/obj/item/clothing/gloves/black = 2
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Investigation clothing"
access = access_forensics_lockers
/datum/supply_packs/security/officergear
name = "Officer equipment"
contains = list(
/obj/item/clothing/suit/storage/vest/officer,
/obj/item/clothing/head/helmet,
/obj/item/weapon/cartridge/security,
/obj/item/clothing/accessory/badge/holo,
/obj/item/clothing/accessory/badge/holo/cord,
/obj/item/device/radio/headset/headset_sec,
/obj/item/weapon/storage/belt/security,
/obj/item/device/flash,
/obj/item/weapon/reagent_containers/spray/pepper,
/obj/item/weapon/grenade/flashbang,
/obj/item/weapon/melee/baton/loaded,
/obj/item/clothing/glasses/sunglasses/sechud,
/obj/item/taperoll/police,
/obj/item/clothing/gloves/black,
/obj/item/device/hailer,
/obj/item/device/flashlight/flare,
/obj/item/clothing/accessory/storage/black_vest,
/obj/item/clothing/head/soft/sec/corp,
/obj/item/clothing/under/rank/security/corp,
/obj/item/weapon/gun/energy/taser,
/obj/item/device/flashlight/maglight
)
cost = 30
containertype = "/obj/structure/closet/crate/secure"
containername = "Officer equipment"
access = access_brig
/datum/supply_packs/security/wardengear
name = "Warden equipment"
contains = list(
/obj/item/clothing/suit/storage/vest/warden,
/obj/item/clothing/under/rank/warden,
/obj/item/clothing/under/rank/warden/corp,
/obj/item/clothing/suit/armor/vest/warden,
/obj/item/clothing/suit/armor/vest/warden/alt,
/obj/item/clothing/head/helmet/warden,
/obj/item/weapon/cartridge/security,
/obj/item/device/radio/headset/headset_sec,
/obj/item/clothing/glasses/sunglasses/sechud,
/obj/item/taperoll/police,
/obj/item/device/hailer,
/obj/item/clothing/accessory/badge/holo/warden,
/obj/item/weapon/storage/box/flashbangs,
/obj/item/weapon/storage/belt/security,
/obj/item/weapon/reagent_containers/spray/pepper,
/obj/item/weapon/melee/baton/loaded,
/obj/item/weapon/storage/box/holobadge,
/obj/item/clothing/head/beret/sec/corporate/warden,
/obj/item/device/flashlight/maglight
)
cost = 45
containertype = "/obj/structure/closet/crate/secure"
containername = "Warden equipment"
access = access_armory
/datum/supply_packs/security/headofsecgear
name = "Head of security equipment"
contains = list(
/obj/item/clothing/head/helmet/HoS,
/obj/item/clothing/suit/storage/vest/hos,
/obj/item/clothing/under/rank/head_of_security/corp,
/obj/item/clothing/suit/armor/hos,
/obj/item/clothing/head/helmet/HoS/dermal,
/obj/item/weapon/cartridge/hos,
/obj/item/device/radio/headset/heads/hos,
/obj/item/clothing/glasses/sunglasses/sechud,
/obj/item/weapon/storage/belt/security,
/obj/item/device/flash,
/obj/item/device/hailer,
/obj/item/clothing/accessory/badge/holo/hos,
/obj/item/clothing/accessory/holster/waist,
/obj/item/weapon/melee/telebaton,
/obj/item/weapon/shield/riot/tele,
/obj/item/clothing/head/beret/sec/corporate/hos,
/obj/item/device/flashlight/maglight
)
cost = 65
containertype = "/obj/structure/closet/crate/secure"
containername = "Head of security equipment"
access = access_hos
/datum/supply_packs/security/securityclothing
name = "Security uniform crate"
contains = list(
/obj/item/weapon/storage/backpack/satchel/sec = 2,
/obj/item/weapon/storage/backpack/security = 2,
/obj/item/clothing/accessory/armband = 4,
/obj/item/clothing/under/rank/security = 4,
/obj/item/clothing/under/rank/security2 = 4,
/obj/item/clothing/under/rank/warden,
/obj/item/clothing/under/rank/head_of_security,
/obj/item/clothing/suit/armor/hos/jensen,
/obj/item/clothing/head/soft/sec = 4,
/obj/item/clothing/gloves/black = 4,
/obj/item/weapon/storage/box/holobadge
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Security uniform crate"
/datum/supply_packs/security/navybluesecurityclothing
name = "Navy blue security uniform crate"
contains = list(
/obj/item/weapon/storage/backpack/satchel/sec = 2,
/obj/item/weapon/storage/backpack/security = 2,
/obj/item/clothing/under/rank/security/navyblue = 4,
/obj/item/clothing/suit/security/navyofficer = 4,
/obj/item/clothing/under/rank/warden/navyblue,
/obj/item/clothing/suit/security/navywarden,
/obj/item/clothing/under/rank/head_of_security/navyblue,
/obj/item/clothing/suit/security/navyhos,
/obj/item/clothing/head/beret/sec/navy/officer = 4,
/obj/item/clothing/head/beret/sec/navy/warden,
/obj/item/clothing/head/beret/sec/navy/hos,
/obj/item/clothing/gloves/black = 4,
/obj/item/weapon/storage/box/holobadge
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Navy blue security uniform crate"
/datum/supply_packs/security/corporatesecurityclothing
name = "Corporate security uniform crate"
contains = list(
/obj/item/weapon/storage/backpack/satchel/sec = 2,
/obj/item/weapon/storage/backpack/security = 2,
/obj/item/clothing/under/rank/security/corp = 4,
/obj/item/clothing/head/soft/sec/corp = 4,
/obj/item/clothing/under/rank/warden/corp,
/obj/item/clothing/under/rank/head_of_security/corp,
/obj/item/clothing/head/beret/sec = 4,
/obj/item/clothing/head/beret/sec/corporate/warden,
/obj/item/clothing/head/beret/sec/corporate/hos,
/obj/item/clothing/under/det/corporate = 2,
/obj/item/clothing/gloves/black = 4,
/obj/item/weapon/storage/box/holobadge
)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Corporate security uniform crate"
/datum/supply_packs/security/biosuit
name = "Security biohazard gear"
contains = list(
/obj/item/clothing/head/bio_hood/security,
/obj/item/clothing/under/rank/security,
/obj/item/clothing/suit/bio_suit/security,
/obj/item/clothing/shoes/white,
/obj/item/clothing/mask/gas,
/obj/item/weapon/tank/oxygen,
/obj/item/clothing/gloves/latex
)
cost = 35
containertype = "/obj/structure/closet/crate/secure"
containername = "Security biohazard gear"

View File

@@ -0,0 +1,130 @@
/*
* Here is where any supply packs
* related to civilian tasks live
*/
/datum/supply_packs/supply
group = "Supplies"
/datum/supply_packs/supply/food
name = "Kitchen supply crate"
contains = list(
/obj/item/weapon/reagent_containers/food/condiment/flour = 6,
/obj/item/weapon/reagent_containers/food/drinks/milk = 3,
/obj/item/weapon/reagent_containers/food/drinks/soymilk = 2,
/obj/item/weapon/storage/fancy/egg_box = 2,
/obj/item/weapon/reagent_containers/food/snacks/tofu = 4,
/obj/item/weapon/reagent_containers/food/snacks/meat = 4
)
cost = 10
containertype = /obj/structure/closet/crate/freezer
containername = "Food crate"
/datum/supply_packs/supply/toner
name = "Toner cartridges"
contains = list(/obj/item/device/toner = 6)
cost = 10
containertype = /obj/structure/closet/crate
containername = "Toner cartridges"
/datum/supply_packs/supply/janitor
name = "Janitorial supplies"
contains = list(
/obj/item/weapon/reagent_containers/glass/bucket,
/obj/item/weapon/mop,
/obj/item/clothing/under/rank/janitor,
/obj/item/weapon/cartridge/janitor,
/obj/item/clothing/gloves/black,
/obj/item/clothing/head/soft/purple,
/obj/item/weapon/storage/belt/janitor,
/obj/item/clothing/shoes/galoshes,
/obj/item/weapon/caution = 4,
/obj/item/weapon/storage/bag/trash,
/obj/item/device/lightreplacer,
/obj/item/weapon/reagent_containers/spray/cleaner,
/obj/item/weapon/reagent_containers/glass/rag,
/obj/item/weapon/grenade/chem_grenade/cleaner = 3,
/obj/structure/mopbucket
)
cost = 10
containertype = /obj/structure/closet/crate
containername = "Janitorial supplies"
/datum/supply_packs/supply/boxes
name = "Empty boxes"
contains = list(/obj/item/weapon/storage/box = 10)
cost = 10
containertype = "/obj/structure/closet/crate"
containername = "Empty box crate"
/datum/supply_packs/supply/bureaucracy
contains = list(
/obj/item/weapon/clipboard = 2,
/obj/item/weapon/pen/red,
/obj/item/weapon/pen/blue,
/obj/item/weapon/pen/blue,
/obj/item/device/camera_film,
/obj/item/weapon/folder/blue,
/obj/item/weapon/folder/red,
/obj/item/weapon/folder/yellow,
/obj/item/weapon/hand_labeler,
/obj/item/weapon/tape_roll,
/obj/structure/filingcabinet/chestdrawer{anchored = 0},
/obj/item/weapon/paper_bin
)
name = "Office supplies"
cost = 15
containertype = /obj/structure/closet/crate
containername = "Office supplies crate"
/datum/supply_packs/supply/spare_pda
name = "Spare PDAs"
cost = 10
containertype = /obj/structure/closet/crate
containername = "Spare PDA crate"
contains = list(/obj/item/device/pda = 3)
/datum/supply_packs/supply/minergear
name = "Shaft miner equipment"
contains = list(
/obj/item/weapon/storage/backpack/industrial,
/obj/item/weapon/storage/backpack/satchel/eng,
/obj/item/clothing/suit/storage/hooded/wintercoat/miner,
/obj/item/device/radio/headset/headset_cargo,
/obj/item/clothing/under/rank/miner,
/obj/item/clothing/gloves/black,
/obj/item/clothing/shoes/black,
/obj/item/device/analyzer,
/obj/item/weapon/storage/bag/ore,
/obj/item/device/flashlight/lantern,
/obj/item/weapon/shovel,
/obj/item/weapon/pickaxe,
/obj/item/weapon/mining_scanner,
/obj/item/clothing/glasses/material,
/obj/item/clothing/glasses/meson
)
cost = 15
containertype = "/obj/structure/closet/crate/secure"
containername = "Shaft miner equipment"
access = access_mining
/datum/supply_packs/supply/mule
name = "Mulebot Crate"
contains = list()
cost = 20
containertype = /obj/structure/largecrate/animal/mulebot
containername = "Mulebot Crate"
/datum/supply_packs/supply/cargotrain
name = "Cargo Train Tug"
contains = list(/obj/vehicle/train/cargo/engine)
cost = 45
containertype = /obj/structure/largecrate
containername = "Cargo Train Tug Crate"
/datum/supply_packs/supply/cargotrailer
name = "Cargo Train Trolley"
contains = list(/obj/vehicle/train/cargo/trolley)
cost = 15
containertype = /obj/structure/largecrate
containername = "Cargo Train Trolley Crate"

View File

@@ -0,0 +1,52 @@
//SUPPLY PACKS
//NOTE: only secure crate types use the access var (and are lockable)
//NOTE: hidden packs only show up when the computer has been hacked.
//ANOTER NOTE: Contraband is obtainable through modified supplycomp circuitboards.
//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle.
//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points.
//var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Atmospherics","Medical","Reagents","Reagent Cartridges","Science","Hydroponics", "Supply", "Miscellaneous")
var/list/all_supply_groups = list("Atmospherics",
"Costumes",
"Engineering",
"Hospitality",
"Materials",
"Medical",
"Miscellaneous",
"Reagents",
"Reagent Cartridges",
"Recreation",
"Robotics",
"Science",
"Security",
"Supplies",
"Voidsuits")
/datum/supply_packs
var/name = null
var/list/contains = list()
var/manifest = ""
var/amount = null
var/cost = null
var/containertype = null
var/containername = null
var/access = null
var/hidden = 0
var/contraband = 0
var/group = "Operations"
/datum/supply_packs/New()
manifest += "<ul>"
for(var/path in contains)
if(!path || !ispath(path, /atom))
continue
var/atom/O = path
manifest += "<li>[initial(O.name)]</li>"
manifest += "</ul>"
/datum/supply_packs/randomised
var/num_contained //number of items picked to be contained in a randomised crate
/datum/supply_packs/randomised/New()
manifest += "Contains any [num_contained] of:"
..()

View File

@@ -0,0 +1,76 @@
/*
* Here is where any supply packs
* related to voidsuits live.
*/
/datum/supply_packs/voidsuits
group = "Voidsuits"
/datum/supply_packs/voidsuits/atmos
name = "Atmospheric voidsuits"
contains = list(
/obj/item/clothing/suit/space/void/atmos = 2,
/obj/item/clothing/head/helmet/space/void/atmos = 2,
/obj/item/clothing/mask/breath = 2,
/obj/item/clothing/shoes/magboots = 2,
/obj/item/weapon/tank/oxygen = 2,
)
cost = 45
containertype = "/obj/structure/closet/crate/secure"
containername = "Atmospheric voidsuit crate"
access = access_atmospherics
/datum/supply_packs/voidsuits/engineering
name = "Engineering voidsuits"
contains = list(
/obj/item/clothing/suit/space/void/engineering = 2,
/obj/item/clothing/head/helmet/space/void/engineering = 2,
/obj/item/clothing/mask/breath = 2,
/obj/item/clothing/shoes/magboots = 2,
/obj/item/weapon/tank/oxygen = 2
)
cost = 40
containertype = "/obj/structure/closet/crate/secure"
containername = "Engineering voidsuit crate"
access = access_engine_equip
/datum/supply_packs/voidsuits/medical
name = "Medical voidsuits"
contains = list(
/obj/item/clothing/suit/space/void/medical = 2,
/obj/item/clothing/head/helmet/space/void/medical = 2,
/obj/item/clothing/mask/breath = 2,
/obj/item/clothing/shoes/magboots = 2,
/obj/item/weapon/tank/oxygen = 2
)
cost = 40
containertype = "/obj/structure/closet/crate/secure"
containername = "Medical voidsuit crate"
access = access_medical_equip
/datum/supply_packs/voidsuits/security
name = "Security voidsuits"
contains = list(
/obj/item/clothing/suit/space/void/security = 2,
/obj/item/clothing/head/helmet/space/void/security = 2,
/obj/item/clothing/mask/breath = 2,
/obj/item/clothing/shoes/magboots = 2,
/obj/item/weapon/tank/oxygen = 2
)
cost = 55
containertype = "/obj/structure/closet/crate/secure"
containername = "Security voidsuit crate"
/datum/supply_packs/voidsuits/supply
name = "Mining voidsuits"
contains = list(
/obj/item/clothing/suit/space/void/mining = 2,
/obj/item/clothing/head/helmet/space/void/mining = 2,
/obj/item/clothing/mask/breath = 2,
/obj/item/weapon/tank/oxygen = 2
)
cost = 35
containertype = "/obj/structure/closet/crate/secure"
containername = "Mining voidsuit crate"
access = access_mining

View File

@@ -0,0 +1,60 @@
/datum/category_item/underwear/bottom/none
name = "None"
always_last = TRUE
/datum/category_item/underwear/bottom/briefs
name = "Briefs"
icon_state = "briefs"
has_color = TRUE
/datum/category_item/underwear/bottom/briefs/is_default(var/gender)
return gender != FEMALE
/datum/category_item/underwear/bottom/boxers_loveheart
name = "Boxers, Loveheart"
icon_state = "boxers_loveheart"
/datum/category_item/underwear/bottom/boxers
name = "Boxers"
icon_state = "boxers"
has_color = TRUE
/datum/category_item/underwear/bottom/boxers_green_and_blue
name = "Boxers, green & blue striped"
icon_state = "boxers_green_and_blue"
/datum/category_item/underwear/bottom/panties
name = "Panties"
icon_state = "panties"
has_color = TRUE
/datum/category_item/underwear/bottom/panties/is_default(var/gender)
return gender == FEMALE
/datum/category_item/underwear/bottom/lacy_thong
name = "Lacy thong"
icon_state = "lacy_thong"
/datum/category_item/underwear/bottom/lacy_thong_alt
name = "Lacy thong, alt"
icon_state = "lacy_thong_alt"
has_color = TRUE
/datum/category_item/underwear/bottom/panties_alt
name = "Panties, alt"
icon_state = "panties_alt"
has_color = TRUE
/datum/category_item/underwear/bottom/compression_shorts
name = "Compression shorts"
icon_state = "compression_shorts"
has_color = TRUE
/datum/category_item/underwear/bottom/thong
name = "Thong"
icon_state = "thong"
has_color = TRUE
/datum/category_item/underwear/bottom/fishnet_lower
name = "Fishnets"
icon_state = "fishnet_lower"

View File

@@ -0,0 +1,59 @@
/datum/category_item/underwear/socks/none
always_last = TRUE
name = "None"
/datum/category_item/underwear/socks/normal
name = "Normal"
icon_state = "socks_norm"
has_color = TRUE
/datum/category_item/underwear/socks/short
name = "Short"
icon_state = "socks_short"
has_color = TRUE
/datum/category_item/underwear/socks/thigh
name = "Thigh"
icon_state = "socks_thigh"
has_color = TRUE
/datum/category_item/underwear/socks/knee
name = "Knee"
icon_state = "socks_knee"
has_color = TRUE
/datum/category_item/underwear/socks/striped_knee
name = "Knee, striped"
icon_state = "striped_knee"
has_color = TRUE
/datum/category_item/underwear/socks/striped_thigh
name = "Thigh, striped"
icon_state = "striped_thigh"
has_color = TRUE
/datum/category_item/underwear/socks/pantyhose
name = "Pantyhose"
icon_state = "pantyhose"
/datum/category_item/underwear/socks/thin_thigh
name = "Thigh, thin"
icon_state = "thin_thigh"
has_color = TRUE
/datum/category_item/underwear/socks/thin_knee
name = "Knee, thin"
icon_state = "thin_knee"
has_color = TRUE
/datum/category_item/underwear/socks/rainbow_thigh
name = "Thigh, rainbow"
icon_state = "rainbow_thigh"
/datum/category_item/underwear/socks/rainbow_knee
name = "Knee, rainbow"
icon_state = "rainbow_knee"
/datum/category_item/underwear/socks/fishnet
name = "Fishnet"
icon_state = "fishnet"

View File

@@ -0,0 +1,55 @@
/datum/category_item/underwear/top/none
name = "None"
always_last = TRUE
/datum/category_item/underwear/top/none/is_default(var/gender)
return gender != FEMALE
/datum/category_item/underwear/top/bra
is_default = TRUE
name = "Bra"
icon_state = "bra"
has_color = TRUE
/datum/category_item/underwear/top/bra/is_default(var/gender)
return gender == FEMALE
/datum/category_item/underwear/top/sports_bra
name = "Sports bra"
icon_state = "sports_bra"
has_color = TRUE
/datum/category_item/underwear/top/sports_bra_alt
name = "Sports bra, alt"
icon_state = "sports_bra_alt"
has_color = TRUE
/datum/category_item/underwear/top/lacy_bra
name = "Lacy bra"
icon_state = "lacy_bra"
/datum/category_item/underwear/top/lacy_bra_alt
name = "Lacy bra, alt"
icon_state = "lacy_bra_alt"
has_color = TRUE
/datum/category_item/underwear/top/lacy_bra_alt_stripe
name = "Lacy bra, alt, stripe"
icon_state = "lacy_bra_alt_stripe"
/datum/category_item/underwear/top/halterneck_bra
name = "Halterneck bra"
icon_state = "halterneck_bra"
has_color = TRUE
/datum/category_item/underwear/top/fishnet_base
name = "Fishnet top"
icon_state = "fishnet_body"
/datum/category_item/underwear/top/fishnet_sleeves
name = "Fishnet with sleeves"
icon_state = "fishnet_sleeves"
/datum/category_item/underwear/top/fishnet_gloves
name = "Fishnet with gloves"
icon_state = "fishnet_gloves"

View File

@@ -0,0 +1,65 @@
/datum/category_item/underwear/undershirt/none
is_default = TRUE
name = "None"
always_last = TRUE
/datum/category_item/underwear/undershirt/shirt
name = "Shirt"
icon_state = "undershirt"
has_color = TRUE
/datum/category_item/underwear/undershirt/tank_top
name = "Tank top"
icon_state = "tanktop"
has_color = TRUE
/datum/category_item/underwear/undershirt/tank_top_alt
name = "Tank top, alt"
icon_state = "tanktop_alt"
has_color = TRUE
/datum/category_item/underwear/undershirt/tank_top_fire
name = "Tank top, fire"
icon_state = "tank_fire_s"
/datum/category_item/underwear/undershirt/shirt_heart
name = "Shirt, heart"
icon_state = "lover_s"
/datum/category_item/underwear/undershirt/shirt_nt
name = "Shirt, NT"
icon_state = "shirt_nano_s"
/datum/category_item/underwear/undershirt/shirt_love_nt
name = "Shirt, I<3NT"
icon_state = "lover_s"
/datum/category_item/underwear/undershirt/shortsleeve_shirt
name = "Shortsleeve shirt"
icon_state = "shortsleeve"
has_color = TRUE
/datum/category_item/underwear/undershirt/polo_shirt
name = "Polo shirt"
icon_state = "polo"
has_color = TRUE
/datum/category_item/underwear/undershirt/sport_shirt_green
name = "Sport shirt, green"
icon_state = "greenshirtsport_s"
/datum/category_item/underwear/undershirt/sport_shirt_red
name = "Sport shirt, red"
icon_state = "redshirtsport_s"
/datum/category_item/underwear/undershirt/sport_shirt_blue
name = "Sport shirt, blue"
icon_state = "blueshirtsport_s"
/datum/category_item/underwear/undershirt/shirt_tiedye
name = "Shirt, tiedye"
icon_state = "shirt_tiedye_s"
/datum/category_item/underwear/undershirt/shirt_blue_striped
name = "Shirt, blue stripes"
icon_state = "shirt_stripes_s"

View File

@@ -0,0 +1,66 @@
/****************************
* Category Collection Setup *
****************************/
/datum/category_collection/underwear
category_group_type = /datum/category_group/underwear
/*************
* Categories *
*************/
/datum/category_group/underwear
var/sort_order // Lower sort order is applied as icons first
datum/category_group/underwear/dd_SortValue()
return sort_order
/datum/category_group/underwear/top
name = "Underwear, top"
sort_order = 1
category_item_type = /datum/category_item/underwear/top
/datum/category_group/underwear/bottom
name = "Underwear, bottom"
sort_order = 2
category_item_type = /datum/category_item/underwear/bottom
/datum/category_group/underwear/socks
name = "Socks"
sort_order = 3
category_item_type = /datum/category_item/underwear/socks
/datum/category_group/underwear/undershirt
name = "Undershirt"
sort_order = 4 // Undershirts currently have the highest sort order because they may cover both underwear and socks.
category_item_type = /datum/category_item/underwear/undershirt
/*******************
* Category entries *
*******************/
/datum/category_item/underwear
var/always_last = FALSE // Should this entry be sorte last?
var/is_default = FALSE // Should this entry be considered the default for its type?
var/icon = 'icons/mob/human.dmi' // Which icon to get the underwear from
var/icon_state // And the particular item state
var/list/tweaks = list() // Underwear customizations.
var/has_color = FALSE
/datum/category_item/underwear/New()
if(has_color)
tweaks += gear_tweak_free_color_choice
/datum/category_item/underwear/dd_SortValue()
if(always_last)
return "~"+name
return name
/datum/category_item/underwear/proc/is_default(var/gender)
return is_default
/datum/category_item/underwear/proc/generate_image(var/list/metadata)
if(!icon_state)
return
var/image/I = image(icon = 'icons/mob/human.dmi', icon_state = icon_state)
for(var/datum/gear_tweak/gt in tweaks)
gt.tweak_item(I, metadata && metadata["[gt]"] ? metadata["[gt]"] : gt.get_default())
return I

Some files were not shown because too many files have changed in this diff Show More