Merge branch 'master' into shep-dev-aurora-cooking

This commit is contained in:
Rykka
2020-07-22 23:25:41 -04:00
368 changed files with 28028 additions and 1953 deletions

View File

@@ -4,13 +4,10 @@ language: c
env: env:
global: global:
- BASENAME="vorestation" # $BASENAME.dmb, $BASENAME.dme, etc. - BASENAME="vorestation" # $BASENAME.dmb, $BASENAME.dme, etc.
- BYOND_MAJOR="513"
- BYOND_MINOR="1520"
- MACRO_COUNT=4
cache: cache:
directories: directories:
- $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR} - $HOME/BYOND
addons: addons:
apt: apt:
@@ -37,13 +34,17 @@ jobs:
include: include:
- stage: "File Tests" #This is the odd man out, with specific installs and stuff. - stage: "File Tests" #This is the odd man out, with specific installs and stuff.
name: "Validate Files" name: "Validate Files"
install: #Need python for some of the tag matching stuff
- pip install --user PyYaml -q
- pip install --user beautifulsoup4 -q
script: ./tools/travis/validate_files.sh
addons: addons:
apt: apt:
packages: ~ # Don't need any packages for this packages:
- python3
- python3-pip
- python3-setuptools
install: #Need python for some of the tag matching stuff
- tools/travis/install_build_deps.sh
script:
- tools/travis/validate_files.sh
- tools/travis/build_tgui.sh
- stage: "Unit Tests" - stage: "Unit Tests"
env: TEST_DEFINE="UNIT_TEST" TEST_FILE="code/_unit_tests.dm" RUN="1" env: TEST_DEFINE="UNIT_TEST" TEST_FILE="code/_unit_tests.dm" RUN="1"
name: "Compile normally (unit tests)" name: "Compile normally (unit tests)"

13
_build_dependencies.sh Normal file
View File

@@ -0,0 +1,13 @@
# This file has all the information on what versions of libraries are thrown into the code
# For dreamchecker
export SPACEMANDMM_TAG=suite-1.4
# For NanoUI + TGUI
export NODE_VERSION=12
# For the scripts in tools
export PHP_VERSION=5.6
# Byond Major
export BYOND_MAJOR=513
# Byond Minor
export BYOND_MINOR=1526
# Macro Count
export MACRO_COUNT=4

View File

@@ -1,5 +1,6 @@
#define SPECIES_WHITELIST_SELECTABLE 0x20 // Can select and customize, but not join as #define SPECIES_WHITELIST_SELECTABLE 0x20 // Can select and customize, but not join as
#define LANGUAGE_DRUDAKAR "D'Rudak'Ar"
#define LANGUAGE_SLAVIC "Pan-Slavic" #define LANGUAGE_SLAVIC "Pan-Slavic"
#define LANGUAGE_BIRDSONG "Birdsong" #define LANGUAGE_BIRDSONG "Birdsong"
#define LANGUAGE_SAGARU "Sagaru" #define LANGUAGE_SAGARU "Sagaru"

View File

@@ -100,6 +100,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_TICKER 60 #define FIRE_PRIORITY_TICKER 60
#define FIRE_PRIORITY_PLANETS 75 #define FIRE_PRIORITY_PLANETS 75
#define FIRE_PRIORITY_MACHINES 100 #define FIRE_PRIORITY_MACHINES 100
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_PROJECTILES 150 #define FIRE_PRIORITY_PROJECTILES 150
#define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500 #define FIRE_PRIORITY_OVERLAYS 500

19
code/__defines/tgui.dm Normal file
View File

@@ -0,0 +1,19 @@
/// Maximum number of windows that can be suspended/reused
#define TGUI_WINDOW_SOFT_LIMIT 5
/// Maximum number of open windows
#define TGUI_WINDOW_HARD_LIMIT 9
/// Maximum ping timeout allowed to detect zombie windows
#define TGUI_PING_TIMEOUT 4 SECONDS
/// Window does not exist
#define TGUI_WINDOW_CLOSED 0
/// Window was just opened, but is still not ready to be sent data
#define TGUI_WINDOW_LOADING 1
/// Window is free and ready to receive data
#define TGUI_WINDOW_READY 2
/// Get a window id based on the provided pool index
#define TGUI_WINDOW_ID(index) "tgui-window-[index]"
/// Get a pool index of the provided window id
#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13))

View File

@@ -616,3 +616,24 @@ datum/projectile_data
if (!client_or_usr) if (!client_or_usr)
return return
winset(client_or_usr, "mainwindow", "flash=5") winset(client_or_usr, "mainwindow", "flash=5")
/**
* Get a bounding box of a list of atoms.
*
* Arguments:
* - atoms - List of atoms. Can accept output of view() and range() procs.
*
* Returns: list(x1, y1, x2, y2)
*/
/proc/get_bbox_of_atoms(list/atoms)
var/list/list_x = list()
var/list/list_y = list()
for(var/_a in atoms)
var/atom/a = _a
list_x += a.x
list_y += a.y
return list(
min(list_x),
min(list_y),
max(list_x),
max(list_y))

View File

@@ -176,6 +176,22 @@
/proc/log_unit_test(text) /proc/log_unit_test(text)
to_world_log("## UNIT_TEST: [text]") to_world_log("## UNIT_TEST: [text]")
/proc/log_tgui(user_or_client, text)
var/entry = ""
if(!user_or_client)
entry += "no user"
else if(istype(user_or_client, /mob))
var/mob/user = user_or_client
entry += "[user.ckey] (as [user])"
else if(istype(user_or_client, /client))
var/client/client = user_or_client
entry += "[client.ckey]"
entry += ":\n[text]"
WRITE_LOG(diary, entry)
/proc/log_asset(text)
WRITE_LOG(diary, "ASSET: [text]")
/proc/report_progress(var/progress_message) /proc/report_progress(var/progress_message)
admin_notice("<span class='boldannounce'>[progress_message]</span>", R_DEBUG) admin_notice("<span class='boldannounce'>[progress_message]</span>", R_DEBUG)
to_world_log(progress_message) to_world_log(progress_message)

View File

@@ -138,6 +138,19 @@
/proc/sanitize_old(var/t,var/list/repl_chars = list("\n"="#","\t"="#")) /proc/sanitize_old(var/t,var/list/repl_chars = list("\n"="#","\t"="#"))
return html_encode(replace_characters(t,repl_chars)) return html_encode(replace_characters(t,repl_chars))
//Removes a few problematic characters
/proc/sanitize_simple(t,list/repl_chars = list("\n"="#","\t"="#"))
for(var/char in repl_chars)
var/index = findtext(t, char)
while(index)
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index + length(char))
index = findtext(t, char, index + length(char))
return t
/proc/sanitize_filename(t)
return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"=""))
/* /*
* Text searches * Text searches
*/ */

View File

@@ -1571,6 +1571,14 @@ var/mob/dview/dview_mob = new
/datum/proc/stack_trace(msg) /datum/proc/stack_trace(msg)
CRASH(msg) CRASH(msg)
GLOBAL_REAL_VAR(list/stack_trace_storage)
/proc/gib_stack_trace()
stack_trace_storage = list()
stack_trace()
stack_trace_storage.Cut(1, min(3,stack_trace_storage.len))
. = stack_trace_storage
stack_trace_storage = null
// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. // \ref behaviour got changed in 512 so this is necesary to replicate old behaviour.
// If it ever becomes necesary to get a more performant REF(), this lies here in wait // If it ever becomes necesary to get a more performant REF(), this lies here in wait
// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]") // #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")

View File

@@ -123,8 +123,3 @@
/obj/screen/fullscreen/fishbed /obj/screen/fullscreen/fishbed
icon_state = "fishbed" icon_state = "fishbed"
#undef FULLSCREEN_LAYER
#undef BLIND_LAYER
#undef DAMAGE_LAYER
#undef CRIT_LAYER

View File

@@ -0,0 +1,171 @@
/client
/**
* Assoc list with all the active maps - when a screen obj is added to
* a map, it's put in here as well.
*
* Format: list(<mapname> = list(/obj/screen))
*/
var/list/screen_maps = list()
/obj/screen
/**
* Map name assigned to this object.
* Automatically set by /client/proc/register_map_obj.
*/
var/assigned_map
/**
* Mark this object as garbage-collectible after you clean the map
* it was registered on.
*
* This could probably be changed to be a proc, for conditional removal.
* But for now, this works.
*/
var/del_on_map_removal = TRUE
/**
* A screen object, which acts as a container for turfs and other things
* you want to show on the map, which you usually attach to "vis_contents".
*/
/obj/screen/map_view
icon_state = "blank"
// Map view has to be on the lowest plane to enable proper lighting
layer = SPACE_PLANE
plane = SPACE_PLANE
/**
* A generic background object.
* It is also implicitly used to allocate a rectangle on the map, which will
* be used for auto-scaling the map.
*/
/obj/screen/background
name = "background"
icon = 'icons/mob/map_backgrounds.dmi'
icon_state = "clear"
layer = SPACE_PLANE
plane = SPACE_PLANE
/**
* Sets screen_loc of this screen object, in form of point coordinates,
* with optional pixel offset (px, py).
*
* If applicable, "assigned_map" has to be assigned before this proc call.
*/
/obj/screen/proc/set_position(x, y, px = 0, py = 0)
if(assigned_map)
screen_loc = "[assigned_map]:[x]:[px],[y]:[py]"
else
screen_loc = "[x]:[px],[y]:[py]"
/**
* Sets screen_loc to fill a rectangular area of the map.
*
* If applicable, "assigned_map" has to be assigned before this proc call.
*/
/obj/screen/proc/fill_rect(x1, y1, x2, y2)
if(assigned_map)
screen_loc = "[assigned_map]:[x1],[y1] to [x2],[y2]"
else
screen_loc = "[x1],[y1] to [x2],[y2]"
/**
* Registers screen obj with the client, which makes it visible on the
* assigned map, and becomes a part of the assigned map's lifecycle.
*/
/client/proc/register_map_obj(obj/screen/screen_obj)
if(!screen_obj.assigned_map)
CRASH("Can't register [screen_obj] without 'assigned_map' property.")
if(!screen_maps[screen_obj.assigned_map])
screen_maps[screen_obj.assigned_map] = list()
// NOTE: Possibly an expensive operation
var/list/screen_map = screen_maps[screen_obj.assigned_map]
if(!screen_map.Find(screen_obj))
screen_map += screen_obj
if(!screen.Find(screen_obj))
screen += screen_obj
/**
* Clears the map of registered screen objects.
*
* Not really needed most of the time, as the client's screen list gets reset
* on relog. any of the buttons are going to get caught by garbage collection
* anyway. they're effectively qdel'd.
*/
/client/proc/clear_map(map_name)
if(!map_name || !(map_name in screen_maps))
return FALSE
for(var/obj/screen/screen_obj in screen_maps[map_name])
screen_maps[map_name] -= screen_obj
if(screen_obj.del_on_map_removal)
qdel(screen_obj)
screen_maps -= map_name
/**
* Clears all the maps of registered screen objects.
*/
/client/proc/clear_all_maps()
for(var/map_name in screen_maps)
clear_map(map_name)
/**
* Creates a popup window with a basic map element in it, without any
* further initialization.
*
* Ratio is how many pixels by how many pixels (keep it simple).
*
* Returns a map name.
*/
/client/proc/create_popup(name, ratiox = 100, ratioy = 100)
winclone(src, "popupwindow", name)
var/list/winparams = list()
winparams["size"] = "[ratiox]x[ratioy]"
winparams["on-close"] = "handle-popup-close [name]"
winset(src, "[name]", list2params(winparams))
winshow(src, "[name]", 1)
var/list/params = list()
params["parent"] = "[name]"
params["type"] = "map"
params["size"] = "[ratiox]x[ratioy]"
params["anchor1"] = "0,0"
params["anchor2"] = "[ratiox],[ratioy]"
winset(src, "[name]_map", list2params(params))
return "[name]_map"
/**
* Create the popup, and get it ready for generic use by giving
* it a background.
*
* Width and height are multiplied by 64 by default.
*/
/client/proc/setup_popup(popup_name, width = 9, height = 9, \
tilesize = 2, bg_icon)
if(!popup_name)
return
clear_map("[popup_name]_map")
var/x_value = world.icon_size * tilesize * width
var/y_value = world.icon_size * tilesize * height
var/map_name = create_popup(popup_name, x_value, y_value)
var/obj/screen/background/background = new
background.assigned_map = map_name
background.fill_rect(1, 1, width, height)
if(bg_icon)
background.icon_state = bg_icon
register_map_obj(background)
return map_name
/**
* Closes a popup.
*/
/client/proc/close_popup(popup)
winshow(src, popup, 0)
handle_popup_close(popup)
/**
* When the popup closes in any way (player or proc call) it calls this.
*/
/client/verb/handle_popup_close(window_id as text)
set hidden = TRUE
clear_map("[window_id]_map")

View File

@@ -3,17 +3,20 @@
#define SKYBOX_TURFS (SKYBOX_PIXELS/WORLD_ICON_SIZE) #define SKYBOX_TURFS (SKYBOX_PIXELS/WORLD_ICON_SIZE)
// Skybox screen object. // Skybox screen object.
/obj/skybox /obj/screen/skybox
name = "skybox" name = "skybox"
icon = null
appearance_flags = TILE_BOUND|PIXEL_SCALE
mouse_opacity = 0 mouse_opacity = 0
anchored = TRUE anchored = TRUE
simulated = FALSE simulated = FALSE
screen_loc = "CENTER,CENTER" screen_loc = "CENTER,CENTER"
layer = OBJ_LAYER
plane = SKYBOX_PLANE plane = SKYBOX_PLANE
blend_mode = BLEND_MULTIPLY // You actually need to do it this way or you see it in occlusion. blend_mode = BLEND_MULTIPLY // You actually need to do it this way or you see it in occlusion.
// Adjust transform property to scale for client's view var. We assume the skybox is 736x736 px // Adjust transform property to scale for client's view var. We assume the skybox is 736x736 px
/obj/skybox/proc/scale_to_view(var/view) /obj/screen/skybox/proc/scale_to_view(var/view)
var/matrix/M = matrix() var/matrix/M = matrix()
// Translate to center the icon over us! // Translate to center the icon over us!
M.Translate(-(SKYBOX_PIXELS - WORLD_ICON_SIZE) / 2) M.Translate(-(SKYBOX_PIXELS - WORLD_ICON_SIZE) / 2)
@@ -23,7 +26,7 @@
src.transform = M src.transform = M
/client /client
var/obj/skybox/skybox var/obj/screen/skybox/skybox
/client/proc/update_skybox(rebuild) /client/proc/update_skybox(rebuild)
if(!skybox) if(!skybox)

View File

@@ -32,7 +32,7 @@ SUBSYSTEM_DEF(ai)
while(currentrun.len) while(currentrun.len)
var/datum/ai_holder/A = currentrun[currentrun.len] var/datum/ai_holder/A = currentrun[currentrun.len]
--currentrun.len --currentrun.len
if(!A || QDELETED(A) || A.busy) // Doesn't exist or won't exist soon or not doing it this tick if(!A || QDELETED(A) || !A.holder?.loc || A.busy) // Doesn't exist or won't exist soon or not doing it this tick
continue continue
if(process_z[get_z(A.holder)]) if(process_z[get_z(A.holder)])

View File

@@ -43,7 +43,7 @@ SUBSYSTEM_DEF(mobs)
if(!M || QDELETED(M)) if(!M || QDELETED(M))
mob_list -= M mob_list -= M
continue continue
else if(M.low_priority && !(process_z[get_z(M)])) else if(M.low_priority && !(M.loc && process_z[get_z(M)]))
slept_mobs++ slept_mobs++
continue continue

View File

@@ -132,7 +132,7 @@ SUBSYSTEM_DEF(skybox)
for(var/z in zlevels) for(var/z in zlevels)
skybox_cache["[z]"] = generate_skybox(z) skybox_cache["[z]"] = generate_skybox(z)
for(var/client/C) for(var/client/C in GLOB.clients)
var/their_z = get_z(C.mob) var/their_z = get_z(C.mob)
if(!their_z) //Nullspace if(!their_z) //Nullspace
continue continue

View File

@@ -0,0 +1,343 @@
/**
* tgui subsystem
*
* Contains all tgui state and subsystem code.
**/
SUBSYSTEM_DEF(tgui)
name = "TGUI"
wait = 9
flags = SS_NO_INIT
priority = FIRE_PRIORITY_TGUI
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
/// A list of UIs scheduled to process
var/list/current_run = list()
/// A list of open UIs
var/list/open_uis = list()
/// A list of open UIs, grouped by src_object and ui_key.
var/list/open_uis_by_src = list()
/// The HTML base used for all UIs.
var/basehtml
/datum/controller/subsystem/tgui/PreInit()
basehtml = file2text('tgui/packages/tgui/public/tgui.html')
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()
/datum/controller/subsystem/tgui/stat_entry()
..("P:[open_uis.len]")
/datum/controller/subsystem/tgui/fire(resumed = 0)
if(!resumed)
src.current_run = open_uis.Copy()
// Cache for sanic speed (lists are references anyways)
var/list/current_run = src.current_run
while(current_run.len)
var/datum/tgui/ui = current_run[current_run.len]
current_run.len--
// TODO: Move user/src_object check to process()
if(ui && ui.user && ui.src_object)
ui.process()
else
open_uis.Remove(ui)
if(MC_TICK_CHECK)
return
/**
* public
*
* Requests a usable tgui window from the pool.
* Returns null if pool was exhausted.
*
* required user mob
* return datum/tgui
*/
/datum/controller/subsystem/tgui/proc/request_pooled_window(mob/user)
if(!user.client)
return null
var/list/windows = user.client.tgui_windows
var/window_id
var/datum/tgui_window/window
var/window_found = FALSE
// Find a usable window
for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
window_id = TGUI_WINDOW_ID(i)
window = windows[window_id]
// As we are looping, create missing window datums
if(!window)
window = new(user.client, window_id, pooled = TRUE)
// Skip windows with acquired locks
if(window.locked)
continue
if(window.status == TGUI_WINDOW_READY)
return window
if(window.status == TGUI_WINDOW_CLOSED)
window.status = TGUI_WINDOW_LOADING
window_found = TRUE
break
if(!window_found)
return null
return window
/**
* public
*
* Force closes all tgui windows.
*
* required user mob
*/
/datum/controller/subsystem/tgui/proc/force_close_all_windows(mob/user)
if(user.client)
user.client.tgui_windows = list()
for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
var/window_id = TGUI_WINDOW_ID(i)
user << browse(null, "window=[window_id]")
/**
* public
*
* Force closes the tgui window by window_id.
*
* required user mob
* required window_id string
*/
/datum/controller/subsystem/tgui/proc/force_close_window(mob/user, window_id)
// Close all tgui datums based on window_id.
for(var/datum/tgui/ui in user.tgui_open_uis)
if(ui.window && ui.window.id == window_id)
ui.close(can_be_suspended = FALSE)
// Unset machine just to be sure.
user.unset_machine()
// Close window directly just to be sure.
user << browse(null, "window=[window_id]")
/**
* public
*
* Get a open UI given a user, src_object, and ui_key and try to update it with data.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
*
* return datum/tgui The found UI.
**/
/datum/controller/subsystem/tgui/proc/try_update_ui(
mob/user,
datum/src_object,
datum/tgui/ui)
// Look up a UI if it wasn't passed.
if(isnull(ui))
ui = get_open_ui(user, src_object)
// Couldn't find a UI.
if(isnull(ui))
return null
ui.process_status()
// UI ended up with the closed status
// or is actively trying to close itself.
// FIXME: Doesn't actually fix the paper bug.
if(ui.status <= STATUS_CLOSE)
ui.close()
return null
ui.send_update()
return ui
/**
* private
*
* Get a open UI given a user, src_object, and ui_key.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
*
* return datum/tgui The found UI.
**/
/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object)
var/key = "[REF(src_object)]"
// No UIs opened for this src_object
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return null // No UIs open.
for(var/datum/tgui/ui in open_uis_by_src[key]) // Find UIs for this object.
// Make sure we have the right user
if(ui.user == user)
return ui
return null // Couldn't find a UI!
/**
* private
*
* Update all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs updated.
**/
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
var/count = 0
var/key = "[REF(src_object)]"
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return count // Couldn't find any UIs for this object.
for(var/datum/tgui/ui in open_uis_by_src[key])
// Check the UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user))
ui.process(force = 1) // Update the UI.
count++ // Count each UI we update.
return count
/**
* private
*
* Close all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs closed.
**/
/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
var/count = 0
var/key = "[REF(src_object)]"
// No UIs opened for this src_object
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return count
for(var/datum/tgui/ui in open_uis_by_src[key])
if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
ui.close() // Close the UI.
count++ // Count each UI we close.
return count
/**
* private
*
* Close all UIs regardless of their attachment to src_object.
*
* return int The number of UIs closed.
**/
/datum/controller/subsystem/tgui/proc/close_all_uis()
var/count = 0
for(var/key in open_uis_by_src)
for(var/datum/tgui/ui in open_uis_by_src[key])
if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
ui.close() // Close the UI.
count++ // Count each UI we close.
return count
/**
* private
*
* Update all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only update UIs belonging this src_object.
*
* return int The number of UIs updated.
**/
/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object)
var/count = 0
if(length(user?.tgui_open_uis) == 0)
return count
for(var/datum/tgui/ui in user.tgui_open_uis)
if(isnull(src_object) || ui.src_object == src_object)
ui.process(force = 1)
count++
return count
/**
* private
*
* Close all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only close UIs belonging this src_object.
*
* return int The number of UIs closed.
**/
/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object)
var/count = 0
if(length(user?.tgui_open_uis) == 0)
return count
for(var/datum/tgui/ui in user.tgui_open_uis)
if(isnull(src_object) || ui.src_object == src_object)
ui.close()
count++
return count
/**
* private
*
* Add a UI to the list of open UIs.
*
* required ui datum/tgui The UI to be added.
**/
/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
var/key = "[REF(ui.src_object)]"
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
open_uis_by_src[key] = list()
ui.user.tgui_open_uis |= ui
var/list/uis = open_uis_by_src[key]
uis |= ui
open_uis |= ui
/**
* private
*
* Remove a UI from the list of open UIs.
*
* required ui datum/tgui The UI to be removed.
*
* return bool If the UI was removed or not.
**/
/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
var/key = "[REF(ui.src_object)]"
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return FALSE
// Remove it from the list of processing UIs.
open_uis.Remove(ui)
// If the user exists, remove it from them too.
if(ui.user)
ui.user.tgui_open_uis.Remove(ui)
var/list/uis = open_uis_by_src[key]
uis.Remove(ui)
if(length(uis) == 0)
open_uis_by_src.Remove(key)
return TRUE
/**
* private
*
* Handle client logout, by closing all their UIs.
*
* required user mob The mob which logged out.
*
* return int The number of UIs closed.
**/
/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
return close_user_uis(user)
/**
* private
*
* Handle clients switching mobs, by transferring their UIs.
*
* required user source The client's original mob.
* required user target The client's new mob.
*
* return bool If the UIs were transferred.
**/
/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
// The old mob had no open UIs.
if(length(source?.tgui_open_uis) == 0)
return FALSE
if(isnull(target.tgui_open_uis) || !istype(target.tgui_open_uis, /list))
target.tgui_open_uis = list()
// Transfer all the UIs.
for(var/datum/tgui/ui in source.tgui_open_uis)
// Inform the UIs of their new owner.
ui.user = target
target.tgui_open_uis.Add(ui)
// Clear the old list.
source.tgui_open_uis.Cut()
return TRUE

View File

@@ -1,49 +0,0 @@
var/global/datum/repository/cameras/camera_repository = new()
/proc/invalidateCameraCache()
camera_repository.networks.Cut()
camera_repository.invalidated = 1
camera_repository.camera_cache_id = (++camera_repository.camera_cache_id % 999999)
/datum/repository/cameras
var/list/networks
var/invalidated = 1
var/camera_cache_id = 1
/datum/repository/cameras/New()
networks = list()
..()
/datum/repository/cameras/proc/cameras_in_network(var/network, var/list/zlevels)
setup_cache()
var/list/network_list = networks[network]
if(LAZYLEN(zlevels))
var/list/filtered_cameras = list()
for(var/list/C in network_list)
//Camera is marked as always-visible
if(C["omni"])
filtered_cameras[++filtered_cameras.len] = C
continue
//Camera might be in an adjacent zlevel
var/camz = C["z"]
if(!camz) //It's inside something (helmet, communicator, etc) or nullspace or who knows
camz = get_z(locate(C["camera"]) in cameranet.cameras)
if(camz in zlevels)
filtered_cameras[++filtered_cameras.len] = C //Can't add lists to lists with +=
return filtered_cameras
else
return network_list
/datum/repository/cameras/proc/setup_cache()
if(!invalidated)
return
invalidated = 0
cameranet.process_sort()
for(var/obj/machinery/camera/C in cameranet.cameras)
var/cam = C.nano_structure()
for(var/network in C.network)
if(!networks[network])
networks[network] = list()
var/list/netlist = networks[network]
netlist[++netlist.len] = cam

View File

@@ -51,6 +51,7 @@ var/global/datum/repository/crew/crew_repository = new()
crewmemberData["area"] = sanitize(A.get_name()) crewmemberData["area"] = sanitize(A.get_name())
crewmemberData["x"] = pos.x crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y crewmemberData["y"] = pos.y
crewmemberData["realZ"] = pos.z
crewmemberData["z"] = using_map.get_zlevel_name(pos.z) crewmemberData["z"] = using_map.get_zlevel_name(pos.z)
crewmembers[++crewmembers.len] = crewmemberData crewmembers[++crewmembers.len] = crewmemberData

View File

@@ -11,42 +11,42 @@
name = "Inflatable barriers" name = "Inflatable barriers"
contains = list(/obj/item/weapon/storage/briefcase/inflatable = 3) contains = list(/obj/item/weapon/storage/briefcase/inflatable = 3)
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/aether
containername = "Inflatable Barrier Crate" containername = "Inflatable Barrier Crate"
/datum/supply_pack/atmos/canister_empty /datum/supply_pack/atmos/canister_empty
name = "Empty gas canister" name = "Empty gas canister"
cost = 7 cost = 7
containername = "Empty gas canister crate" containername = "Empty gas canister crate"
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/aether
contains = list(/obj/machinery/portable_atmospherics/canister) contains = list(/obj/machinery/portable_atmospherics/canister)
/datum/supply_pack/atmos/canister_air /datum/supply_pack/atmos/canister_air
name = "Air canister" name = "Air canister"
cost = 10 cost = 10
containername = "Air canister crate" containername = "Air canister crate"
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/aether
contains = list(/obj/machinery/portable_atmospherics/canister/air) contains = list(/obj/machinery/portable_atmospherics/canister/air)
/datum/supply_pack/atmos/canister_oxygen /datum/supply_pack/atmos/canister_oxygen
name = "Oxygen canister" name = "Oxygen canister"
cost = 15 cost = 15
containername = "Oxygen canister crate" containername = "Oxygen canister crate"
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/aether
contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) contains = list(/obj/machinery/portable_atmospherics/canister/oxygen)
/datum/supply_pack/atmos/canister_nitrogen /datum/supply_pack/atmos/canister_nitrogen
name = "Nitrogen canister" name = "Nitrogen canister"
cost = 10 cost = 10
containername = "Nitrogen canister crate" containername = "Nitrogen canister crate"
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/aether
contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen)
/datum/supply_pack/atmos/canister_phoron /datum/supply_pack/atmos/canister_phoron
name = "Phoron gas canister" name = "Phoron gas canister"
cost = 60 cost = 60
containername = "Phoron gas canister crate" containername = "Phoron gas canister crate"
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/aether
access = access_atmospherics access = access_atmospherics
contains = list(/obj/machinery/portable_atmospherics/canister/phoron) contains = list(/obj/machinery/portable_atmospherics/canister/phoron)
@@ -54,7 +54,7 @@
name = "N2O gas canister" name = "N2O gas canister"
cost = 15 cost = 15
containername = "N2O gas canister crate" containername = "N2O gas canister crate"
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/aether
access = access_atmospherics access = access_atmospherics
contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent) contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent)
@@ -62,7 +62,7 @@
name = "Carbon dioxide gas canister" name = "Carbon dioxide gas canister"
cost = 15 cost = 15
containername = "CO2 canister crate" containername = "CO2 canister crate"
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/aether
access = access_atmospherics access = access_atmospherics
contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide)
@@ -70,7 +70,7 @@
contains = list(/obj/machinery/pipedispenser/orderable) contains = list(/obj/machinery/pipedispenser/orderable)
name = "Pipe Dispenser" name = "Pipe Dispenser"
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/aether
containername = "Pipe Dispenser Crate" containername = "Pipe Dispenser Crate"
access = access_atmospherics access = access_atmospherics
@@ -78,7 +78,7 @@
contains = list(/obj/machinery/pipedispenser/disposal/orderable) contains = list(/obj/machinery/pipedispenser/disposal/orderable)
name = "Disposals Pipe Dispenser" name = "Disposals Pipe Dispenser"
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/aether
containername = "Disposal Dispenser Crate" containername = "Disposal Dispenser Crate"
access = access_atmospherics access = access_atmospherics
@@ -89,7 +89,7 @@
/obj/item/weapon/tank/air = 3 /obj/item/weapon/tank/air = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/internals containertype = /obj/structure/closet/crate/aether
containername = "Internals crate" containername = "Internals crate"
/datum/supply_pack/atmos/evacuation /datum/supply_pack/atmos/evacuation
@@ -104,5 +104,5 @@
/obj/item/clothing/mask/gas = 4 /obj/item/clothing/mask/gas = 4
) )
cost = 35 cost = 35
containertype = /obj/structure/closet/crate/internals containertype = /obj/structure/closet/crate/aether
containername = "Emergency crate" containername = "Emergency crate"

View File

@@ -28,7 +28,7 @@
/obj/item/weapon/grenade/chem_grenade/incendiary /obj/item/weapon/grenade/chem_grenade/incendiary
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/weapon
containername = "Special Ops crate" containername = "Special Ops crate"
contraband = 1 contraband = 1
@@ -39,7 +39,7 @@
/obj/item/weapon/reagent_containers/food/snacks/unajerky = 4 /obj/item/weapon/reagent_containers/food/snacks/unajerky = 4
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/unathi
containername = "Moghes imports crate" containername = "Moghes imports crate"
contraband = 1 contraband = 1
@@ -51,7 +51,7 @@
) )
cost = 50 cost = 50
contraband = 1 contraband = 1
containertype = /obj/structure/closet/crate/secure/weapon containertype = /obj/structure/closet/crate/hedberg
containername = "Ballistic weapons crate" containername = "Ballistic weapons crate"
/datum/supply_pack/randomised/misc/telecrate //you get something awesome, a couple of decent things, and a few weak/filler things /datum/supply_pack/randomised/misc/telecrate //you get something awesome, a couple of decent things, and a few weak/filler things
@@ -103,5 +103,5 @@
) )
cost = 250 //more than a hat crate!, cost = 250 //more than a hat crate!,
contraband = 1 contraband = 1
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large
containername = "Suspicious crate" containername = "Suspicious crate"

View File

@@ -1,6 +1,6 @@
/* /*
* Here is where any supply packs * Here is where any supply packs
* related to weapons live. * related to costumes live.
*/ */
@@ -19,7 +19,7 @@
/obj/item/clothing/head/wizard/fake /obj/item/clothing/head/wizard/fake
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanothreads
containername = "Wizard costume crate" containername = "Wizard costume crate"
/datum/supply_pack/randomised/costumes/hats /datum/supply_pack/randomised/costumes/hats
@@ -48,8 +48,8 @@
) )
name = "Collectable hat crate!" name = "Collectable hat crate!"
cost = 200 cost = 200
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanothreads
containername = "Collectable hats crate! Brought to you by Bass.inc!" containername = "Collectable hats crate"
/datum/supply_pack/randomised/costumes/costume /datum/supply_pack/randomised/costumes/costume
num_contained = 3 num_contained = 3
@@ -84,7 +84,7 @@
) )
name = "Costumes crate" name = "Costumes crate"
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanothreads
containername = "Actor Costumes" containername = "Actor Costumes"
/datum/supply_pack/costumes/formal_wear /datum/supply_pack/costumes/formal_wear
@@ -104,15 +104,15 @@
/obj/item/clothing/shoes/leather, /obj/item/clothing/shoes/leather,
/obj/item/clothing/accessory/wcoat /obj/item/clothing/accessory/wcoat
) )
name = "Formalwear closet" name = "Formalwear (Suits)"
cost = 30 cost = 30
containertype = /obj/structure/closet containertype = /obj/structure/closet/crate/gilthari
containername = "Formalwear for the best occasions." containername = "Formal suit crate"
datum/supply_pack/costumes/witch datum/supply_pack/costumes/witch
name = "Witch costume" name = "Witch costume"
containername = "Witch costume" containername = "Witch costume"
containertype = /obj/structure/closet containertype = /obj/structure/closet/crate/nanothreads
cost = 20 cost = 20
contains = list( contains = list(
/obj/item/clothing/suit/wizrobe/marisa/fake, /obj/item/clothing/suit/wizrobe/marisa/fake,
@@ -124,7 +124,7 @@ datum/supply_pack/costumes/witch
/datum/supply_pack/randomised/costumes/costume_hats /datum/supply_pack/randomised/costumes/costume_hats
name = "Costume hats" name = "Costume hats"
containername = "Actor hats crate" containername = "Actor hats crate"
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanothreads
cost = 10 cost = 10
num_contained = 3 num_contained = 3
contains = list( contains = list(
@@ -147,9 +147,9 @@ datum/supply_pack/costumes/witch
) )
/datum/supply_pack/randomised/costumes/dresses /datum/supply_pack/randomised/costumes/dresses
name = "Womens formal dress locker" name = "Formalwear (Dresses)"
containername = "Pretty dress locker" containername = "Formal dress crate"
containertype = /obj/structure/closet containertype = /obj/structure/closet/crate/gilthari
cost = 15 cost = 15
num_contained = 3 num_contained = 3
contains = list( contains = list(

View File

@@ -11,30 +11,72 @@
name = "Replacement lights" name = "Replacement lights"
contains = list(/obj/item/weapon/storage/box/lights/mixed = 3) contains = list(/obj/item/weapon/storage/box/lights/mixed = 3)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/galaksi
containername = "Replacement lights" containername = "Replacement lights"
/datum/supply_pack/eng/smescoil /datum/supply_pack/eng/smescoil
name = "Superconducting Magnetic Coil" name = "Superconducting Magnetic Coil"
contains = list(/obj/item/weapon/smes_coil) contains = list(/obj/item/weapon/smes_coil)
cost = 75 cost = 75
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/focalpoint
containername = "Superconducting Magnetic Coil crate" containername = "Superconducting Magnetic Coil crate"
/datum/supply_pack/eng/smescoil/super_capacity /datum/supply_pack/eng/smescoil/super_capacity
name = "Superconducting Capacitance Coil" name = "Superconducting Capacitance Coil"
contains = list(/obj/item/weapon/smes_coil/super_capacity) contains = list(/obj/item/weapon/smes_coil/super_capacity)
cost = 90 cost = 90
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/focalpoint
containername = "Superconducting Capacitance Coil crate" containername = "Superconducting Capacitance Coil crate"
/datum/supply_pack/eng/smescoil/super_io /datum/supply_pack/eng/smescoil/super_io
name = "Superconducting Transmission Coil" name = "Superconducting Transmission Coil"
contains = list(/obj/item/weapon/smes_coil/super_io) contains = list(/obj/item/weapon/smes_coil/super_io)
cost = 90 cost = 90
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/focalpoint
containername = "Superconducting Transmission Coil crate" containername = "Superconducting Transmission Coil crate"
/datum/supply_pack/eng/shield_capacitor
name = "Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor)
cost = 20
containertype = /obj/structure/closet/crate/focalpoint
containername = "shield capacitor crate"
/datum/supply_pack/eng/shield_capacitor/advanced
name = "Advanced Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor/advanced)
cost = 30
containertype = /obj/structure/closet/crate/focalpoint
containername = "advanced shield capacitor crate"
/datum/supply_pack/eng/bubble_shield
name = "Bubble Shield Generator"
contains = list(/obj/machinery/shield_gen)
cost = 40
containertype =/obj/structure/closet/crate/focalpoint
containername = "shield bubble generator crate"
/datum/supply_pack/eng/bubble_shield/advanced
name = "Advanced Bubble Shield Generator"
contains = list(/obj/machinery/shield_gen/advanced)
cost = 60
containertype = /obj/structure/closet/crate/focalpoint
containername = "advanced bubble shield generator crate"
/datum/supply_pack/eng/hull_shield
name = "Hull Shield Generator"
contains = list(/obj/machinery/shield_gen/external)
cost = 80
containertype = /obj/structure/closet/crate/focalpoint
containername = "shield hull generator crate"
/datum/supply_pack/eng/hull_shield/advanced
name = "Advanced Hull Shield Generator"
contains = list(/obj/machinery/shield_gen/external/advanced)
cost = 120
containertype = /obj/structure/closet/crate/focalpoint
containername = "advanced hull shield generator crate"
/datum/supply_pack/eng/electrical /datum/supply_pack/eng/electrical
name = "Electrical maintenance crate" name = "Electrical maintenance crate"
contains = list( contains = list(
@@ -44,7 +86,7 @@
/obj/item/weapon/cell/high = 2 /obj/item/weapon/cell/high = 2
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/engineering/electrical containertype = /obj/structure/closet/crate/ward
containername = "Electrical maintenance crate" containername = "Electrical maintenance crate"
/datum/supply_pack/eng/e_welders /datum/supply_pack/eng/e_welders
@@ -53,7 +95,7 @@
/obj/item/weapon/weldingtool/electric = 3 /obj/item/weapon/weldingtool/electric = 3
) )
cost = 15 cost = 15
containertype = /obj/structure/closet/crate/engineering/electrical containertype = /obj/structure/closet/crate/ward
containername = "Electric welder crate" containername = "Electric welder crate"
/datum/supply_pack/eng/mechanical /datum/supply_pack/eng/mechanical
@@ -65,14 +107,14 @@
/obj/item/clothing/head/hardhat /obj/item/clothing/head/hardhat
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/xion
containername = "Mechanical maintenance crate" containername = "Mechanical maintenance crate"
/datum/supply_pack/eng/fueltank /datum/supply_pack/eng/fueltank
name = "Fuel tank crate" name = "Fuel tank crate"
contains = list(/obj/structure/reagent_dispensers/fueltank) contains = list(/obj/structure/reagent_dispensers/fueltank)
cost = 10 cost = 10
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/nanotrasen
containername = "fuel tank crate" containername = "fuel tank crate"
/datum/supply_pack/eng/solar /datum/supply_pack/eng/solar
@@ -84,35 +126,35 @@
/obj/item/weapon/paper/solar /obj/item/weapon/paper/solar
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/einstein
containername = "Solar pack crate" containername = "Solar pack crate"
/datum/supply_pack/eng/engine /datum/supply_pack/eng/engine
name = "Emitter crate" name = "Emitter crate"
contains = list(/obj/machinery/power/emitter = 2) contains = list(/obj/machinery/power/emitter = 2)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
containername = "Emitter crate" containername = "Emitter crate"
access = access_ce access = access_ce
/datum/supply_pack/eng/engine/field_gen /datum/supply_pack/eng/engine/field_gen
name = "Field Generator crate" name = "Field Generator crate"
contains = list(/obj/machinery/field_generator = 2) contains = list(/obj/machinery/field_generator = 2)
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/xion
containername = "Field Generator crate" containername = "Field Generator crate"
access = access_ce access = access_ce
/datum/supply_pack/eng/engine/sing_gen /datum/supply_pack/eng/engine/sing_gen
name = "Singularity Generator crate" name = "Singularity Generator crate"
contains = list(/obj/machinery/the_singularitygen) contains = list(/obj/machinery/the_singularitygen)
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
containername = "Singularity Generator crate" containername = "Singularity Generator crate"
access = access_ce access = access_ce
/datum/supply_pack/eng/engine/collector /datum/supply_pack/eng/engine/collector
name = "Collector crate" name = "Collector crate"
contains = list(/obj/machinery/power/rad_collector = 3) contains = list(/obj/machinery/power/rad_collector = 3)
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
containername = "Collector crate" containername = "Collector crate"
/datum/supply_pack/eng/engine/PA /datum/supply_pack/eng/engine/PA
@@ -127,23 +169,33 @@
/obj/structure/particle_accelerator/power_box, /obj/structure/particle_accelerator/power_box,
/obj/structure/particle_accelerator/end_cap /obj/structure/particle_accelerator/end_cap
) )
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
containername = "Particle Accelerator crate" containername = "Particle Accelerator crate"
access = access_ce access = access_ce
/datum/supply_pack/eng/shield_generator /datum/supply_pack/eng/shield_gen
name = "Shield Generator Construction Kit" contains = list(/obj/item/weapon/circuitboard/shield_gen)
contains = list( name = "Bubble shield generator circuitry"
/obj/item/weapon/circuitboard/shield_generator, cost = 30
/obj/item/weapon/stock_parts/capacitor, containertype = /obj/structure/closet/crate/secure/focalpoint
/obj/item/weapon/stock_parts/micro_laser, containername = "bubble shield generator circuitry crate"
/obj/item/weapon/smes_coil, access = access_ce
/obj/item/weapon/stock_parts/console_screen,
/obj/item/weapon/stock_parts/subspace/amplifier /datum/supply_pack/eng/shield_gen_ex
) contains = list(/obj/item/weapon/circuitboard/shield_gen_ex)
cost = 80 name = "Hull shield generator circuitry"
containertype = /obj/structure/closet/crate/engineering cost = 30
containername = "shield generator construction kit crate" containertype = /obj/structure/closet/crate/secure/focalpoint
containername = "hull shield generator circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_cap
contains = list(/obj/item/weapon/circuitboard/shield_cap)
name = "Bubble shield capacitor circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/focalpoint
containername = "shield capacitor circuitry crate"
access = access_ce
/datum/supply_pack/eng/smbig /datum/supply_pack/eng/smbig
name = "Supermatter Core" name = "Supermatter Core"
@@ -157,7 +209,7 @@
contains = list(/obj/machinery/power/generator) contains = list(/obj/machinery/power/generator)
name = "Mark I Thermoelectric Generator" name = "Mark I Thermoelectric Generator"
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/einstein
containername = "Mk1 TEG crate" containername = "Mk1 TEG crate"
access = access_engine access = access_engine
@@ -165,7 +217,7 @@
contains = list(/obj/machinery/atmospherics/binary/circulator) contains = list(/obj/machinery/atmospherics/binary/circulator)
name = "Binary atmospheric circulator" name = "Binary atmospheric circulator"
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure/large containertype = /obj/structure/closet/crate/secure/large/einstein
containername = "Atmospheric circulator crate" containername = "Atmospheric circulator crate"
access = access_engine access = access_engine
@@ -183,7 +235,7 @@
name = "P.A.C.M.A.N. portable generator parts" name = "P.A.C.M.A.N. portable generator parts"
cost = 25 cost = 25
containername = "P.A.C.M.A.N. Portable Generator Construction Kit" containername = "P.A.C.M.A.N. Portable Generator Construction Kit"
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/focalpoint
access = access_tech_storage access = access_tech_storage
contains = list( contains = list(
/obj/item/weapon/stock_parts/micro_laser, /obj/item/weapon/stock_parts/micro_laser,
@@ -196,7 +248,7 @@
name = "Super P.A.C.M.A.N. portable generator parts" name = "Super P.A.C.M.A.N. portable generator parts"
cost = 35 cost = 35
containername = "Super P.A.C.M.A.N. portable generator construction kit" containername = "Super P.A.C.M.A.N. portable generator construction kit"
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/focalpoint
access = access_tech_storage access = access_tech_storage
contains = list( contains = list(
/obj/item/weapon/stock_parts/micro_laser, /obj/item/weapon/stock_parts/micro_laser,
@@ -209,7 +261,7 @@
name = "R-UST Mk. 8 Tokamak fusion core crate" name = "R-UST Mk. 8 Tokamak fusion core crate"
cost = 50 cost = 50
containername = "R-UST Mk. 8 Tokamak Fusion Core crate" containername = "R-UST Mk. 8 Tokamak Fusion Core crate"
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
access = access_engine access = access_engine
contains = list( contains = list(
/obj/item/weapon/book/manual/rust_engine, /obj/item/weapon/book/manual/rust_engine,
@@ -221,7 +273,7 @@
name = "R-UST Mk. 8 fuel injector crate" name = "R-UST Mk. 8 fuel injector crate"
cost = 30 cost = 30
containername = "R-UST Mk. 8 fuel injector crate" containername = "R-UST Mk. 8 fuel injector crate"
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
access = access_engine access = access_engine
contains = list( contains = list(
/obj/machinery/fusion_fuel_injector, /obj/machinery/fusion_fuel_injector,
@@ -233,7 +285,7 @@
name = "Gyrotron crate" name = "Gyrotron crate"
cost = 15 cost = 15
containername = "Gyrotron Crate" containername = "Gyrotron Crate"
containertype = /obj/structure/closet/crate/secure/engineering containertype = /obj/structure/closet/crate/secure/einstein
access = access_engine access = access_engine
contains = list( contains = list(
/obj/machinery/power/emitter/gyrotron, /obj/machinery/power/emitter/gyrotron,
@@ -244,12 +296,12 @@
name = "Fusion Fuel Compressor circuitry crate" name = "Fusion Fuel Compressor circuitry crate"
cost = 10 cost = 10
containername = "Fusion Fuel Compressor circuitry crate" containername = "Fusion Fuel Compressor circuitry crate"
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/einstein
contains = list(/obj/item/weapon/circuitboard/fusion_fuel_compressor) contains = list(/obj/item/weapon/circuitboard/fusion_fuel_compressor)
/datum/supply_pack/eng/tritium /datum/supply_pack/eng/tritium
name = "Tritium crate" name = "Tritium crate"
cost = 75 cost = 75
containername = "Tritium crate" containername = "Tritium crate"
containertype = /obj/structure/closet/crate/engineering containertype = /obj/structure/closet/crate/einstein
contains = list(/obj/fiftyspawner/tritium) contains = list(/obj/fiftyspawner/tritium)

View File

@@ -1,3 +1,17 @@
/datum/supply_pack/eng/modern_shield
name = "Modern Shield Construction Kit"
contains = list(
/obj/item/weapon/circuitboard/shield_generator,
/obj/item/weapon/stock_parts/capacitor,
/obj/item/weapon/stock_parts/micro_laser,
/obj/item/weapon/smes_coil,
/obj/item/weapon/stock_parts/console_screen,
/obj/item/weapon/stock_parts/subspace/amplifier
)
cost = 80
containertype = /obj/structure/closet/crate/focalpoint
containername = "shield generator construction kit crate"
/datum/supply_pack/eng/thermoregulator /datum/supply_pack/eng/thermoregulator
contains = list(/obj/machinery/power/thermoregulator) contains = list(/obj/machinery/power/thermoregulator)
name = "Thermal Regulator" name = "Thermal Regulator"

View File

@@ -23,7 +23,7 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 4, /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 4,
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/gilthari
containername = "Party equipment" containername = "Party equipment"
/datum/supply_pack/hospitality/barsupplies /datum/supply_pack/hospitality/barsupplies
@@ -43,7 +43,7 @@
/obj/item/weapon/storage/box/glass_extras/sticks /obj/item/weapon/storage/box/glass_extras/sticks
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/gilthari
containername = "crate of bar supplies" containername = "crate of bar supplies"
/datum/supply_pack/hospitality/cookingoil /datum/supply_pack/hospitality/cookingoil
@@ -67,7 +67,7 @@
) )
name = "Surprise pack of five pizzas" name = "Surprise pack of five pizzas"
cost = 15 cost = 15
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/freezer/centauri
containername = "Pizza crate" containername = "Pizza crate"
/datum/supply_pack/hospitality/gifts /datum/supply_pack/hospitality/gifts
@@ -81,5 +81,5 @@
/obj/item/weapon/paper/card/flower /obj/item/weapon/paper/card/flower
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/allico
containername = "crate of gifts" containername = "crate of gifts"

View File

@@ -11,7 +11,7 @@
name = "Monkey crate" name = "Monkey crate"
contains = list (/obj/item/weapon/storage/box/monkeycubes) contains = list (/obj/item/weapon/storage/box/monkeycubes)
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/freezer/nanotrasen
containername = "Monkey crate" containername = "Monkey crate"
/datum/supply_pack/hydro/farwa /datum/supply_pack/hydro/farwa
@@ -110,7 +110,7 @@
/obj/item/seeds/sugarcaneseed /obj/item/seeds/sugarcaneseed
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/hydroponics containertype = /obj/structure/closet/crate/carp
containername = "Seeds crate" containername = "Seeds crate"
access = access_hydroponics access = access_hydroponics
@@ -124,7 +124,7 @@
/obj/item/weapon/material/twohanded/fireaxe/scythe /obj/item/weapon/material/twohanded/fireaxe/scythe
) )
cost = 45 cost = 45
containertype = /obj/structure/closet/crate/hydroponics containertype = /obj/structure/closet/crate/grayson
containername = "Weed control crate" containername = "Weed control crate"
access = access_hydroponics access = access_hydroponics
@@ -132,7 +132,7 @@
name = "Water tank crate" name = "Water tank crate"
contains = list(/obj/structure/reagent_dispensers/watertank) contains = list(/obj/structure/reagent_dispensers/watertank)
cost = 10 cost = 10
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/aether
containername = "water tank crate" containername = "water tank crate"
/datum/supply_pack/hydro/bee_keeper /datum/supply_pack/hydro/bee_keeper
@@ -144,14 +144,14 @@
/obj/item/bee_pack /obj/item/bee_pack
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/hydroponics containertype = /obj/structure/closet/crate/carp
containername = "Beekeeping crate" containername = "Beekeeping crate"
access = access_hydroponics access = access_hydroponics
/datum/supply_pack/hydro/tray /datum/supply_pack/hydro/tray
name = "Empty hydroponics trays" name = "Empty hydroponics trays"
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/hydroponics containertype = /obj/structure/closet/crate/aether
containername = "Hydroponics tray crate" containername = "Hydroponics tray crate"
contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0} = 3) contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0} = 3)
access = access_hydroponics access = access_hydroponics

View File

@@ -11,40 +11,40 @@
name = "50 metal sheets" name = "50 metal sheets"
contains = list(/obj/fiftyspawner/steel) contains = list(/obj/fiftyspawner/steel)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Metal sheets crate" containername = "Metal sheets crate"
/datum/supply_pack/materials/glass50 /datum/supply_pack/materials/glass50
name = "50 glass sheets" name = "50 glass sheets"
contains = list(/obj/fiftyspawner/glass) contains = list(/obj/fiftyspawner/glass)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Glass sheets crate" containername = "Glass sheets crate"
/datum/supply_pack/materials/wood50 /datum/supply_pack/materials/wood50
name = "50 wooden planks" name = "50 wooden planks"
contains = list(/obj/fiftyspawner/wood) contains = list(/obj/fiftyspawner/wood)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Wooden planks crate" containername = "Wooden planks crate"
/datum/supply_pack/materials/plastic50 /datum/supply_pack/materials/plastic50
name = "50 plastic sheets" name = "50 plastic sheets"
contains = list(/obj/fiftyspawner/plastic) contains = list(/obj/fiftyspawner/plastic)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Plastic sheets crate" containername = "Plastic sheets crate"
/datum/supply_pack/materials/cardboard_sheets /datum/supply_pack/materials/cardboard_sheets
contains = list(/obj/fiftyspawner/cardboard) contains = list(/obj/fiftyspawner/cardboard)
name = "50 cardboard sheets" name = "50 cardboard sheets"
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Cardboard sheets crate" containername = "Cardboard sheets crate"
/datum/supply_pack/materials/carpet /datum/supply_pack/materials/carpet
name = "Imported carpet" name = "Imported carpet"
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Imported carpet crate" containername = "Imported carpet crate"
cost = 15 cost = 15
contains = list( contains = list(
@@ -55,7 +55,7 @@
/datum/supply_pack/misc/linoleum /datum/supply_pack/misc/linoleum
name = "Linoleum" name = "Linoleum"
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
containername = "Linoleum crate" containername = "Linoleum crate"
cost = 15 cost = 15
contains = list(/obj/fiftyspawner/linoleum) contains = list(/obj/fiftyspawner/linoleum)

View File

@@ -22,28 +22,28 @@
/obj/item/weapon/storage/box/autoinjectors /obj/item/weapon/storage/box/autoinjectors
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/medical containertype = /obj/structure/closet/crate/zenghu
containername = "Medical crate" containername = "Medical crate"
/datum/supply_pack/med/bloodpack /datum/supply_pack/med/bloodpack
name = "BloodPack crate" name = "BloodPack crate"
contains = list(/obj/item/weapon/storage/box/bloodpacks = 3) contains = list(/obj/item/weapon/storage/box/bloodpacks = 3)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/medical containertype = /obj/structure/closet/crate/nanocare
containername = "BloodPack crate" containername = "BloodPack crate"
/datum/supply_pack/med/bodybag /datum/supply_pack/med/bodybag
name = "Body bag crate" name = "Body bag crate"
contains = list(/obj/item/weapon/storage/box/bodybags = 3) contains = list(/obj/item/weapon/storage/box/bodybags = 3)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/medical containertype = /obj/structure/closet/crate/nanocare
containername = "Body bag crate" containername = "Body bag crate"
/datum/supply_pack/med/cryobag /datum/supply_pack/med/cryobag
name = "Stasis bag crate" name = "Stasis bag crate"
contains = list(/obj/item/bodybag/cryobag = 3) contains = list(/obj/item/bodybag/cryobag = 3)
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/medical containertype = /obj/structure/closet/crate/nanocare
containername = "Stasis bag crate" containername = "Stasis bag crate"
/datum/supply_pack/med/surgery /datum/supply_pack/med/surgery
@@ -62,7 +62,7 @@
/obj/item/weapon/surgical/circular_saw /obj/item/weapon/surgical/circular_saw
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/veymed
containername = "Surgery crate" containername = "Surgery crate"
access = access_medical access = access_medical
@@ -73,7 +73,7 @@
/obj/item/weapon/storage/box/cdeathalarm_kit /obj/item/weapon/storage/box/cdeathalarm_kit
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/ward
containername = "Death Alarm crate" containername = "Death Alarm crate"
access = access_medical access = access_medical
@@ -83,7 +83,7 @@
/obj/item/weapon/storage/firstaid/clotting /obj/item/weapon/storage/firstaid/clotting
) )
cost = 100 cost = 100
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/zenghu
containername = "Clotting Medicine crate" containername = "Clotting Medicine crate"
access = access_medical access = access_medical
@@ -97,7 +97,7 @@
/obj/item/weapon/storage/belt/medical = 3 /obj/item/weapon/storage/belt/medical = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/veymed
containername = "Sterile equipment crate" containername = "Sterile equipment crate"
/datum/supply_pack/med/extragear /datum/supply_pack/med/extragear
@@ -109,7 +109,7 @@
/obj/item/clothing/suit/storage/hooded/wintercoat/medical = 3 /obj/item/clothing/suit/storage/hooded/wintercoat/medical = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Medical surplus equipment" containername = "Medical surplus equipment"
access = access_medical access = access_medical
@@ -133,7 +133,7 @@
/obj/item/weapon/reagent_containers/syringe /obj/item/weapon/reagent_containers/syringe
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Chief medical officer equipment" containername = "Chief medical officer equipment"
access = access_cmo access = access_cmo
@@ -156,7 +156,7 @@
/obj/item/weapon/reagent_containers/syringe /obj/item/weapon/reagent_containers/syringe
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Medical Doctor equipment" containername = "Medical Doctor equipment"
access = access_medical_equip access = access_medical_equip
@@ -179,7 +179,7 @@
/obj/item/weapon/reagent_containers/syringe /obj/item/weapon/reagent_containers/syringe
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Chemist equipment" containername = "Chemist equipment"
access = access_chemistry access = access_chemistry
@@ -207,7 +207,7 @@
/obj/item/clothing/accessory/storage/white_vest /obj/item/clothing/accessory/storage/white_vest
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Paramedic equipment" containername = "Paramedic equipment"
access = access_medical_equip access = access_medical_equip
@@ -226,7 +226,7 @@
/obj/item/weapon/cartridge/medical /obj/item/weapon/cartridge/medical
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Psychiatrist equipment" containername = "Psychiatrist equipment"
access = access_psychiatrist access = access_psychiatrist
@@ -247,7 +247,7 @@
/obj/item/weapon/storage/box/gloves /obj/item/weapon/storage/box/gloves
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Medical scrubs crate" containername = "Medical scrubs crate"
access = access_medical_equip access = access_medical_equip
@@ -264,7 +264,7 @@
/obj/item/weapon/pen /obj/item/weapon/pen
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/veymed
containername = "Autopsy equipment crate" containername = "Autopsy equipment crate"
access = access_morgue access = access_morgue
@@ -291,7 +291,7 @@
/obj/item/weapon/storage/box/gloves /obj/item/weapon/storage/box/gloves
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Medical uniform crate" containername = "Medical uniform crate"
access = access_medical_equip access = access_medical_equip
@@ -309,7 +309,7 @@
/obj/item/weapon/storage/box/gloves /obj/item/weapon/storage/box/gloves
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Medical biohazard equipment" containername = "Medical biohazard equipment"
access = access_medical_equip access = access_medical_equip
@@ -317,7 +317,7 @@
name = "Portable freezers crate" name = "Portable freezers crate"
contains = list(/obj/item/weapon/storage/box/freezer = 7) contains = list(/obj/item/weapon/storage/box/freezer = 7)
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/veymed
containername = "Portable freezers" containername = "Portable freezers"
access = access_medical_equip access = access_medical_equip
@@ -325,7 +325,7 @@
name = "Virus sample crate" name = "Virus sample crate"
contains = list(/obj/item/weapon/virusdish/random = 4) contains = list(/obj/item/weapon/virusdish/random = 4)
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/zenghu
containername = "Virus sample crate" containername = "Virus sample crate"
access = access_cmo access = access_cmo
@@ -333,40 +333,40 @@
name = "Defibrillator crate" name = "Defibrillator crate"
contains = list(/obj/item/device/defib_kit = 2) contains = list(/obj/item/device/defib_kit = 2)
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/medical containertype = /obj/structure/closet/crate/veymed
containername = "Defibrillator crate" containername = "Defibrillator crate"
/datum/supply_pack/med/distillery /datum/supply_pack/med/distillery
name = "Chemical distiller crate" name = "Chemical distiller crate"
contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery = 1) contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery = 1)
cost = 50 cost = 50
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/nanotrasen
containername = "Chemical distiller crate" containername = "Chemical distiller crate"
/datum/supply_pack/med/advdistillery /datum/supply_pack/med/advdistillery
name = "Industrial Chemical distiller crate" name = "Industrial Chemical distiller crate"
contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery/industrial = 1) contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery/industrial = 1)
cost = 150 cost = 150
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/xion
containername = "Industrial Chemical distiller crate" containername = "Industrial Chemical distiller crate"
/datum/supply_pack/med/oxypump /datum/supply_pack/med/oxypump
name = "Oxygen pump crate" name = "Oxygen pump crate"
contains = list(/obj/machinery/oxygen_pump/mobile = 1) contains = list(/obj/machinery/oxygen_pump/mobile = 1)
cost = 125 cost = 125
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/xion
containername = "Oxygen pump crate" containername = "Oxygen pump crate"
/datum/supply_pack/med/anestheticpump /datum/supply_pack/med/anestheticpump
name = "Anesthetic pump crate" name = "Anesthetic pump crate"
contains = list(/obj/machinery/oxygen_pump/mobile/anesthetic = 1) contains = list(/obj/machinery/oxygen_pump/mobile/anesthetic = 1)
cost = 130 cost = 130
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/nanotrasen
containername = "Anesthetic pump crate" containername = "Anesthetic pump crate"
/datum/supply_pack/med/stablepump /datum/supply_pack/med/stablepump
name = "Portable stabilizer crate" name = "Portable stabilizer crate"
contains = list(/obj/machinery/oxygen_pump/mobile/stabilizer = 1) contains = list(/obj/machinery/oxygen_pump/mobile/stabilizer = 1)
cost = 175 cost = 175
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/nanotrasen
containername = "Portable stabilizer crate" containername = "Portable stabilizer crate"

View File

@@ -20,7 +20,7 @@
) )
name = "Trading Card Crate" name = "Trading Card Crate"
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/oculum
containername = "cards crate" containername = "cards crate"
/datum/supply_pack/randomised/misc/dnd /datum/supply_pack/randomised/misc/dnd
@@ -36,7 +36,7 @@
) )
name = "Miniatures Crate" name = "Miniatures Crate"
cost = 200 cost = 200
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/oculum
containername = "Miniature Crate" containername = "Miniature Crate"
/datum/supply_pack/randomised/misc/plushies /datum/supply_pack/randomised/misc/plushies
@@ -88,14 +88,14 @@
//VOREStation Add End //VOREStation Add End
name = "Plushies Crate" name = "Plushies Crate"
cost = 15 cost = 15
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/allico
containername = "Plushies Crate" containername = "Plushies Crate"
/datum/supply_pack/misc/eftpos /datum/supply_pack/misc/eftpos
contains = list(/obj/item/device/eftpos) contains = list(/obj/item/device/eftpos)
name = "EFTPOS scanner" name = "EFTPOS scanner"
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanotrasen
containername = "EFTPOS crate" containername = "EFTPOS crate"
/datum/supply_pack/misc/chaplaingear /datum/supply_pack/misc/chaplaingear
@@ -113,7 +113,7 @@
/obj/item/weapon/storage/fancy/candle_box = 3 /obj/item/weapon/storage/fancy/candle_box = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/gilthari
containername = "Chaplain equipment crate" containername = "Chaplain equipment crate"
/datum/supply_pack/misc/hoverpod /datum/supply_pack/misc/hoverpod
@@ -136,14 +136,14 @@
/obj/item/clothing/accessory/storage/webbing /obj/item/clothing/accessory/storage/webbing
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanothreads
containername = "Webbing crate" containername = "Webbing crate"
/datum/supply_pack/misc/holoplant /datum/supply_pack/misc/holoplant
name = "Holoplant Pot" name = "Holoplant Pot"
contains = list(/obj/machinery/holoplant/shipped) contains = list(/obj/machinery/holoplant/shipped)
cost = 15 cost = 15
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/thinktronic
containername = "Holoplant crate" containername = "Holoplant crate"
/datum/supply_pack/misc/glucose_hypos /datum/supply_pack/misc/glucose_hypos
@@ -152,7 +152,7 @@
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/glucose = 5 /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/glucose = 5
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/zenghu
containername = "Glucose Hypo Crate" containername = "Glucose Hypo Crate"
/datum/supply_pack/misc/mre_rations /datum/supply_pack/misc/mre_rations
@@ -169,7 +169,7 @@
/obj/item/weapon/storage/mre/menu9, /obj/item/weapon/storage/mre/menu9,
/obj/item/weapon/storage/mre/menu10) /obj/item/weapon/storage/mre/menu10)
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/centauri
containername = "ready to eat rations" containername = "ready to eat rations"
/datum/supply_pack/misc/paste_rations /datum/supply_pack/misc/paste_rations
@@ -178,7 +178,7 @@
/obj/item/weapon/storage/mre/menu11 = 2 /obj/item/weapon/storage/mre/menu11 = 2
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/freezer/centauri
containername = "emergency rations" containername = "emergency rations"
/datum/supply_pack/misc/medical_rations /datum/supply_pack/misc/medical_rations
@@ -187,5 +187,5 @@
/obj/item/weapon/storage/mre/menu13 = 2 /obj/item/weapon/storage/mre/menu13 = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/zenghu
containername = "emergency rations" containername = "emergency rations"

View File

@@ -20,7 +20,7 @@
/obj/item/weapon/material/twohanded/fireaxe/foam = 2 /obj/item/weapon/material/twohanded/fireaxe/foam = 2
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/allico
containername = "foam weapon crate" containername = "foam weapon crate"
/datum/supply_pack/recreation/lasertag /datum/supply_pack/recreation/lasertag
@@ -31,8 +31,8 @@
/obj/item/weapon/gun/energy/lasertag/blue, /obj/item/weapon/gun/energy/lasertag/blue,
/obj/item/clothing/suit/bluetag /obj/item/clothing/suit/bluetag
) )
containertype = /obj/structure/closet containertype = /obj/structure/closet/crate/ward
containername = "Lasertag Closet" containername = "Lasertag Supplies"
cost = 10 cost = 10
/datum/supply_pack/recreation/artscrafts /datum/supply_pack/recreation/artscrafts
@@ -55,14 +55,14 @@
/obj/item/weapon/wrapping_paper = 3 /obj/item/weapon/wrapping_paper = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/allico
containername = "Arts and Crafts crate" containername = "Arts and Crafts crate"
/datum/supply_pack/recreation/painters /datum/supply_pack/recreation/painters
name = "Station Painting Supplies" name = "Station Painting Supplies"
cost = 10 cost = 10
containername = "station painting supplies crate" containername = "station painting supplies crate"
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/grayson
contains = list( contains = list(
/obj/item/device/pipe_painter = 2, /obj/item/device/pipe_painter = 2,
/obj/item/device/floor_painter = 2, /obj/item/device/floor_painter = 2,
@@ -82,7 +82,7 @@
name = "Deluxe Fishing Bait" name = "Deluxe Fishing Bait"
cost = 40 cost = 40
containername = "deluxe bait crate" containername = "deluxe bait crate"
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/carp
num_contained = 8 num_contained = 8
contains = list( contains = list(
/obj/item/weapon/storage/box/wormcan, /obj/item/weapon/storage/box/wormcan,
@@ -93,7 +93,7 @@
name = "Laser Tag Turrets" name = "Laser Tag Turrets"
cost = 40 cost = 40
containername = "laser tag turret crate" containername = "laser tag turret crate"
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/ward
contains = list( contains = list(
/obj/machinery/porta_turret/lasertag/blue, /obj/machinery/porta_turret/lasertag/blue,
/obj/machinery/porta_turret/lasertag/red /obj/machinery/porta_turret/lasertag/red

View File

@@ -20,7 +20,7 @@
/obj/item/weapon/cell/high = 2 /obj/item/weapon/cell/high = 2
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Robotics assembly" containername = "Robotics assembly"
access = access_robotics access = access_robotics
@@ -56,7 +56,7 @@
name = "Morpheus robolimb blueprints" name = "Morpheus robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/morpheus) contains = list(/obj/item/weapon/disk/limb/morpheus)
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/morpheus
containername = "Robolimb blueprints (Morpheus)" containername = "Robolimb blueprints (Morpheus)"
access = access_robotics access = access_robotics
@@ -64,7 +64,7 @@
name = "Cyber Solutions robolimb blueprints" name = "Cyber Solutions robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/cybersolutions) contains = list(/obj/item/weapon/disk/limb/cybersolutions)
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/cybersolutions
containername = "Robolimb blueprints (Cyber Solutions)" containername = "Robolimb blueprints (Cyber Solutions)"
access = access_robotics access = access_robotics
@@ -72,7 +72,7 @@
name = "Xion robolimb blueprints" name = "Xion robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/xion) contains = list(/obj/item/weapon/disk/limb/xion)
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/xion
containername = "Robolimb blueprints (Xion)" containername = "Robolimb blueprints (Xion)"
access = access_robotics access = access_robotics
@@ -80,7 +80,7 @@
name = "Grayson robolimb blueprints" name = "Grayson robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/grayson) contains = list(/obj/item/weapon/disk/limb/grayson)
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/grayson
containername = "Robolimb blueprints (Grayson)" containername = "Robolimb blueprints (Grayson)"
access = access_robotics access = access_robotics
@@ -88,7 +88,7 @@
name = "Hephaestus robolimb blueprints" name = "Hephaestus robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/hephaestus) contains = list(/obj/item/weapon/disk/limb/hephaestus)
cost = 35 cost = 35
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/heph
containername = "Robolimb blueprints (Hephaestus)" containername = "Robolimb blueprints (Hephaestus)"
access = access_robotics access = access_robotics
@@ -96,7 +96,7 @@
name = "Ward-Takahashi robolimb blueprints" name = "Ward-Takahashi robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/wardtakahashi) contains = list(/obj/item/weapon/disk/limb/wardtakahashi)
cost = 35 cost = 35
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/ward
containername = "Robolimb blueprints (Ward-Takahashi)" containername = "Robolimb blueprints (Ward-Takahashi)"
access = access_robotics access = access_robotics
@@ -104,7 +104,7 @@
name = "Zeng Hu robolimb blueprints" name = "Zeng Hu robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/zenghu) contains = list(/obj/item/weapon/disk/limb/zenghu)
cost = 35 cost = 35
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/zenghu
containername = "Robolimb blueprints (Zeng Hu)" containername = "Robolimb blueprints (Zeng Hu)"
access = access_robotics access = access_robotics
@@ -112,7 +112,7 @@
name = "Bishop robolimb blueprints" name = "Bishop robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/bishop) contains = list(/obj/item/weapon/disk/limb/bishop)
cost = 70 cost = 70
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/bishop
containername = "Robolimb blueprints (Bishop)" containername = "Robolimb blueprints (Bishop)"
access = access_robotics access = access_robotics
@@ -133,7 +133,7 @@
/obj/item/weapon/circuitboard/mecha/ripley/peripherals /obj/item/weapon/circuitboard/mecha/ripley/peripherals
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/xion
containername = "APLU \"Ripley\" Circuit Crate" containername = "APLU \"Ripley\" Circuit Crate"
access = access_robotics access = access_robotics
@@ -144,7 +144,7 @@
/obj/item/weapon/circuitboard/mecha/odysseus/main /obj/item/weapon/circuitboard/mecha/odysseus/main
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/veymed
containername = "\"Odysseus\" Circuit Crate" containername = "\"Odysseus\" Circuit Crate"
access = access_robotics access = access_robotics
@@ -158,7 +158,7 @@
) )
name = "Random APLU modkit" name = "Random APLU modkit"
cost = 200 cost = 200
containertype = /obj/structure/closet/crate/science containertype = /obj/structure/closet/crate/xion
containername = "heavy crate" containername = "heavy crate"
/datum/supply_pack/randomised/robotics/exosuit_mod/durand /datum/supply_pack/randomised/robotics/exosuit_mod/durand
@@ -168,6 +168,7 @@
/obj/item/device/kit/paint/durand/phazon /obj/item/device/kit/paint/durand/phazon
) )
name = "Random Durand exosuit modkit" name = "Random Durand exosuit modkit"
containertype = /obj/structure/closet/crate/heph
/datum/supply_pack/randomised/robotics/exosuit_mod/gygax /datum/supply_pack/randomised/robotics/exosuit_mod/gygax
contains = list( contains = list(
@@ -176,6 +177,7 @@
/obj/item/device/kit/paint/gygax/recitence /obj/item/device/kit/paint/gygax/recitence
) )
name = "Random Gygax exosuit modkit" name = "Random Gygax exosuit modkit"
containertype = /obj/structure/closet/crate/heph
/datum/supply_pack/robotics/jumper_cables /datum/supply_pack/robotics/jumper_cables
name = "Jumper kit crate" name = "Jumper kit crate"
@@ -183,7 +185,7 @@
/obj/item/device/defib_kit/jumper_kit = 2 /obj/item/device/defib_kit/jumper_kit = 2
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/einstein
containername = "Jumper kit crate" containername = "Jumper kit crate"
access = access_robotics access = access_robotics

View File

@@ -9,7 +9,7 @@
name = "Coolant tank crate" name = "Coolant tank crate"
contains = list(/obj/structure/reagent_dispensers/coolanttank) contains = list(/obj/structure/reagent_dispensers/coolanttank)
cost = 15 cost = 15
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/aether
containername = "coolant tank crate" containername = "coolant tank crate"
/datum/supply_pack/sci/phoron /datum/supply_pack/sci/phoron
@@ -39,7 +39,7 @@
/obj/item/seeds/kudzuseed /obj/item/seeds/kudzuseed
) )
cost = 15 cost = 15
containertype = /obj/structure/closet/crate/hydroponics containertype = /obj/structure/closet/crate/carp
containername = "Exotic Seeds crate" containername = "Exotic Seeds crate"
access = access_hydroponics access = access_hydroponics
@@ -47,14 +47,14 @@
name = "Integrated circuit printer" name = "Integrated circuit printer"
contains = list(/obj/item/device/integrated_circuit_printer = 2) contains = list(/obj/item/device/integrated_circuit_printer = 2)
cost = 15 cost = 15
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/ward
containername = "Integrated circuit crate" containername = "Integrated circuit crate"
/datum/supply_pack/sci/integrated_circuit_printer_upgrade /datum/supply_pack/sci/integrated_circuit_printer_upgrade
name = "Integrated circuit printer upgrade - advanced designs" name = "Integrated circuit printer upgrade - advanced designs"
contains = list(/obj/item/weapon/disk/integrated_circuit/upgrade/advanced) contains = list(/obj/item/weapon/disk/integrated_circuit/upgrade/advanced)
cost = 30 cost = 30
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/ward
containername = "Integrated circuit crate" containername = "Integrated circuit crate"
/datum/supply_pack/sci/xenoarch /datum/supply_pack/sci/xenoarch
@@ -75,6 +75,6 @@
/obj/item/weapon/storage/bag/fossils, /obj/item/weapon/storage/bag/fossils,
/obj/item/weapon/hand_labeler) /obj/item/weapon/hand_labeler)
cost = 100 cost = 100
containertype = /obj/structure/closet/crate/secure/science containertype = /obj/structure/closet/crate/secure/xion
containername = "Xenoarchaeology Tech crate" containername = "Xenoarchaeology Tech crate"
access = access_research access = access_research

View File

@@ -53,11 +53,11 @@
/obj/item/clothing/accessory/storage/pouches/blue, /obj/item/clothing/accessory/storage/pouches/blue,
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Plate Carrier crate" containername = "Plate Carrier crate"
/datum/supply_pack/security/carriersgreen /datum/supply_pack/security/carriersgreen
name = "Armor - Blue modular armor" name = "Armor - Green modular armor"
contains = list( contains = list(
/obj/item/clothing/suit/armor/pcarrier/green, /obj/item/clothing/suit/armor/pcarrier/green,
/obj/item/clothing/accessory/armor/armguards/green, /obj/item/clothing/accessory/armor/armguards/green,
@@ -65,7 +65,7 @@
/obj/item/clothing/accessory/storage/pouches/green, /obj/item/clothing/accessory/storage/pouches/green,
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Plate Carrier crate" containername = "Plate Carrier crate"
/datum/supply_pack/security/carriersnavy /datum/supply_pack/security/carriersnavy
@@ -77,7 +77,7 @@
/obj/item/clothing/accessory/storage/pouches/navy, /obj/item/clothing/accessory/storage/pouches/navy,
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Plate Carrier crate" containername = "Plate Carrier crate"
/datum/supply_pack/security/carrierstan /datum/supply_pack/security/carrierstan
@@ -89,7 +89,7 @@
/obj/item/clothing/accessory/storage/pouches/tan, /obj/item/clothing/accessory/storage/pouches/tan,
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Plate Carrier crate" containername = "Plate Carrier crate"
/datum/supply_pack/security/armorplate /datum/supply_pack/security/armorplate
@@ -98,7 +98,7 @@
/obj/item/clothing/accessory/armor/armorplate, /obj/item/clothing/accessory/armor/armorplate,
) )
cost = 5 cost = 5
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/security/armorplatestab /datum/supply_pack/security/armorplatestab
@@ -107,7 +107,7 @@
/obj/item/clothing/accessory/armor/armorplate/stab, /obj/item/clothing/accessory/armor/armorplate/stab,
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/security/armorplatemedium /datum/supply_pack/security/armorplatemedium
@@ -116,7 +116,7 @@
/obj/item/clothing/accessory/armor/armorplate/medium, /obj/item/clothing/accessory/armor/armorplate/medium,
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/security/armorplatetac /datum/supply_pack/security/armorplatetac
@@ -125,7 +125,7 @@
/obj/item/clothing/accessory/armor/armorplate/tactical, /obj/item/clothing/accessory/armor/armorplate/tactical,
) )
cost = 15 cost = 15
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/randomised/security/carriers /datum/supply_pack/randomised/security/carriers
@@ -140,7 +140,7 @@
/obj/item/clothing/suit/armor/pcarrier/press /obj/item/clothing/suit/armor/pcarrier/press
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Plate Carrier crate" containername = "Plate Carrier crate"
/datum/supply_pack/security/carriertags /datum/supply_pack/security/carriertags
@@ -158,7 +158,7 @@
/obj/item/clothing/accessory/armor/tag/abneg /obj/item/clothing/accessory/armor/tag/abneg
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Plate Carrier crate" containername = "Plate Carrier crate"
/datum/supply_pack/security/helmcovers /datum/supply_pack/security/helmcovers
@@ -174,7 +174,7 @@
/obj/item/clothing/accessory/armor/helmcover/tan /obj/item/clothing/accessory/armor/helmcover/tan
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Helmet Covers crate" containername = "Helmet Covers crate"
/datum/supply_pack/randomised/security/armorplates /datum/supply_pack/randomised/security/armorplates
@@ -193,7 +193,7 @@
/obj/item/clothing/accessory/armor/armorplate/bulletproof /obj/item/clothing/accessory/armor/armorplate/bulletproof
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/randomised/security/carrierarms /datum/supply_pack/randomised/security/carrierarms
@@ -210,7 +210,7 @@
/obj/item/clothing/accessory/armor/armguards/bulletproof /obj/item/clothing/accessory/armor/armguards/bulletproof
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/randomised/security/carrierlegs /datum/supply_pack/randomised/security/carrierlegs
@@ -227,7 +227,7 @@
/obj/item/clothing/accessory/armor/legguards/bulletproof /obj/item/clothing/accessory/armor/legguards/bulletproof
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/randomised/security/carrierbags /datum/supply_pack/randomised/security/carrierbags
@@ -246,7 +246,7 @@
/obj/item/clothing/accessory/storage/pouches/large/tan /obj/item/clothing/accessory/storage/pouches/large/tan
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/scg
containername = "Armor plate crate" containername = "Armor plate crate"
/datum/supply_pack/security/riot_gear /datum/supply_pack/security/riot_gear
@@ -260,7 +260,7 @@
/obj/item/weapon/storage/box/handcuffs /obj/item/weapon/storage/box/handcuffs
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Riot gear crate" containername = "Riot gear crate"
access = access_armory access = access_armory
@@ -273,7 +273,7 @@
/obj/item/clothing/shoes/leg_guard/riot /obj/item/clothing/shoes/leg_guard/riot
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Riot armor crate" containername = "Riot armor crate"
access = access_armory access = access_armory
@@ -287,7 +287,7 @@
/obj/item/clothing/accessory/armor/legguards/riot /obj/item/clothing/accessory/armor/legguards/riot
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Riot armor crate" containername = "Riot armor crate"
access = access_armory access = access_armory
@@ -300,7 +300,7 @@
/obj/item/clothing/shoes/leg_guard/laserproof /obj/item/clothing/shoes/leg_guard/laserproof
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Ablative armor crate" containername = "Ablative armor crate"
access = access_armory access = access_armory
@@ -314,7 +314,7 @@
/obj/item/clothing/accessory/armor/legguards/laserproof /obj/item/clothing/accessory/armor/legguards/laserproof
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/lawson
containername = "Ablative armor crate" containername = "Ablative armor crate"
access = access_armory access = access_armory
@@ -327,7 +327,7 @@
/obj/item/clothing/shoes/leg_guard/bulletproof /obj/item/clothing/shoes/leg_guard/bulletproof
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Ballistic armor crate" containername = "Ballistic armor crate"
access = access_armory access = access_armory
/* VOREStation Removal - Howabout no ERT armor being orderable? /* VOREStation Removal - Howabout no ERT armor being orderable?
@@ -342,7 +342,7 @@
/obj/item/clothing/accessory/armor/legguards/bulletproof /obj/item/clothing/accessory/armor/legguards/bulletproof
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/heph
containername = "Ballistic armor crate" containername = "Ballistic armor crate"
access = access_armory access = access_armory
@@ -355,13 +355,13 @@
/obj/item/clothing/shoes/leg_guard/combat /obj/item/clothing/shoes/leg_guard/combat
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/saare
containername = "Combat armor crate" containername = "Combat armor crate"
access = access_armory access = access_armory
/datum/supply_pack/security/tactical /datum/supply_pack/security/tactical
name = "Armor - Tactical" name = "Armor - Tactical"
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/saare
containername = "Tactical armor crate" containername = "Tactical armor crate"
cost = 40 cost = 40
access = access_armory access = access_armory
@@ -387,7 +387,7 @@
/datum/supply_pack/security/flexitac /datum/supply_pack/security/flexitac
name = "Armor - Tactical Light" name = "Armor - Tactical Light"
containertype = /obj/structure/closet/crate/secure/gear containertype = /obj/structure/closet/crate/secure/saare
containername = "Tactical Light armor crate" containername = "Tactical Light armor crate"
cost = 75 cost = 75
access = access_armory access = access_armory
@@ -412,15 +412,14 @@
name = "Misc - Security Barriers" name = "Misc - Security Barriers"
contains = list(/obj/machinery/deployable/barrier = 4) contains = list(/obj/machinery/deployable/barrier = 4)
cost = 20 cost = 20
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/secure/heph
containername = "Security barrier crate" containername = "Security barrier crate"
access = null
/datum/supply_pack/security/securityshieldgen /datum/supply_pack/security/securityshieldgen
name = "Misc - Wall shield generators" name = "Misc - Wall shield generators"
contains = list(/obj/machinery/shieldwallgen = 4) contains = list(/obj/machinery/shieldwallgen = 4)
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/heph
containername = "Wall shield generators crate" containername = "Wall shield generators crate"
access = access_teleporter access = access_teleporter
@@ -434,7 +433,7 @@
/obj/item/clothing/accessory/holster/hip /obj/item/clothing/accessory/holster/hip
) )
cost = 15 cost = 15
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/hedberg
containername = "Holster crate" containername = "Holster crate"
/datum/supply_pack/security/extragear /datum/supply_pack/security/extragear
@@ -446,7 +445,7 @@
/obj/item/clothing/suit/storage/hooded/wintercoat/security = 3 /obj/item/clothing/suit/storage/hooded/wintercoat/security = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanothreads
containername = "Security surplus equipment" containername = "Security surplus equipment"
/datum/supply_pack/security/detectivegear /datum/supply_pack/security/detectivegear
@@ -473,7 +472,7 @@
/obj/item/weapon/storage/bag/detective /obj/item/weapon/storage/bag/detective
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Forensic equipment" containername = "Forensic equipment"
access = access_forensics_lockers access = access_forensics_lockers
@@ -486,7 +485,7 @@
/obj/item/device/detective_scanner /obj/item/device/detective_scanner
) )
cost = 60 cost = 60
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/ward
containername = "Forensic equipment" containername = "Forensic equipment"
access = access_forensics_lockers access = access_forensics_lockers
@@ -508,7 +507,7 @@
/obj/item/clothing/gloves/black = 2 /obj/item/clothing/gloves/black = 2
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Investigation clothing" containername = "Investigation clothing"
access = access_forensics_lockers access = access_forensics_lockers
@@ -538,7 +537,7 @@
/obj/item/device/flashlight/maglight /obj/item/device/flashlight/maglight
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Officer equipment" containername = "Officer equipment"
access = access_brig access = access_brig
@@ -567,7 +566,7 @@
/obj/item/device/flashlight/maglight /obj/item/device/flashlight/maglight
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Warden equipment" containername = "Warden equipment"
access = access_armory access = access_armory
@@ -594,7 +593,7 @@
/obj/item/device/flashlight/maglight /obj/item/device/flashlight/maglight
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Head of security equipment" containername = "Head of security equipment"
access = access_hos access = access_hos
@@ -613,7 +612,7 @@
/obj/item/weapon/storage/box/holobadge /obj/item/weapon/storage/box/holobadge
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Security uniform crate" containername = "Security uniform crate"
/datum/supply_pack/security/navybluesecurityclothing /datum/supply_pack/security/navybluesecurityclothing
@@ -634,7 +633,7 @@
/obj/item/weapon/storage/box/holobadge /obj/item/weapon/storage/box/holobadge
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Navy blue security uniform crate" containername = "Navy blue security uniform crate"
/datum/supply_pack/security/corporatesecurityclothing /datum/supply_pack/security/corporatesecurityclothing
@@ -654,7 +653,7 @@
/obj/item/weapon/storage/box/holobadge /obj/item/weapon/storage/box/holobadge
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Corporate security uniform crate" containername = "Corporate security uniform crate"
/datum/supply_pack/security/biosuit /datum/supply_pack/security/biosuit
@@ -670,7 +669,7 @@
/obj/item/weapon/storage/box/gloves /obj/item/weapon/storage/box/gloves
) )
cost = 25 cost = 25
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Security biohazard gear" containername = "Security biohazard gear"
access = access_security access = access_security
@@ -680,6 +679,6 @@
/obj/item/weapon/contraband/poster/nanotrasen = 6 /obj/item/weapon/contraband/poster/nanotrasen = 6
) )
cost = 20 cost = 20
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanotrasen
containername = "Morale Posters" containername = "Morale Posters"
access = access_maint_tunnels access = access_maint_tunnels

View File

@@ -18,14 +18,14 @@
/obj/item/weapon/reagent_containers/food/condiment/yeast = 3 /obj/item/weapon/reagent_containers/food/condiment/yeast = 3
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/freezer containertype = /obj/structure/closet/crate/freezer/centauri
containername = "Food crate" containername = "Food crate"
/datum/supply_pack/supply/toner /datum/supply_pack/supply/toner
name = "Toner cartridges" name = "Toner cartridges"
contains = list(/obj/item/device/toner = 6) contains = list(/obj/item/device/toner = 6)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/ummarcar
containername = "Toner cartridges" containername = "Toner cartridges"
/datum/supply_pack/supply/janitor /datum/supply_pack/supply/janitor
@@ -48,7 +48,7 @@
/obj/structure/mopbucket /obj/structure/mopbucket
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/galaksi
containername = "Janitorial supplies" containername = "Janitorial supplies"
/datum/supply_pack/supply/shipping /datum/supply_pack/supply/shipping
@@ -62,7 +62,7 @@
/obj/item/weapon/tool/wirecutters, /obj/item/weapon/tool/wirecutters,
/obj/item/weapon/tape_roll = 2) /obj/item/weapon/tape_roll = 2)
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/ummarcar
containername = "Shipping supplies crate" containername = "Shipping supplies crate"
/datum/supply_pack/supply/bureaucracy /datum/supply_pack/supply/bureaucracy
@@ -82,13 +82,13 @@
) )
name = "Office supplies" name = "Office supplies"
cost = 15 cost = 15
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/ummarcar
containername = "Office supplies crate" containername = "Office supplies crate"
/datum/supply_pack/supply/spare_pda /datum/supply_pack/supply/spare_pda
name = "Spare PDAs" name = "Spare PDAs"
cost = 10 cost = 10
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/thinktronic
containername = "Spare PDA crate" containername = "Spare PDA crate"
contains = list(/obj/item/device/pda = 3) contains = list(/obj/item/device/pda = 3)
@@ -112,7 +112,7 @@
/obj/item/clothing/glasses/meson /obj/item/clothing/glasses/meson
) )
cost = 10 cost = 10
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/xion
containername = "Shaft miner equipment" containername = "Shaft miner equipment"
access = access_mining access = access_mining
/* //VOREStation Edit - Pointless on Tether. /* //VOREStation Edit - Pointless on Tether.
@@ -127,12 +127,12 @@
name = "Cargo Train Tug" name = "Cargo Train Tug"
contains = list(/obj/vehicle/train/engine) contains = list(/obj/vehicle/train/engine)
cost = 35 cost = 35
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/xion
containername = "Cargo Train Tug Crate" containername = "Cargo Train Tug Crate"
/datum/supply_pack/supply/cargotrailer /datum/supply_pack/supply/cargotrailer
name = "Cargo Train Trolley" name = "Cargo Train Trolley"
contains = list(/obj/vehicle/train/trolley) contains = list(/obj/vehicle/train/trolley)
cost = 15 cost = 15
containertype = /obj/structure/largecrate containertype = /obj/structure/closet/crate/large/xion
containername = "Cargo Train Trolley Crate" containername = "Cargo Train Trolley Crate"

View File

@@ -17,7 +17,7 @@
/obj/item/weapon/tank/oxygen = 2, /obj/item/weapon/tank/oxygen = 2,
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/aether
containername = "Atmospheric voidsuit crate" containername = "Atmospheric voidsuit crate"
access = access_atmospherics access = access_atmospherics
@@ -31,7 +31,7 @@
/obj/item/weapon/tank/oxygen = 2, /obj/item/weapon/tank/oxygen = 2,
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/aether
containername = "Heavy Duty Atmospheric voidsuit crate" containername = "Heavy Duty Atmospheric voidsuit crate"
access = access_atmospherics access = access_atmospherics
@@ -45,7 +45,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/xion
containername = "Engineering voidsuit crate" containername = "Engineering voidsuit crate"
access = access_engine_equip access = access_engine_equip
@@ -59,7 +59,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/xion
containername = "Engineering Construction voidsuit crate" containername = "Engineering Construction voidsuit crate"
access = access_engine_equip access = access_engine_equip
@@ -73,7 +73,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 45 cost = 45
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/xion
containername = "Engineering Hazmat voidsuit crate" containername = "Engineering Hazmat voidsuit crate"
access = access_engine_equip access = access_engine_equip
@@ -87,7 +87,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/xion
containername = "Reinforced Engineering voidsuit crate" containername = "Reinforced Engineering voidsuit crate"
access = access_engine_equip access = access_engine_equip
@@ -101,7 +101,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/veymed
containername = "Medical voidsuit crate" containername = "Medical voidsuit crate"
access = access_medical_equip access = access_medical_equip
@@ -115,7 +115,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/veymed
containername = "Medical EMT voidsuit crate" containername = "Medical EMT voidsuit crate"
access = access_medical_equip access = access_medical_equip
@@ -129,7 +129,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 45 cost = 45
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/nanocare
containername = "Medical Biohazard voidsuit crate" containername = "Medical Biohazard voidsuit crate"
access = access_medical_equip access = access_medical_equip
@@ -143,7 +143,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 60 cost = 60
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/veymed
containername = "Vey-Med Autoadaptive voidsuit (humanoid) crate" containername = "Vey-Med Autoadaptive voidsuit (humanoid) crate"
access = access_medical_equip access = access_medical_equip
@@ -168,7 +168,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/heph
containername = "Security voidsuit crate" containername = "Security voidsuit crate"
/datum/supply_pack/voidsuits/security/crowd /datum/supply_pack/voidsuits/security/crowd
@@ -181,7 +181,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 60 cost = 60
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/heph
containername = "Security Crowd Control voidsuit crate" containername = "Security Crowd Control voidsuit crate"
access = access_armory access = access_armory
@@ -195,7 +195,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 60 cost = 60
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/heph
containername = "Security EVA voidsuit crate" containername = "Security EVA voidsuit crate"
access = access_armory access = access_armory
@@ -208,7 +208,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 40 cost = 40
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/xion
containername = "Mining voidsuit crate" containername = "Mining voidsuit crate"
access = access_mining access = access_mining
@@ -221,7 +221,7 @@
/obj/item/weapon/tank/oxygen = 2 /obj/item/weapon/tank/oxygen = 2
) )
cost = 50 cost = 50
containertype = /obj/structure/closet/crate/secure containertype = /obj/structure/closet/crate/secure/grayson
containername = "Frontier Mining voidsuit crate" containername = "Frontier Mining voidsuit crate"
access = access_mining access = access_mining
@@ -232,6 +232,6 @@
/obj/item/clothing/mask/gas/zaddat = 1 /obj/item/clothing/mask/gas/zaddat = 1
) )
cost = 30 cost = 30
containertype = /obj/structure/closet/crate containertype = /obj/structure/closet/crate/nanotrasen
containername = "Zaddat Shroud crate" containername = "Zaddat Shroud crate"
access = null access = null

View File

@@ -1,6 +1,6 @@
/atom/movable /atom/movable
layer = OBJ_LAYER layer = OBJ_LAYER
appearance_flags = TILE_BOUND|PIXEL_SCALE appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER
glide_size = 8 glide_size = 8
var/last_move = null //The direction the atom last moved var/last_move = null //The direction the atom last moved
var/anchored = 0 var/anchored = 0

View File

@@ -232,12 +232,6 @@
else else
to_chat(O, "<b><a href='byond://?src=\ref[O];track2=\ref[O];track=\ref[U];trackname=[U.name]'>[U]</a></b> holds \a [itemname] up to one of your cameras ...") to_chat(O, "<b><a href='byond://?src=\ref[O];track2=\ref[O];track=\ref[U];trackname=[U.name]'>[U]</a></b> holds \a [itemname] up to one of your cameras ...")
O << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", itemname, info), text("window=[]", itemname)) O << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", itemname, info), text("window=[]", itemname))
for(var/mob/O in player_list)
if (istype(O.machine, /obj/machinery/computer/security))
var/obj/machinery/computer/security/S = O.machine
if (S.current_camera == src)
to_chat(O, "[U] holds \a [itemname] up to one of the cameras ...")
O << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", itemname, info), text("window=[]", itemname))
else if (istype(W, /obj/item/weapon/camera_bug)) else if (istype(W, /obj/item/weapon/camera_bug))
if (!src.can_use()) if (!src.can_use())
@@ -494,8 +488,6 @@
else else
cameranet.updateVisibility(src, 0) cameranet.updateVisibility(src, 0)
invalidateCameraCache()
// Resets the camera's wires to fully operational state. Used by one of Malfunction abilities. // Resets the camera's wires to fully operational state. Used by one of Malfunction abilities.
/obj/machinery/camera/proc/reset_wires() /obj/machinery/camera/proc/reset_wires()
if(!wires) if(!wires)

View File

@@ -173,7 +173,6 @@ var/global/list/engineering_networks = list(
var/number = my_area.len var/number = my_area.len
c_tag = "[A.name] #[number]" c_tag = "[A.name] #[number]"
invalidateCameraCache()
/obj/machinery/camera/autoname/Destroy() /obj/machinery/camera/autoname/Destroy()
var/area/A = get_area(src) var/area/A = get_area(src)

View File

@@ -1,142 +1,132 @@
/obj/machinery/computer/aifixer /obj/machinery/computer/aifixer
name = "\improper AI system integrity restorer" name = "\improper AI system integrity restorer"
desc = "Restores AI units to working condition, assuming you have one inside!" desc = "Used with intelliCards containing nonfunctional AIs to restore them to working order."
icon_keyboard = "rd_key"
icon_screen = "ai-fixer"
light_color = "#a97faa"
circuit = /obj/item/weapon/circuitboard/aifixer
req_one_access = list(access_robotics, access_heads) req_one_access = list(access_robotics, access_heads)
var/mob/living/silicon/ai/occupant = null circuit = /obj/item/weapon/circuitboard/aifixer
var/active = 0 icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
/obj/machinery/computer/aifixer/New() active_power_usage = 1000
..()
update_icon()
/obj/machinery/computer/aifixer/proc/load_ai(var/mob/living/silicon/ai/transfer, var/obj/item/device/aicard/card, var/mob/user) /// Variable containing transferred AI
var/mob/living/silicon/ai/occupier
if(!transfer) /// Variable dictating if we are in the process of restoring the occupier AI
return var/restoring = FALSE
// Transfer over the AI.
to_chat(transfer, "You have been transferred into a stationary terminal. Sadly, there is no remote access from here.")
to_chat(user, "<span class='notice'>Transfer successful:</span> [transfer.name] placed within stationary terminal.")
transfer.loc = src
transfer.cancel_camera()
transfer.control_disabled = 1
occupant = transfer
if(card)
card.clear()
update_icon()
/obj/machinery/computer/aifixer/attackby(I as obj, user as mob)
if(istype(I, /obj/item/device/aicard))
/obj/machinery/computer/aifixer/attackby(obj/item/I, mob/living/user)
if(I.is_screwdriver())
if(occupier)
if(stat & (NOPOWER|BROKEN)) if(stat & (NOPOWER|BROKEN))
to_chat(user, "This terminal isn't functioning right now.") to_chat(user, "<span class='warning'>The screws on [name]'s screen won't budge.</span>")
else
to_chat(user, "<span class='warning'>The screws on [name]'s screen won't budge and it emits a warning beep.</span>")
return
if(istype(I, /obj/item/device/aicard))
if(stat & (NOPOWER|BROKEN))
to_chat(user, "<span class='warning'>This terminal isn't functioning right now.</span>")
return
if(restoring)
to_chat(user, "<span class='danger'>Terminal is busy restoring [occupier] right now.</span>")
return return
var/obj/item/device/aicard/card = I var/obj/item/device/aicard/card = I
var/mob/living/silicon/ai/comp_ai = locate() in src if(occupier)
var/mob/living/silicon/ai/card_ai = locate() in card if(card.grab_ai(occupier, user))
occupier = null
if(istype(comp_ai)) else if(card.carded_ai)
if(active) var/mob/living/silicon/ai/new_occupant = card.carded_ai
to_chat(user, "<span class='danger'>ERROR:</span> Reconstruction in progress.") to_chat(new_occupant, "<span class='notice'>You have been transferred into a stationary terminal. Sadly there is no remote access from here.</span>")
return to_chat(user, "<span class='notice'>Transfer Successful:</span> [new_occupant] placed within stationary terminal.")
card.grab_ai(comp_ai, user) new_occupant.forceMove(src)
if(!(locate(/mob/living/silicon/ai) in src)) occupant = null new_occupant.cancel_camera()
else if(istype(card_ai)) new_occupant.control_disabled = TRUE
load_ai(card_ai,card,user) occupier = new_occupant
occupant = locate(/mob/living/silicon/ai) in src card.clear()
update_icon() update_icon()
return else
..() to_chat(user, "<span class='notice'>There is no AI loaded onto this computer, and no AI loaded onto [I]. What exactly are you trying to do here?</span>")
return return ..()
/obj/machinery/computer/aifixer/attack_ai(var/mob/user as mob) /obj/machinery/computer/aifixer/attack_hand(mob/user)
return attack_hand(user) if(stat & (NOPOWER|BROKEN))
return
tgui_interact(user)
/obj/machinery/computer/aifixer/attack_hand(var/mob/user as mob) /obj/machinery/computer/aifixer/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AiRestorer", name)
ui.open()
/obj/machinery/computer/aifixer/tgui_data(mob/user)
var/list/data = list()
data["ejectable"] = FALSE
data["AI_present"] = FALSE
data["error"] = null
if(!occupier)
data["error"] = "Please transfer an AI unit."
else
data["AI_present"] = TRUE
data["name"] = occupier.name
data["restoring"] = restoring
data["health"] = (occupier.health + 100) / 2
data["isDead"] = occupier.stat == DEAD
var/list/laws = list()
for(var/datum/ai_law/law in occupier.laws.all_laws())
laws += "[law.get_index()]: [law.law]"
data["laws"] = laws
return data
/obj/machinery/computer/aifixer/tgui_act(action, params)
if(..()) if(..())
return return
if(!occupier)
restoring = FALSE
user.set_machine(src) switch(action)
var/dat = "<h3>AI System Integrity Restorer</h3><br><br>" if("PRG_beginReconstruction")
if(occupier?.health < 100)
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
restoring = TRUE
var/mob/observer/dead/ghost = occupier.get_ghost()
if(ghost)
ghost.notify_revive("Your core files are being restored!", source = src)
. = TRUE
if (src.occupant) /obj/machinery/computer/aifixer/proc/Fix()
var/laws use_power(active_power_usage)
dat += "Stored AI: [src.occupant.name]<br>System integrity: [src.occupant.hardware_integrity()]%<br>Backup Capacitor: [src.occupant.backup_capacitor()]%<br>" occupier.adjustOxyLoss(-5, 0, FALSE)
occupier.adjustFireLoss(-5, 0, FALSE)
occupier.adjustBruteLoss(-5, 0)
if(occupier.health >= 0 && occupier.stat == DEAD)
occupier.revive()
for (var/datum/ai_law/law in occupant.laws.all_laws()) return occupier.health < 100
laws += "[law.get_index()]: [law.law]<BR>"
dat += "Laws:<br>[laws]<br>"
if (src.occupant.stat == 2)
dat += "<b>AI nonfunctional</b>"
else
dat += "<b>AI functional</b>"
if (!src.active)
dat += {"<br><br><A href='byond://?src=\ref[src];fix=1'>Begin Reconstruction</A>"}
else
dat += "<br><br>Reconstruction in process, please wait.<br>"
dat += {" <A href='?src=\ref[user];mach_close=computer'>Close</A>"}
user << browse(dat, "window=computer;size=400x500")
onclose(user, "computer")
return
/obj/machinery/computer/aifixer/process() /obj/machinery/computer/aifixer/process()
if(..()) if(..())
src.updateDialog() if(restoring)
return var/oldstat = occupier.stat
restoring = Fix()
/obj/machinery/computer/aifixer/Topic(href, href_list) if(oldstat != occupier.stat)
if(..()) update_icon()
return 1
if (href_list["fix"])
src.active = 1
src.overlays += image(icon, "ai-fixer-on")
while (src.occupant.getOxyLoss() > 0 || src.occupant.getFireLoss() > 0 || src.occupant.getToxLoss() > 0 || src.occupant.getBruteLoss() > 0)
src.occupant.adjustOxyLoss(-1)
src.occupant.adjustFireLoss(-1)
src.occupant.adjustToxLoss(-1)
src.occupant.adjustBruteLoss(-1)
src.occupant.updatehealth()
if (src.occupant.health >= 0 && src.occupant.stat == DEAD)
src.occupant.set_stat(CONSCIOUS)
src.occupant.lying = 0
dead_mob_list -= src.occupant
living_mob_list += src.occupant
src.overlays -= image(icon, "ai-fixer-404")
src.overlays += image(icon, "ai-fixer-full")
src.occupant.add_ai_verbs()
src.updateUsrDialog()
sleep(10)
src.active = 0
src.overlays -= image(icon, "ai-fixer-on")
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/aifixer/update_icon() /obj/machinery/computer/aifixer/update_icon()
..() . = ..()
if((stat & BROKEN) || (stat & NOPOWER)) if(stat & (NOPOWER|BROKEN))
return return
if(occupant) if(restoring)
if(occupant.stat) . += "ai-fixer-on"
add_overlay("ai-fixer-404") if (occupier)
switch (occupier.stat)
if (CONSCIOUS)
. += "ai-fixer-full"
if (UNCONSCIOUS)
. += "ai-fixer-404"
else else
add_overlay("ai-fixer-full") . += "ai-fixer-empty"
else
add_overlay("ai-fixer-empty")

View File

@@ -3,201 +3,44 @@
/obj/machinery/computer/security /obj/machinery/computer/security
name = "security camera monitor" name = "security camera monitor"
desc = "Used to access the various cameras on the station." desc = "Used to access the various cameras on the station."
icon_keyboard = "security_key" icon_keyboard = "security_key"
icon_screen = "cameras" icon_screen = "cameras"
light_color = "#a91515" light_color = "#a91515"
var/current_network = null
var/obj/machinery/camera/current_camera = null
var/last_pic = 1.0
var/list/network
var/mapping = 0//For the overview file, interesting bit of code.
var/cache_id = 0
circuit = /obj/item/weapon/circuitboard/security circuit = /obj/item/weapon/circuitboard/security
/obj/machinery/computer/security/New() var/mapping = 0//For the overview file, interesting bit of code.
if(!network) var/list/network = list()
network = using_map.station_networks.Copy()
..()
if(network.len)
current_network = network[1]
/obj/machinery/computer/security/attack_ai(var/mob/user as mob) var/datum/tgui_module/camera/camera
return attack_hand(user)
/obj/machinery/computer/security/check_eye(var/mob/user as mob) /obj/machinery/computer/security/Initialize()
if (user.stat || ((get_dist(user, src) > 1 || !( user.canmove ) || user.blinded) && !istype(user, /mob/living/silicon))) //user can't see - not sure why canmove is here.
return -1
if(!current_camera)
return 0
var/viewflag = current_camera.check_eye(user)
if ( viewflag < 0 ) //camera doesn't work
reset_current()
return viewflag
/obj/machinery/computer/security/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
if(stat & (NOPOWER|BROKEN)) return
if(user.stat) return
var/data[0]
data["current_camera"] = current_camera ? current_camera.nano_structure() : null
data["current_network"] = current_network
data["networks"] = network ? network : list()
var/map_levels = using_map.get_map_levels(src.z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)
data["map_levels"] = map_levels
if(current_network)
data["cameras"] = camera_repository.cameras_in_network(current_network, map_levels)
if(current_camera)
switch_to_camera(user, current_camera)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Console", 900, 800)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "sec_camera_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "sec_camera_map_header.tmpl")
ui.set_initial_data(data)
ui.open()
/obj/machinery/computer/security/Topic(href, href_list)
if(..())
return 1
if(href_list["switch_camera"])
if(stat&(NOPOWER|BROKEN)) return //VOREStation Edit - Removed zlevel check
if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras
if(!C)
return
if(!(current_network in C.network))
return
switch_to_camera(usr, C)
return 1
else if(href_list["switch_network"])
if(stat&(NOPOWER|BROKEN)) return //VOREStation Edit - Removed zlevel check
if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
if(href_list["switch_network"] in network)
current_network = href_list["switch_network"]
return 1
else if(href_list["reset"])
if(stat&(NOPOWER|BROKEN)) return //VOREStation Edit - Removed zlevel check
if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
reset_current()
usr.reset_view(current_camera)
return 1
else
. = ..() . = ..()
if(!LAZYLEN(network))
network = using_map.station_networks.Copy()
camera = new(src, network)
/obj/machinery/computer/security/attack_hand(var/mob/user as mob) /obj/machinery/computer/security/Destroy()
if(stat & (NOPOWER|BROKEN)) return QDEL_NULL(camera)
return ..()
if(!isAI(user)) /obj/machinery/computer/security/tgui_interact(mob/user, datum/tgui/ui = null)
user.set_machine(src) camera.tgui_interact(user, ui)
ui_interact(user)
/obj/machinery/computer/security/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C) /obj/machinery/computer/security/attack_hand(mob/user)
//don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras. add_fingerprint(user)
if(isAI(user)) if(stat & (BROKEN|NOPOWER))
var/mob/living/silicon/ai/A = user
// Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
if(!A.is_in_chassis())
return 0
A.eyeobj.setLoc(get_turf(C))
A.client.eye = A.eyeobj
return 1
if (!C.can_use() || user.stat || (get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) && !istype(user, /mob/living/silicon)))
return 0
set_current(C)
user.reset_view(current_camera)
check_eye(user)
return 1
/obj/machinery/computer/security/relaymove(mob/user,direct)
var/turf/T = get_turf(current_camera)
for(var/i; i < 10; i++)
T = get_step(T, direct)
jump_on_click(user, T)
//Camera control: moving.
/obj/machinery/computer/security/proc/jump_on_click(var/mob/user,var/A)
if(user.machine != src)
return return
var/obj/machinery/camera/jump_to tgui_interact(user)
if(istype(A,/obj/machinery/camera))
jump_to = A
else if(ismob(A))
if(ishuman(A))
jump_to = locate() in A:head
else if(isrobot(A))
jump_to = A:camera
else if(isobj(A))
jump_to = locate() in A
else if(isturf(A))
var/best_dist = INFINITY
for(var/obj/machinery/camera/camera in get_area(A))
if(!camera.can_use())
continue
if(!can_access_camera(camera))
continue
var/dist = get_dist(camera,A)
if(dist < best_dist)
best_dist = dist
jump_to = camera
if(isnull(jump_to))
return
if(can_access_camera(jump_to))
switch_to_camera(user,jump_to)
/obj/machinery/computer/security/process() /obj/machinery/computer/security/attack_ai(mob/user)
if(cache_id != camera_repository.camera_cache_id) to_chat(user, "<span class='notice'>You realise its kind of stupid to access a camera console when you have the entire camera network at your metaphorical fingertips</span>")
cache_id = camera_repository.camera_cache_id
SSnanoui.update_uis(src)
/obj/machinery/computer/security/proc/can_access_camera(var/obj/machinery/camera/C)
var/list/shared_networks = src.network & C.network
if(shared_networks.len)
return 1
return 0
/obj/machinery/computer/security/proc/set_current(var/obj/machinery/camera/C)
if(current_camera == C)
return return
if(current_camera) /obj/machinery/computer/security/proc/set_network(list/new_network)
reset_current() network = new_network
camera.network = network
src.current_camera = C camera.access_based = FALSE
if(current_camera)
current_camera.camera_computers_using_this.Add(src)
update_use_power(USE_POWER_ACTIVE)
var/mob/living/L = current_camera.loc
if(istype(L))
L.tracking_initiated()
/obj/machinery/computer/security/proc/reset_current()
if(current_camera)
current_camera.camera_computers_using_this.Remove(src)
var/mob/living/L = current_camera.loc
if(istype(L))
L.tracking_cancelled()
current_camera = null
update_use_power(USE_POWER_IDLE)
//Camera control: mouse.
/* Oh my god
/atom/DblClick()
..()
if(istype(usr.machine,/obj/machinery/computer/security))
var/obj/machinery/computer/security/console = usr.machine
console.jump_on_click(usr,src)
*/
//Camera control: arrow keys. //Camera control: arrow keys.
/obj/machinery/computer/security/telescreen /obj/machinery/computer/security/telescreen

View File

@@ -1,116 +0,0 @@
//the researchable camera circuit that can connect to any camera network
/obj/item/weapon/circuitboard/camera
//name = "Circuit board (Camera)"
var/secured = 1
var/authorised = 0
var/possibleNets[0]
var/network = ""
build_path = null
//when adding a new camera network, you should only need to update these two procs
New()
possibleNets["Engineering"] = access_ce
possibleNets["SS13"] = access_hos
possibleNets["Mining"] = access_mining
possibleNets["Cargo"] = access_qm
possibleNets["Research"] = access_rd
possibleNets["Medbay"] = access_cmo
..()
proc/updateBuildPath()
build_path = null
if(authorised && secured)
switch(network)
if("SS13")
build_path = /obj/machinery/computer/security
if("Engineering")
build_path = /obj/machinery/computer/security/engineering
if("Mining")
build_path = /obj/machinery/computer/security/mining
if("Research")
build_path = /obj/machinery/computer/security/research
if("Medbay")
build_path = /obj/machinery/computer/security/medbay
if("Cargo")
build_path = /obj/machinery/computer/security/cargo
attackby(var/obj/item/I, var/mob/user)//if(health > 50)
..()
else if(I.is_screwdriver())
secured = !secured
user.visible_message("<span class='notice'>The [src] can [secured ? "no longer" : "now"] be modified.</span>")
playsound(src, I.usesound, 50, 1)
updateBuildPath()
return
attack_self(var/mob/user)
if(!secured && ishuman(user))
user.machine = src
interact(user, 0)
proc/interact(var/mob/user, var/ai=0)
if(secured)
return
if (!ishuman(user))
return ..(user)
var/t = "<B>Circuitboard Console - Camera Monitoring Computer</B><BR>"
t += "<A href='?src=\ref[src];close=1'>Close</A><BR>"
t += "<hr> Please select a camera network:<br>"
for(var/curNet in possibleNets)
if(network == curNet)
t += "- [curNet]<br>"
else
t += "- <A href='?src=\ref[src];net=[curNet]'>[curNet]</A><BR>"
t += "<hr>"
if(network)
if(authorised)
t += "Authenticated <A href='?src=\ref[src];removeauth=1'>(Clear Auth)</A><BR>"
else
t += "<A href='?src=\ref[src];auth=1'><b>*Authenticate*</b></A> (Requires an appropriate access ID)<br>"
else
t += "<A href='?src=\ref[src];auth=1'>*Authenticate*</A> (Requires an appropriate access ID)<BR>"
t += "<A href='?src=\ref[src];close=1'>Close</A><BR>"
user << browse(t, "window=camcircuit;size=500x400")
onclose(user, "camcircuit")
Topic(href, href_list)
..()
if( href_list["close"] )
usr << browse(null, "window=camcircuit")
usr.machine = null
return
else if(href_list["net"])
network = href_list["net"]
authorised = 0
else if( href_list["auth"] )
var/mob/M = usr
var/obj/item/weapon/card/id/I = M.equipped()
if (istype(I, /obj/item/device/pda))
var/obj/item/device/pda/pda = I
I = pda.id
if (I && istype(I))
if(access_captain in I.access)
authorised = 1
else if (possibleNets[network] in I.access)
authorised = 1
if(istype(I,/obj/item/weapon/card/emag))
I.resolve_attackby(src, usr)
else if( href_list["removeauth"] )
authorised = 0
updateDialog()
updateDialog()
if(istype(src.loc,/mob))
attack_self(src.loc)
/obj/item/weapon/circuitboard/camera/emag_act(var/remaining_charges, var/mob/user)
if(network)
authorised = 1
to_chat(user, "<span class='notice'>You authorised the circuit network!</span>")
updateDialog()
return 1
else
to_chat(user, "<span class='warning'>You must select a camera network circuit!</span>")

View File

@@ -8,7 +8,7 @@
idle_power_usage = 250 idle_power_usage = 250
active_power_usage = 500 active_power_usage = 500
circuit = /obj/item/weapon/circuitboard/crew circuit = /obj/item/weapon/circuitboard/crew
var/datum/nano_module/program/crew_monitor/crew_monitor var/datum/tgui_module/crew_monitor/crew_monitor
/obj/machinery/computer/crew/New() /obj/machinery/computer/crew/New()
crew_monitor = new(src) crew_monitor = new(src)
@@ -20,16 +20,16 @@
..() ..()
/obj/machinery/computer/crew/attack_ai(mob/user) /obj/machinery/computer/crew/attack_ai(mob/user)
ui_interact(user) attack_hand(user)
/obj/machinery/computer/crew/attack_hand(mob/user) /obj/machinery/computer/crew/attack_hand(mob/user)
add_fingerprint(user) add_fingerprint(user)
if(stat & (BROKEN|NOPOWER)) if(stat & (BROKEN|NOPOWER))
return return
ui_interact(user) tgui_interact(user)
/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) /obj/machinery/computer/crew/tgui_interact(mob/user, datum/tgui/ui = null)
crew_monitor.ui_interact(user, ui_key, ui, force_open) crew_monitor.tgui_interact(user, ui)
/obj/machinery/computer/crew/interact(mob/user) /obj/machinery/computer/crew/interact(mob/user)
crew_monitor.ui_interact(user) crew_monitor.tgui_interact(user)

View File

@@ -522,7 +522,7 @@
announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]", announce_channel, using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)) announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]", announce_channel, using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE))
//visible_message("<span class='notice'>\The [initial(name)] hums and hisses as it moves [to_despawn.real_name] into storage.</span>", 3) //visible_message("<span class='notice'>\The [initial(name)] hums and hisses as it moves [to_despawn.real_name] into storage.</span>", 3)
visible_message("<span class='notice'>\The [initial(name)] [on_store_visible_message_1] [to_despawn.real_name] [on_store_visible_message_2].</span>", 3) visible_message("<span class='notice'>\The [initial(name)] [on_store_visible_message_1] [to_despawn.real_name] [on_store_visible_message_2]</span>", 3)
//VOREStation Edit begin: Dont delete mobs-in-mobs //VOREStation Edit begin: Dont delete mobs-in-mobs
if(to_despawn.client && to_despawn.stat<2) if(to_despawn.client && to_despawn.stat<2)

View File

@@ -164,6 +164,8 @@
var/datum/action/innate/mecha/mech_switch_damtype/switch_damtype_action = new var/datum/action/innate/mecha/mech_switch_damtype/switch_damtype_action = new
var/datum/action/innate/mecha/mech_toggle_phasing/phasing_action = new var/datum/action/innate/mecha/mech_toggle_phasing/phasing_action = new
var/weapons_only_cycle = FALSE //So combat mechs don't switch to their equipment at times.
/obj/mecha/drain_power(var/drain_check) /obj/mecha/drain_power(var/drain_check)

View File

@@ -185,6 +185,9 @@
var/list/available_equipment = list() var/list/available_equipment = list()
available_equipment = chassis.equipment available_equipment = chassis.equipment
if(chassis.weapons_only_cycle)
available_equipment = chassis.weapon_equipment
if(available_equipment.len == 0) if(available_equipment.len == 0)
chassis.occupant_message("No equipment available.") chassis.occupant_message("No equipment available.")
return return
@@ -419,3 +422,17 @@
return return
/obj/mecha/verb/toggle_weapons_only_cycle()
set category = "Exosuit Interface"
set name = "Toggle weapons only cycling"
set src = usr.loc
set popup_menu = 0
set_weapons_only_cycle()
/obj/mecha/proc/set_weapons_only_cycle()
if(usr!=src.occupant)
return
weapons_only_cycle = !weapons_only_cycle
src.occupant_message("<font color=\"[weapons_only_cycle?"#00f\">En":"#f00\">Dis"]abled weapons only cycling.</font>")
return

View File

@@ -7,6 +7,7 @@
R.add_language(LANGUAGE_DAEMON, 1) R.add_language(LANGUAGE_DAEMON, 1)
R.add_language(LANGUAGE_ENOCHIAN, 1) R.add_language(LANGUAGE_ENOCHIAN, 1)
R.add_language(LANGUAGE_SLAVIC, 1) R.add_language(LANGUAGE_SLAVIC, 1)
R.add_language(LANGUAGE_DRUDAKAR, 1)
return 1 return 1
else else
return 0 return 0

View File

@@ -33,7 +33,7 @@
var/datum/pipe_recipe/recipe // pipe recipie selected for display/construction var/datum/pipe_recipe/recipe // pipe recipie selected for display/construction
var/static/datum/pipe_recipe/first_atmos var/static/datum/pipe_recipe/first_atmos
var/static/datum/pipe_recipe/first_disposal var/static/datum/pipe_recipe/first_disposal
var/static/datum/asset/iconsheet/pipes/icon_assets var/static/datum/asset/spritesheet/pipes/icon_assets
var/static/list/pipe_layers = list( var/static/list/pipe_layers = list(
"Regular" = PIPING_LAYER_REGULAR, "Regular" = PIPING_LAYER_REGULAR,
"Supply" = PIPING_LAYER_SUPPLY, "Supply" = PIPING_LAYER_SUPPLY,
@@ -75,7 +75,7 @@
/obj/item/weapon/pipe_dispenser/interact(mob/user) /obj/item/weapon/pipe_dispenser/interact(mob/user)
SetupPipes() SetupPipes()
if(!icon_assets) if(!icon_assets)
icon_assets = get_asset_datum(/datum/asset/iconsheet/pipes) icon_assets = get_asset_datum(/datum/asset/spritesheet/pipes)
icon_assets.send(user) icon_assets.send(user)
var/list/lines = list() var/list/lines = list()
@@ -365,7 +365,7 @@
if(_dir == p_dir && flipped == p_flipped) if(_dir == p_dir && flipped == p_flipped)
attrs += " class=\"linkOn\"" attrs += " class=\"linkOn\""
if(icon_state) if(icon_state)
var/img_tag = icon_assets.icon_tag(icon_state, _dir) var/img_tag = icon_assets.icon_tag("[dirtext]-[icon_state]")
return "<a href=\"?src=\ref[src];dir=[dirtext];flipped=[flipped]\" title=\"[title]\"[attrs]>[img_tag]</a>" return "<a href=\"?src=\ref[src];dir=[dirtext];flipped=[flipped]\" title=\"[title]\"[attrs]>[img_tag]</a>"
else else
return "<a href=\"?src=\ref[src];dir=[dirtext];flipped=[flipped]\" title=\"[title]\"[attrs]>[noimg]</a>" return "<a href=\"?src=\ref[src];dir=[dirtext];flipped=[flipped]\" title=\"[title]\"[attrs]>[noimg]</a>"

View File

@@ -12,7 +12,6 @@
/obj/item/weapon/circuitboard/security/New() /obj/item/weapon/circuitboard/security/New()
..() ..()
network = using_map.station_networks
/obj/item/weapon/circuitboard/security/tv /obj/item/weapon/circuitboard/security/tv
name = T_BOARD("security camera monitor - television") name = T_BOARD("security camera monitor - television")
@@ -45,7 +44,7 @@
/obj/item/weapon/circuitboard/security/construct(var/obj/machinery/computer/security/C) /obj/item/weapon/circuitboard/security/construct(var/obj/machinery/computer/security/C)
if (..(C)) if (..(C))
C.network = network.Copy() C.set_network(network.Copy())
/obj/item/weapon/circuitboard/security/deconstruct(var/obj/machinery/computer/security/C) /obj/item/weapon/circuitboard/security/deconstruct(var/obj/machinery/computer/security/C)
if (..(C)) if (..(C))

View File

@@ -34,6 +34,36 @@
/obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt,
/obj/effect/decal/remains/robot) /obj/effect/decal/remains/robot)
/obj/random/crate //Random 'standard' crates for variety in maintenance spawns.
name = "random crate"
desc = "This is a random crate"
icon = 'icons/obj/closets/bases/crate.dmi'
icon_state = "base"
/obj/random/crate/item_to_spawn() //General crates, excludes some more high-grade and medical brands
return pick (/obj/structure/closet/crate/plastic,
/obj/structure/closet/crate/aether,
/obj/structure/closet/crate/centauri,
/obj/structure/closet/crate/einstein,
/obj/structure/closet/crate/focalpoint,
/obj/structure/closet/crate/gilthari,
/obj/structure/closet/crate/grayson,
/obj/structure/closet/crate/nanotrasen,
/obj/structure/closet/crate/nanothreads,
/obj/structure/closet/crate/oculum,
/obj/structure/closet/crate/ward,
/obj/structure/closet/crate/xion,
/obj/structure/closet/crate/zenghu,
/obj/structure/closet/crate/allico,
/obj/structure/closet/crate/carp,
/obj/structure/closet/crate/galaksi,
/obj/structure/closet/crate/thinktronic,
/obj/structure/closet/crate/ummarcar,
/obj/structure/closet/crate/unathi,
/obj/structure/closet/crate/hydroponics,
/obj/structure/closet/crate/engineering,
/obj/structure/closet/crate)
/obj/random/obstruction //Large objects to block things off in maintenance /obj/random/obstruction //Large objects to block things off in maintenance
name = "random obstruction" name = "random obstruction"
desc = "This is a random obstruction." desc = "This is a random obstruction."

View File

@@ -761,8 +761,210 @@
"lid_stripes" = COLOR_NT_RED "lid_stripes" = COLOR_NT_RED
) )
// Freezers
/decl/closet_appearance/crate/freezer /decl/closet_appearance/crate/freezer
color = COLOR_OFF_WHITE
/decl/closet_appearance/crate/freezer/centauri
color = COLOR_BABY_BLUE color = COLOR_BABY_BLUE
extra_decals = list(
"centauri" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/freezer/nanotrasen
color = COLOR_BABY_BLUE
extra_decals = list(
"nano" = COLOR_OFF_WHITE
)
// Corporate Branding
/decl/closet_appearance/crate/aether
color = COLOR_YELLOW_GRAY
decals = list(
"crate_stripes" = COLOR_BLUE_LIGHT,
"aether" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/allico
color = COLOR_LIGHT_VIOLET
decals = list(
"crate_stripe" = COLOR_AMBER
)
/decl/closet_appearance/crate/carp
color = COLOR_PURPLE
decals = list(
"toptext" = COLOR_OFF_WHITE,
"crate_reticle" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/centauri
color = COLOR_BABY_BLUE
decals = list(
"crate_stripe" = COLOR_LUMINOL
)
extra_decals = list(
"centauri" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/cybersolutions
color = COLOR_ALUMINIUM
extra_decals = list(
"hazard" = COLOR_DARK_GOLD,
"toptext" = COLOR_DARK_GOLD
)
/decl/closet_appearance/crate/einstein
color = COLOR_DARK_BLUE_GRAY
extra_decals = list(
"crate_stripe_left" = COLOR_BEIGE,
"crate_stripe_right" = COLOR_BEIGE,
"einstein" = COLOR_OFF_WHITE,
"hazard" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/focalpoint
color = COLOR_GOLD
extra_decals = list(
"crate_stripe_left" = COLOR_NAVY_BLUE,
"crate_stripe_right" = COLOR_NAVY_BLUE,
"focal" = COLOR_OFF_WHITE,
"hazard" = COLOR_NAVY_BLUE
)
/decl/closet_appearance/crate/galaksi
color = COLOR_OFF_WHITE
decals = list(
"lid_stripes" = COLOR_HULL,
"galaksi" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/gilthari
color = COLOR_GRAY20
extra_decals = list(
"crate_stripe_left" = COLOR_GOLD,
"crate_stripe_right" = COLOR_GOLD,
"gilthari" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/grayson
color = COLOR_STEEL
extra_decals = list(
"crate_stripe_left" = COLOR_MAROON,
"crate_stripe_right" = COLOR_MAROON,
"grayson" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/heph
color = COLOR_GRAY20
extra_decals = list(
"crate_stripe_left" = COLOR_NT_RED,
"crate_stripe_right" = COLOR_NT_RED,
"heph" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/morpheus
color = COLOR_ALUMINIUM
extra_decals = list(
"hazard" = COLOR_GUNMETAL,
"toptext" = COLOR_GUNMETAL
)
/decl/closet_appearance/crate/nanotrasen
color = COLOR_NT_RED
extra_decals = list(
"crate_stripe_left" = COLOR_OFF_WHITE,
"crate_stripe_right" = COLOR_OFF_WHITE,
"nano" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/nanotrasenclothing
color = COLOR_NT_RED
extra_decals = list(
"crate_stripe_left" = COLOR_SEDONA,
"crate_stripe_right" = COLOR_SEDONA,
"nano" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/nanotrasenmedical
color = COLOR_OFF_WHITE
extra_decals = list(
"crate_stripe" = COLOR_NT_RED,
"nano" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/oculum
color = COLOR_SURGERY_BLUE
decals = list(
"crate_stripe_left" = COLOR_OFF_WHITE,
"crate_stripe_right" = COLOR_OFF_WHITE,
"oculum" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/saare
color = COLOR_ALUMINIUM
extra_decals = list(
"hazard" = COLOR_RED,
"xion" = COLOR_GRAY40
)
/decl/closet_appearance/crate/thinktronic
color = COLOR_PALE_PURPLE_GRAY
decals = list(
"toptext" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/ummarcar
color = COLOR_BEIGE
decals = list(
"crate_stripes" = COLOR_OFF_WHITE,
"toptext" = COLOR_GRAY20
)
/decl/closet_appearance/crate/unathiimport
color = COLOR_SILVER
decals = list(
"crate_stripe" = COLOR_RED,
"crate_reticle" = COLOR_RED_GRAY
)
/decl/closet_appearance/crate/veymed
color = COLOR_OFF_WHITE
decals = list(
"crate_stripe" = COLOR_PALE_BTL_GREEN
)
extra_decals = list(
"lid_stripes" = COLOR_RED,
"crate_cross" = COLOR_GREEN
)
/decl/closet_appearance/crate/ward
color = COLOR_OFF_WHITE
extra_decals = list(
"crate_stripe_left" = COLOR_COMMAND_BLUE,
"crate_stripe_right" = COLOR_COMMAND_BLUE,
"hazard" = COLOR_OFF_WHITE,
"wt" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/xion
color = COLOR_ORANGE
extra_decals = list(
"crate_stripes" = COLOR_OFF_WHITE,
"xion" = COLOR_OFF_WHITE,
"hazard" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/zenghu
color = COLOR_OFF_WHITE
extra_decals = list(
"crate_stripes" = COLOR_RED,
"zenghu" = COLOR_OFF_WHITE
)
// Secure Crates
/decl/closet_appearance/crate/secure /decl/closet_appearance/crate/secure
can_lock = TRUE can_lock = TRUE
@@ -775,7 +977,8 @@
extra_decals = list( extra_decals = list(
"crate_stripe_left" = COLOR_OFF_WHITE, "crate_stripe_left" = COLOR_OFF_WHITE,
"crate_stripe_right" = COLOR_OFF_WHITE, "crate_stripe_right" = COLOR_OFF_WHITE,
"toxin" = COLOR_OFF_WHITE "toxin" = COLOR_OFF_WHITE,
"nano" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/crate/secure/weapon /decl/closet_appearance/crate/secure/weapon
@@ -789,16 +992,61 @@
"hazard" = COLOR_OFF_WHITE "hazard" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/crate/secure/heph // Secure corporate branding
color = COLOR_GRAY20
/decl/closet_appearance/crate/secure/aether
color = COLOR_YELLOW_GRAY
decals = list( decals = list(
"crate_bracing" "crate_bracing"
) )
extra_decals = list( extra_decals = list(
"crate_stripe_left" = COLOR_NT_RED, "crate_stripes" = COLOR_BLUE_LIGHT,
"crate_stripe_right" = COLOR_NT_RED, "aether" = COLOR_OFF_WHITE
"hazard" = COLOR_OFF_WHITE, )
"heph" = COLOR_OFF_WHITE
/decl/closet_appearance/crate/secure/bishop
color = COLOR_OFF_WHITE
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_SKY_BLUE,
"crate_stripe_right" = COLOR_SKY_BLUE,
"bishop" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/cybersolutions
color = COLOR_ALUMINIUM
decals = list(
"crate_bracing"
)
extra_decals = list(
"hazard" = COLOR_DARK_GOLD,
"toptext" = COLOR_DARK_GOLD
)
/decl/closet_appearance/crate/secure/einstein
color = COLOR_DARK_BLUE_GRAY
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_BEIGE,
"crate_stripe_right" = COLOR_BEIGE,
"einstein" = COLOR_OFF_WHITE,
"hazard" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/focalpoint
color = COLOR_GOLD
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_NAVY_BLUE,
"crate_stripe_right" = COLOR_NAVY_BLUE,
"focal" = COLOR_OFF_WHITE,
"hazard" = COLOR_NAVY_BLUE
) )
/decl/closet_appearance/crate/secure/gilthari /decl/closet_appearance/crate/secure/gilthari
@@ -813,16 +1061,15 @@
"gilthari" = COLOR_OFF_WHITE "gilthari" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/crate/secure/ward /decl/closet_appearance/crate/secure/grayson
color = COLOR_OFF_WHITE color = COLOR_STEEL
decals = list( decals = list(
"crate_bracing" "crate_bracing"
) )
extra_decals = list( extra_decals = list(
"crate_stripe_left" = COLOR_COMMAND_BLUE, "crate_stripe_left" = COLOR_MAROON,
"crate_stripe_right" = COLOR_COMMAND_BLUE, "crate_stripe_right" = COLOR_MAROON,
"hazard" = COLOR_OFF_WHITE, "grayson" = COLOR_OFF_WHITE
"wt" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/crate/secure/hedberg /decl/closet_appearance/crate/secure/hedberg
@@ -837,6 +1084,18 @@
"hedberg" = COLOR_OFF_WHITE "hedberg" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/crate/secure/heph
color = COLOR_GRAY20
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_NT_RED,
"crate_stripe_right" = COLOR_NT_RED,
"hazard" = COLOR_OFF_WHITE,
"heph" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/lawson /decl/closet_appearance/crate/secure/lawson
color = COLOR_SAN_MARINO_BLUE color = COLOR_SAN_MARINO_BLUE
decals = list( decals = list(
@@ -849,6 +1108,103 @@
"lawson" = COLOR_OFF_WHITE "lawson" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/crate/secure/morpheus
color = COLOR_ALUMINIUM
decals = list(
"crate_bracing"
)
extra_decals = list(
"hazard" = COLOR_GUNMETAL,
"toptext" = COLOR_GUNMETAL
)
/decl/closet_appearance/crate/secure/nanotrasen
color = COLOR_NT_RED
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_OFF_WHITE,
"crate_stripe_right" = COLOR_OFF_WHITE,
"nano" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/nanotrasenmedical
color = COLOR_OFF_WHITE
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe" = COLOR_NT_RED,
"nano" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/saare
color = COLOR_ALUMINIUM
decals = list(
"crate_bracing"
)
extra_decals = list(
"hazard" = COLOR_RED,
"xion" = COLOR_GRAY40
)
/decl/closet_appearance/crate/secure/solgov
color = COLOR_SAN_MARINO_BLUE
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_OFF_WHITE,
"crate_stripes" = COLOR_OFF_WHITE,
"hazard" = COLOR_OFF_WHITE,
"scg" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/veymed
color = COLOR_OFF_WHITE
decals = list(
"crate_bracing",
"crate_stripe" = COLOR_PALE_BTL_GREEN
)
extra_decals = list(
"lid_stripes" = COLOR_RED,
"crate_cross" = COLOR_GREEN
)
/decl/closet_appearance/crate/secure/ward
color = COLOR_OFF_WHITE
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripe_left" = COLOR_COMMAND_BLUE,
"crate_stripe_right" = COLOR_COMMAND_BLUE,
"hazard" = COLOR_OFF_WHITE,
"wt" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/xion
color = COLOR_ORANGE
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripes" = COLOR_OFF_WHITE,
"xion" = COLOR_OFF_WHITE,
"hazard" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/zenghu
color = COLOR_OFF_WHITE
decals = list(
"crate_bracing"
)
extra_decals = list(
"crate_stripes" = COLOR_RED,
"zenghu" = COLOR_OFF_WHITE
)
/decl/closet_appearance/crate/secure/hydroponics /decl/closet_appearance/crate/secure/hydroponics
extra_decals = list( extra_decals = list(
"crate_stripe_left" = COLOR_GREEN_GRAY, "crate_stripe_left" = COLOR_GREEN_GRAY,
@@ -869,6 +1225,7 @@
extra_decals = null extra_decals = null
/decl/closet_appearance/large_crate/critter /decl/closet_appearance/large_crate/critter
color = COLOR_BEIGE
decals = list( decals = list(
"airholes" "airholes"
) )
@@ -882,6 +1239,42 @@
"text" = COLOR_GREEN_GRAY "text" = COLOR_GREEN_GRAY
) )
/decl/closet_appearance/large_crate/aether
color = COLOR_YELLOW_GRAY
decals = list(
"crate_bracing"
)
extra_decals = list(
"text" = COLOR_BLUE_LIGHT
)
/decl/closet_appearance/large_crate/einstein
color = COLOR_DARK_BLUE_GRAY
decals = list(
"crate_bracing"
)
extra_decals = list(
"text" = COLOR_BEIGE
)
/decl/closet_appearance/large_crate/nanotrasen
color = COLOR_NT_RED
decals = list(
"crate_bracing"
)
extra_decals = list(
"text" = COLOR_OFF_WHITE
)
/decl/closet_appearance/large_crate/xion
color = COLOR_ORANGE
decals = list(
"crate_bracing"
)
extra_decals = list(
"text" = COLOR_OFF_WHITE
)
/decl/closet_appearance/large_crate/secure /decl/closet_appearance/large_crate/secure
can_lock = TRUE can_lock = TRUE
@@ -895,6 +1288,46 @@
"text_upper" = COLOR_OFF_WHITE "text_upper" = COLOR_OFF_WHITE
) )
/decl/closet_appearance/large_crate/secure/aether
color = COLOR_YELLOW_GRAY
decals = list(
"crate_bracing"
)
extra_decals = list(
"marking" = COLOR_OFF_WHITE,
"text_upper" = COLOR_BLUE_LIGHT
)
/decl/closet_appearance/large_crate/secure/einstein
color = COLOR_DARK_BLUE_GRAY
decals = list(
"crate_bracing"
)
extra_decals = list(
"marking" = COLOR_OFF_WHITE,
"text_upper" = COLOR_BEIGE
)
/decl/closet_appearance/large_crate/secure/heph
color = COLOR_GRAY20
decals = list(
"crate_bracing"
)
extra_decals = list(
"marking" = COLOR_NT_RED,
"text_upper" = COLOR_NT_RED
)
/decl/closet_appearance/large_crate/secure/xion
color = COLOR_ORANGE
decals = list(
"crate_bracing"
)
extra_decals = list(
"marking" = COLOR_OFF_WHITE,
"text_upper" = COLOR_OFF_WHITE
)
// Cabinets. // Cabinets.
/decl/closet_appearance/cabinet /decl/closet_appearance/cabinet
base_icon = 'icons/obj/closets/bases/cabinet.dmi' base_icon = 'icons/obj/closets/bases/cabinet.dmi'

View File

@@ -6,6 +6,7 @@
icon = 'icons/obj/closets/bases/crate.dmi' icon = 'icons/obj/closets/bases/crate.dmi'
closet_appearance = /decl/closet_appearance/crate closet_appearance = /decl/closet_appearance/crate
climbable = 1 climbable = 1
dir = 4 //Spawn facing 'forward' by default.
var/points_per_crate = 5 var/points_per_crate = 5
var/rigged = 0 var/rigged = 0
@@ -65,6 +66,26 @@
update_icon() update_icon()
return 1 return 1
/obj/structure/closet/crate/verb/rotate_clockwise()
set name = "Rotate Crate Clockwise"
set category = "Object"
set src in oview(1)
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, 270))
/obj/structure/closet/crate/verb/rotate_counterclockwise()
set category = "Object"
set name = "Rotate Crate Counterclockwise"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, 90))
/obj/structure/closet/crate/attackby(obj/item/weapon/W as obj, mob/user as mob) /obj/structure/closet/crate/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(opened) if(opened)
if(isrobot(user)) if(isrobot(user))
@@ -274,6 +295,14 @@
var/target_temp = T0C - 40 var/target_temp = T0C - 40
var/cooling_power = 40 var/cooling_power = 40
/obj/structure/closet/crate/freezer/centauri
desc = "A freezer stamped with the logo of Centauri Provisions."
closet_appearance = /decl/closet_appearance/crate/freezer/centauri
/obj/structure/closet/crate/freezer/nanotrasen
desc = "A freezer stamped with the logo of NanoTrasen."
closet_appearance = /decl/closet_appearance/crate/freezer/nanotrasen
/obj/structure/closet/crate/freezer/return_air() /obj/structure/closet/crate/freezer/return_air()
var/datum/gas_mixture/gas = (..()) var/datum/gas_mixture/gas = (..())
if(!gas) return null if(!gas) return null
@@ -303,6 +332,11 @@
organ.preserved = 0 organ.preserved = 0
..() ..()
/obj/structure/closet/crate/weapon
name = "weapons crate"
desc = "A barely secured weapons crate."
closet_appearance = /decl/closet_appearance/crate/secure/weapon
/obj/structure/closet/crate/freezer/rations //Fpr use in the escape shuttle /obj/structure/closet/crate/freezer/rations //Fpr use in the escape shuttle
name = "emergency rations" name = "emergency rations"
desc = "A crate of emergency rations." desc = "A crate of emergency rations."
@@ -310,14 +344,12 @@
starts_with = list( starts_with = list(
/obj/random/mre = 6) /obj/random/mre = 6)
/obj/structure/closet/crate/bin /obj/structure/closet/crate/bin
name = "large bin" name = "large bin"
desc = "A large bin." desc = "A large bin."
closet_appearance = null closet_appearance = null
icon = 'icons/obj/closets/largebin.dmi' icon = 'icons/obj/closets/largebin.dmi'
/obj/structure/closet/crate/radiation /obj/structure/closet/crate/radiation
name = "radioactive gear crate" name = "radioactive gear crate"
desc = "A crate with a radiation sign on it." desc = "A crate with a radiation sign on it."
@@ -327,27 +359,145 @@
/obj/item/clothing/suit/radiation = 4, /obj/item/clothing/suit/radiation = 4,
/obj/item/clothing/head/radiation = 4) /obj/item/clothing/head/radiation = 4)
//TSCs
/obj/structure/closet/crate/aether
desc = "A crate painted in the colours of Aether Atmospherics and Recycling."
closet_appearance = /decl/closet_appearance/crate/aether
/obj/structure/closet/crate/centauri
desc = "A crate decorated with the logo of Centauri Provisions."
closet_appearance = /decl/closet_appearance/crate/centauri
/obj/structure/closet/crate/einstein
desc = "A crate labelled with an Einstein Engines sticker."
closet_appearance = /decl/closet_appearance/crate/einstein
/obj/structure/closet/crate/focalpoint
desc = "A crate marked with the decal of Focal Point Energistics."
closet_appearance = /decl/closet_appearance/crate/focalpoint
/obj/structure/closet/crate/gilthari
desc = "A crate embossed with the logo of Gilthari Exports."
closet_appearance = /decl/closet_appearance/crate/gilthari
/obj/structure/closet/crate/grayson
desc = "A bare metal crate spraypainted with Grayson Manufactories decals."
closet_appearance = /decl/closet_appearance/crate/grayson
/obj/structure/closet/crate/heph
desc = "A sturdy crate marked with the logo of Hephaestus Industries."
closet_appearance = /decl/closet_appearance/crate/heph
/obj/structure/closet/crate/morpheus
desc = "A crate crudely imprinted with 'MORPHEUS CYBERKINETICS'."
closet_appearance = /decl/closet_appearance/crate/morpheus
/obj/structure/closet/crate/nanotrasen
desc = "A crate emblazoned with the standard NanoTrasen livery."
closet_appearance = /decl/closet_appearance/crate/nanotrasen
/obj/structure/closet/crate/nanothreads
desc = "A crate emblazoned with the NanoThreads Garments livery, a subsidary of the NanoTrasen Corporation."
closet_appearance = /decl/closet_appearance/crate/nanotrasenclothing
/obj/structure/closet/crate/nanocare
desc = "A crate emblazoned with the NanoCare Medical livery, a subsidary of the NanoTrasen Corporation."
closet_appearance = /decl/closet_appearance/crate/nanotrasenmedical
/obj/structure/closet/crate/oculum
desc = "A crate minimally decorated with the logo of media giant Oculum Broadcast."
closet_appearance = /decl/closet_appearance/crate/oculum
/obj/structure/closet/crate/veymed
desc = "A sterile crate extensively detailed in Veymed colours."
closet_appearance = /decl/closet_appearance/crate/veymed
/obj/structure/closet/crate/ward
desc = "A crate decaled with the logo of Ward-Takahashi."
closet_appearance = /decl/closet_appearance/crate/ward
/obj/structure/closet/crate/xion
desc = "A crate painted in Xion Manufacturing Group orange."
closet_appearance = /decl/closet_appearance/crate/xion
/obj/structure/closet/crate/zenghu
desc = "A sterile crate marked with the logo of Zeng-Hu Pharmaceuticals."
closet_appearance = /decl/closet_appearance/crate/zenghu
// Brands/subsidiaries
/obj/structure/closet/crate/allico
desc = "A crate painted in the distinctive cheerful colours of AlliCo. Ltd."
closet_appearance = /decl/closet_appearance/crate/allico
/obj/structure/closet/crate/carp
desc = "A crate painted with the garish livery of Consolidated Agricultural Resources Plc."
closet_appearance = /decl/closet_appearance/crate/carp
/obj/structure/closet/crate/hedberg
name = "weapons crate"
desc = "A weapons crate stamped with the logo of Hedberg-Hammarstrom and the lock conspicuously absent."
closet_appearance = /decl/closet_appearance/crate/secure/hedberg
/obj/structure/closet/crate/galaksi
desc = "A crate printed with the markings of Ward-Takahashi's Galaksi Appliance branding."
closet_appearance = /decl/closet_appearance/crate/galaksi
/obj/structure/closet/crate/thinktronic
desc = "A crate printed with the markings of Thinktronic Systems."
closet_appearance = /decl/closet_appearance/crate/thinktronic
/obj/structure/closet/crate/ummarcar
desc = "A flimsy crate marked labelled 'UmMarcar Office Supply'."
closet_appearance = /decl/closet_appearance/crate/ummarcar
/obj/structure/closet/crate/unathi
name = "import crate"
desc = "A crate painted with the markings of Moghes Imported Sissalik Jerky."
closet_appearance = /decl/closet_appearance/crate/unathiimport
// Secure Crates
/obj/structure/closet/crate/secure/weapon /obj/structure/closet/crate/secure/weapon
name = "weapons crate" name = "weapons crate"
desc = "A secure weapons crate." desc = "A secure weapons crate."
closet_appearance = /decl/closet_appearance/crate/secure/weapon closet_appearance = /decl/closet_appearance/crate/secure/weapon
/obj/structure/closet/crate/secure/aether
desc = "A secure crate painted in the colours of Aether Atmospherics and Recycling."
closet_appearance = /decl/closet_appearance/crate/secure/aether
/obj/structure/closet/crate/secure/bishop
desc = "A secure crate finely decorated with the emblem of Bishop Cybernetics."
closet_appearance = /decl/closet_appearance/crate/secure/bishop
/obj/structure/closet/crate/secure/cybersolutions
desc = "An unadorned secure metal crate labelled 'Cyber Solutions'."
closet_appearance = /decl/closet_appearance/crate/secure/cybersolutions
/obj/structure/closet/crate/secure/einstein
desc = "A secure crate labelled with an Einstein Engines sticker."
closet_appearance = /decl/closet_appearance/crate/secure/einstein
/obj/structure/closet/crate/secure/focalpoint
desc = "A secure crate marked with the decal of Focal Point Energistics."
closet_appearance = /decl/closet_appearance/crate/secure/focalpoint
/obj/structure/closet/crate/secure/gilthari
desc = "A secure crate embossed with the logo of Gilthari Exports."
closet_appearance = /decl/closet_appearance/crate/secure/gilthari
/obj/structure/closet/crate/secure/grayson
desc = "A secure bare metal crate spraypainted with Grayson Manufactories decals."
closet_appearance = /decl/closet_appearance/crate/secure/grayson
/obj/structure/closet/crate/secure/hedberg /obj/structure/closet/crate/secure/hedberg
name = "weapons crate" name = "weapons crate"
desc = "A secure weapons crate stamped with the logo of Hedberg-Hammarstrom." desc = "A secure weapons crate stamped with the logo of Hedberg-Hammarstrom."
closet_appearance = /decl/closet_appearance/crate/secure/hedberg closet_appearance = /decl/closet_appearance/crate/secure/hedberg
/obj/structure/closet/crate/secure/gilthari
name = "weapons crate"
desc = "A secure weapons crate embossed with the logo of Gilthari Exports."
closet_appearance = /decl/closet_appearance/crate/secure/gilthari
/obj/structure/closet/crate/secure/ward
name = "weapons crate"
desc = "A secure weapons crate decaled with the logo of Ward-Takahashi."
closet_appearance = /decl/closet_appearance/crate/secure/ward
/obj/structure/closet/crate/secure/heph /obj/structure/closet/crate/secure/heph
name = "weapons crate" name = "weapons crate"
desc = "A secure weapons crate marked with the logo of Hephaestus Industries." desc = "A secure weapons crate marked with the logo of Hephaestus Industries."
@@ -358,9 +508,47 @@
desc = "A secure weapons crate marked with the logo of Lawson Arms." desc = "A secure weapons crate marked with the logo of Lawson Arms."
closet_appearance = /decl/closet_appearance/crate/secure/lawson closet_appearance = /decl/closet_appearance/crate/secure/lawson
/obj/structure/closet/crate/secure/morpheus
desc = "A secure crate crudely imprinted with 'MORPHEUS CYBERKINETICS'."
closet_appearance = /decl/closet_appearance/crate/secure/morpheus
/obj/structure/closet/crate/secure/nanotrasen
desc = "A secure crate emblazoned with the standard NanoTrasen livery."
closet_appearance = /decl/closet_appearance/crate/secure/nanotrasen
/obj/structure/closet/crate/secure/nanocare
desc = "A secure crate emblazoned with the NanoCare Medical livery, a subsidary of the NanoTrasen Corporation."
closet_appearance = /decl/closet_appearance/crate/secure/nanotrasenmedical
/obj/structure/closet/crate/secure/scg
name = "weapons crate"
desc = "A secure crate in the official colours of the Solar Confederate Government."
closet_appearance = /decl/closet_appearance/crate/secure/solgov
/obj/structure/closet/crate/secure/saare
name = "weapons crate"
desc = "A secure weapons crate plainly stamped with the logo of Stealth Assault Enterprises."
closet_appearance = /decl/closet_appearance/crate/secure/saare
/obj/structure/closet/crate/secure/veymed
desc = "A secure sterile crate extensively detailed in Veymed colours."
closet_appearance = /decl/closet_appearance/crate/secure/veymed
/obj/structure/closet/crate/secure/ward
desc = "A secure crate decaled with the logo of Ward-Takahashi."
closet_appearance = /decl/closet_appearance/crate/secure/ward
/obj/structure/closet/crate/secure/xion
desc = "A secure crate painted in Xion Manufacturing Group orange."
closet_appearance = /decl/closet_appearance/crate/secure/xion
/obj/structure/closet/crate/secure/zenghu
desc = "A secure sterile crate marked with the logo of Zeng-Hu Pharmaceuticals."
closet_appearance = /decl/closet_appearance/crate/secure/zenghu
/obj/structure/closet/crate/secure/phoron /obj/structure/closet/crate/secure/phoron
name = "phoron crate" name = "phoron crate"
desc = "A secure phoron crate." desc = "A secure phoron crate painted in standard NanoTrasen livery."
closet_appearance = /decl/closet_appearance/crate/secure/hazard closet_appearance = /decl/closet_appearance/crate/secure/hazard
/obj/structure/closet/crate/secure/gear /obj/structure/closet/crate/secure/gear
@@ -368,27 +556,24 @@
desc = "A secure gear crate." desc = "A secure gear crate."
closet_appearance = /decl/closet_appearance/crate/secure/weapon closet_appearance = /decl/closet_appearance/crate/secure/weapon
/obj/structure/closet/crate/secure/hydrosec /obj/structure/closet/crate/secure/hydrosec
name = "secure hydroponics crate" name = "secure hydroponics crate"
desc = "A crate with a lock on it, painted in the scheme of the station's botanists." desc = "A crate with a lock on it, painted in the scheme of the station's botanists."
closet_appearance = /decl/closet_appearance/crate/secure/hydroponics closet_appearance = /decl/closet_appearance/crate/secure/hydroponics
/obj/structure/closet/crate/secure/engineering /obj/structure/closet/crate/secure/engineering
desc = "A crate with a lock on it, painted in the scheme of the station's engineers." desc = "A crate with a lock on it, painted in the scheme of the station's engineers."
name = "secure engineering crate" name = "secure engineering crate"
/obj/structure/closet/crate/secure/science /obj/structure/closet/crate/secure/science
name = "secure science crate" name = "secure science crate"
desc = "A crate with a lock on it, painted in the scheme of the station's scientists." desc = "A crate with a lock on it, painted in the scheme of the station's scientists."
/obj/structure/closet/crate/secure/bin /obj/structure/closet/crate/secure/bin
name = "secure bin" name = "secure bin"
desc = "A secure bin." desc = "A secure bin."
// Large crates
/obj/structure/closet/crate/large /obj/structure/closet/crate/large
name = "large crate" name = "large crate"
@@ -414,6 +599,30 @@
break break
return return
/obj/structure/closet/crate/large/critter
name = "animal crate"
desc = "A hefty crate for hauling animals."
closet_appearance = /decl/closet_appearance/large_crate/critter
/obj/structure/closet/crate/large/aether
name = "large atmospherics crate"
desc = "A hefty metal crate, painted in Aether Atmospherics and Recycling colours."
closet_appearance = /decl/closet_appearance/large_crate/aether
/obj/structure/closet/crate/large/einstein
name = "large crate"
desc = "A hefty metal crate, painted in Einstein Engines colours."
closet_appearance = /decl/closet_appearance/large_crate/einstein
/obj/structure/closet/crate/large/nanotrasen
name = "large crate"
desc = "A hefty metal crate, painted in standard NanoTrasen livery."
closet_appearance = /decl/closet_appearance/large_crate/nanotrasen
/obj/structure/closet/crate/large/xion
name = "large crate"
desc = "A hefty metal crate, painted in Xion Manufacturing Group orange."
closet_appearance = /decl/closet_appearance/large_crate/xion
/obj/structure/closet/crate/secure/large /obj/structure/closet/crate/secure/large
name = "large crate" name = "large crate"
@@ -441,10 +650,30 @@
return return
//fluff variant
/obj/structure/closet/crate/secure/large/reinforced /obj/structure/closet/crate/secure/large/reinforced
desc = "A hefty, reinforced metal crate with an electronic locking system." desc = "A hefty, reinforced metal crate with an electronic locking system."
/obj/structure/closet/crate/secure/large/aether
name = "secure atmospherics crate"
desc = "A hefty metal crate with an electronic locking system, painted in Aether Atmospherics and Recycling colours."
closet_appearance = /decl/closet_appearance/large_crate/secure/aether
/obj/structure/closet/crate/secure/large/einstein
desc = "A hefty metal crate with an electronic locking system, painted in Einstein Engines colours."
closet_appearance = /decl/closet_appearance/large_crate/secure/einstein
/obj/structure/closet/crate/large/secure/heph
desc = "A hefty metal crate with an electronic locking system, marked with Hephaestus Industries colours."
closet_appearance = /decl/closet_appearance/large_crate/secure/heph
/obj/structure/closet/crate/secure/large/nanotrasen
desc = "A hefty metal crate with an electronic locking system, painted in standard NanoTrasen livery."
closet_appearance = /decl/closet_appearance/large_crate/secure/hazard
/obj/structure/closet/crate/large/secure/xion
desc = "A hefty metal crate with an electronic locking system, painted in Xion Manufacturing Group orange."
closet_appearance = /decl/closet_appearance/large_crate/secure/xion
/obj/structure/closet/crate/engineering /obj/structure/closet/crate/engineering
name = "engineering crate" name = "engineering crate"

View File

@@ -44,8 +44,8 @@
/obj/structure/largecrate/hoverpod /obj/structure/largecrate/hoverpod
name = "\improper Hoverpod assembly crate" name = "\improper Hoverpod assembly crate"
desc = "It comes in a box for the fabricator's sake. Where does the wood come from? ... And why is it lighter?" desc = "You aren't sure how this crate is so light, but the Wulf Aeronautics logo might be a hint."
icon_state = "mulecrate" icon_state = "vehiclecrate"
/obj/structure/largecrate/hoverpod/attackby(obj/item/weapon/W as obj, mob/user as mob) /obj/structure/largecrate/hoverpod/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_crowbar()) if(W.is_crowbar())
@@ -60,7 +60,7 @@
/obj/structure/largecrate/vehicle /obj/structure/largecrate/vehicle
name = "vehicle crate" name = "vehicle crate"
desc = "It comes in a box for the consumer's sake. ..How is this lighter?" desc = "Wulf Aeronautics says it comes in a box for the consumer's sake... How is this so light?"
icon_state = "vehiclecrate" icon_state = "vehiclecrate"
/obj/structure/largecrate/vehicle/Initialize() /obj/structure/largecrate/vehicle/Initialize()
@@ -74,18 +74,22 @@
/obj/structure/largecrate/vehicle/quadbike /obj/structure/largecrate/vehicle/quadbike
name = "\improper ATV crate" name = "\improper ATV crate"
desc = "A hefty wooden crate proudly displaying the logo of Ward-Takahashi's automotive division."
starts_with = list(/obj/structure/vehiclecage/quadbike) starts_with = list(/obj/structure/vehiclecage/quadbike)
/obj/structure/largecrate/vehicle/quadtrailer /obj/structure/largecrate/vehicle/quadtrailer
name = "\improper ATV trailer crate" name = "\improper ATV trailer crate"
desc = "A hefty wooden crate proudly displaying the logo of Ward-Takahashi's automotive division."
starts_with = list(/obj/structure/vehiclecage/quadtrailer) starts_with = list(/obj/structure/vehiclecage/quadtrailer)
/obj/structure/largecrate/animal /obj/structure/largecrate/animal
icon_state = "lisacrate" //VOREStation Edit icon_state = "crittercrate"
desc = "A hefty wooden crate with air holes. It is marked with the logo of NanoTrasen Pastures and the slogan, '90% less cloning defects* than competing brands**, or your money back***!'"
/obj/structure/largecrate/animal/mulebot /obj/structure/largecrate/animal/mulebot
name = "Mulebot crate" name = "Mulebot crate"
icon_state = "mulecrate" //VOREStation Edit desc = "A hefty wooden crate labelled 'Proud Product of the Xion Manufacturing Group'"
icon_state = "mulecrate"
starts_with = list(/mob/living/bot/mulebot) starts_with = list(/mob/living/bot/mulebot)
/obj/structure/largecrate/animal/corgi /obj/structure/largecrate/animal/corgi

View File

@@ -253,6 +253,10 @@
'sound/vore/sunesound/prey/death_07.ogg','sound/vore/sunesound/prey/death_08.ogg','sound/vore/sunesound/prey/death_09.ogg', 'sound/vore/sunesound/prey/death_07.ogg','sound/vore/sunesound/prey/death_08.ogg','sound/vore/sunesound/prey/death_09.ogg',
'sound/vore/sunesound/prey/death_10.ogg') 'sound/vore/sunesound/prey/death_10.ogg')
//END VORESTATION EDIT //END VORESTATION EDIT
if ("terminal_type")
soundin = pick('sound/machines/terminal_button01.ogg', 'sound/machines/terminal_button02.ogg', 'sound/machines/terminal_button03.ogg', \
'sound/machines/terminal_button04.ogg', 'sound/machines/terminal_button05.ogg', 'sound/machines/terminal_button06.ogg', \
'sound/machines/terminal_button07.ogg', 'sound/machines/terminal_button08.ogg')
return soundin return soundin
//Are these even used? //Are these even used?

View File

@@ -119,3 +119,11 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check
holder.disassociate() holder.disassociate()
//qdel(holder) //qdel(holder)
return 1 return 1
//This proc checks whether subject has at least ONE of the rights specified in rights_required.
/proc/check_rights_for(client/subject, rights_required)
if(subject && subject.holder)
if(rights_required && !(rights_required & subject.holder.rights))
return 0
return 1
return 0

View File

@@ -18,7 +18,6 @@
var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared. var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared.
var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source. var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source.
var/list/cameras //List of cameras that can be switched to, if the player has that capability. var/list/cameras //List of cameras that can be switched to, if the player has that capability.
var/cache_id //ID for camera cache, changed by invalidateCameraCache().
var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera). var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera).
var/area/last_name //The last acquired name, used should origin be lost var/area/last_name //The last acquired name, used should origin be lost
var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated. var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated.
@@ -78,15 +77,10 @@
return last_name return last_name
/datum/alarm/proc/cameras() /datum/alarm/proc/cameras()
// reset camera cache
if(camera_repository.camera_cache_id != cache_id)
cameras = null
cache_id = camera_repository.camera_cache_id
// If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras // If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras
else if(cameras && (last_camera_area != alarm_area())) if(cameras && (last_camera_area != alarm_area()))
cameras = null cameras = null
// The list of cameras is also reset by /proc/invalidateCameraCache()
if(!cameras) if(!cameras)
cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras() cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras()

View File

@@ -0,0 +1,110 @@
/*
Asset cache quick users guide:
Make a datum in asset_list_items.dm with your assets for your thing.
Checkout asset_list.dm for the helper subclasses
The simple subclass will most like be of use for most cases.
Then call get_asset_datum() with the type of the datum you created and store the return
Then call .send(client) on that stored return value.
Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE
*/
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
//This proc sends the asset to the client, but only if it needs it.
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset(client/client, asset_name)
return send_asset_list(client, list(asset_name))
/// Sends a list of assets to a client
/// This proc will no longer block, use client.asset_flush() if you to need know when the client has all assets (such as for output()). (This is not required for browse() calls as they use the same message queue as asset sends)
/// client - a client or mob
/// asset_list - A list of asset filenames to be sent to the client.
/// Returns TRUE if any assets were sent.
/proc/send_asset_list(client/client, list/asset_list)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return
else
return
var/list/unreceived = list()
for (var/asset_name in asset_list)
var/datum/asset_cache_item/asset = SSassets.cache[asset_name]
if (!asset)
continue
var/asset_file = asset.resource
if (!asset_file)
continue
var/asset_md5 = asset.md5
if (client.sent_assets[asset_name] == asset_md5)
continue
unreceived[asset_name] = asset_md5
if (unreceived.len)
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
to_chat(client, "Sending Resources...")
for(var/asset in unreceived)
var/datum/asset_cache_item/ACI
if ((ACI = SSassets.cache[asset]))
log_asset("Sending asset [asset] to client [client]")
client << browse_rsc(ACI.resource, asset)
client.sent_assets |= unreceived
addtimer(CALLBACK(client, /client/proc/asset_cache_update_json), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
return TRUE
return FALSE
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
//The proc calls procs that sleep for long times.
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE, filerate = 3)
var/startingfilerate = filerate
for(var/file in files)
if (!client)
break
if (register_asset)
register_asset(file, files[file])
if (send_asset(client, file))
if (!(--filerate))
filerate = startingfilerate
client.asset_flush()
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
//icons and virtual assets get copied to the dyn rsc before use
/proc/register_asset(asset_name, asset)
var/datum/asset_cache_item/ACI = new(asset_name, asset)
//this is technically never something that was supported and i want metrics on how often it happens if at all.
if (SSassets.cache[asset_name])
var/datum/asset_cache_item/OACI = SSassets.cache[asset_name]
if (OACI.md5 != ACI.md5)
stack_trace("ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]")
else
var/list/stacktrace = gib_stack_trace()
log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]")
SSassets.cache[asset_name] = ACI
return ACI
/// Returns the url of the asset, currently this is just its name, here to allow further work cdn'ing assets.
/// Can be given an asset as well, this is just a work around for buggy edge cases where two assets may have the same name, doesn't matter now, but it will when the cdn comes.
/proc/get_asset_url(asset_name, asset = null)
var/datum/asset_cache_item/ACI = SSassets.cache[asset_name]
return ACI?.url
//Generated names do not include file extention.
//Used mainly for code that deals with assets in a generic way
//The same asset will always lead to the same asset name
/proc/generate_asset_name(file)
return "asset.[md5(fcopy_rsc(file))]"

View File

@@ -0,0 +1,51 @@
/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]"
/client/proc/asset_cache_confirm_arrival(job_id)
var/asset_cache_job = round(text2num(job_id))
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit.
if (asset_cache_job > 0 && asset_cache_job <= last_asset_job && !(completed_asset_jobs["[asset_cache_job]"]))
completed_asset_jobs["[asset_cache_job]"] = TRUE
last_completed_asset_job = max(last_completed_asset_job, asset_cache_job)
else
return asset_cache_job || TRUE
/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING]
/client/proc/asset_cache_preload_data(data)
/*var/jsonend = findtextEx(data, "{{{ENDJSONDATA}}}")
if (!jsonend)
CRASH("invalid asset_cache_preload_data, no jsonendmarker")*/
//var/json = html_decode(copytext(data, 1, jsonend))
var/json = data
var/list/preloaded_assets = json_decode(json)
for (var/preloaded_asset in preloaded_assets)
if (copytext(preloaded_asset, findlasttext(preloaded_asset, ".")+1) in list("js", "jsm", "htm", "html"))
preloaded_assets -= preloaded_asset
continue
sent_assets |= preloaded_assets
/// Updates the client side stored html/json combo file used to keep track of what assets the client has between restarts/reconnects.
/client/proc/asset_cache_update_json(verify = FALSE, list/new_assets = list())
if (world.time - connection_time < 10 SECONDS) //don't override the existing data file on a new connection
return
if (!islist(new_assets))
new_assets = list("[new_assets]" = md5(SSassets.cache[new_assets]))
src << browse(json_encode(new_assets|sent_assets), "file=asset_data.json&display=0")
/// Blocks until all currently sending browser assets have been sent.
/// Due to byond limitations, this proc will sleep for 1 client round trip even if the client has no pending asset sends.
/// This proc will return an untrue value if it had to return before confirming the send, such as timeout or the client going away.
/client/proc/asset_flush(timeout = 50)
var/job = ++last_asset_job
var/t = 0
var/timeout_time = timeout
src << browse({"<script>window.location.href="?asset_cache_confirm_arrival=[job]"</script>"}, "window=asset_cache_browser&file=asset_cache_send_verify.htm")
while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic()
stoplag(1) // Lock up the caller until this is received.
t++
if (t < timeout_time)
return TRUE

View File

@@ -0,0 +1,23 @@
/**
* # asset_cache_item
*
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
**/
/datum/asset_cache_item
var/name
var/url
var/md5
var/resource
/datum/asset_cache_item/New(name, file)
if (!isfile(file))
file = fcopy_rsc(file)
md5 = md5(file)
if (!md5)
md5 = md5(fcopy_rsc(file))
if (!md5)
CRASH("invalid asset sent to asset cache")
log_world("asset cache unexpected success of second fcopy_rsc")
src.name = name
url = name
resource = file

View File

@@ -0,0 +1,260 @@
//These datums are used to populate the asset cache, the proc "register()" does this.
//Place any asset datums you create in asset_list_items.dm
//all of our asset datums, used for referring to these later
GLOBAL_LIST_EMPTY(asset_datums)
//get an assetdatum or make a new one
/proc/get_asset_datum(type)
return GLOB.asset_datums[type] || new type()
/datum/asset
var/_abstract = /datum/asset
/datum/asset/New()
GLOB.asset_datums[type] = src
register()
/datum/asset/proc/get_url_mappings()
return list()
/datum/asset/proc/register()
return
/datum/asset/proc/send(client)
return
//If you don't need anything complicated.
/datum/asset/simple
_abstract = /datum/asset/simple
var/assets = list()
/datum/asset/simple/register()
for(var/asset_name in assets)
assets[asset_name] = register_asset(asset_name, assets[asset_name])
/datum/asset/simple/send(client)
. = send_asset_list(client, assets)
/datum/asset/simple/get_url_mappings()
. = list()
for (var/asset_name in assets)
var/datum/asset_cache_item/ACI = assets[asset_name]
if (!ACI)
continue
.[asset_name] = ACI.url
// For registering or sending multiple others at once
/datum/asset/group
_abstract = /datum/asset/group
var/list/children
/datum/asset/group/register()
for(var/type in children)
get_asset_datum(type)
/datum/asset/group/send(client/C)
for(var/type in children)
var/datum/asset/A = get_asset_datum(type)
. = A.send(C) || .
/datum/asset/group/get_url_mappings()
. = list()
for(var/type in children)
var/datum/asset/A = get_asset_datum(type)
. += A.get_url_mappings()
// spritesheet implementation - coalesces various icons into a single .png file
// and uses CSS to select icons out of that file - saves on transferring some
// 1400-odd individual PNG files
#define SPR_SIZE 1
#define SPR_IDX 2
#define SPRSZ_COUNT 1
#define SPRSZ_ICON 2
#define SPRSZ_STRIPPED 3
/datum/asset/spritesheet
_abstract = /datum/asset/spritesheet
var/name
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
/datum/asset/spritesheet/register()
if (!name)
CRASH("spritesheet [type] cannot register without a name")
ensure_stripped()
for(var/size_id in sizes)
var/size = sizes[size_id]
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
var/res_name = "spritesheet_[name].css"
var/fname = "data/spritesheets/[res_name]"
fdel(fname)
text2file(generate_css(), fname)
register_asset(res_name, fcopy_rsc(fname))
fdel(fname)
/datum/asset/spritesheet/send(client/C)
if (!name)
return
var/all = list("spritesheet_[name].css")
for(var/size_id in sizes)
all += "[name]_[size_id].png"
. = send_asset_list(C, all)
/datum/asset/spritesheet/get_url_mappings()
if (!name)
return
. = list("spritesheet_[name].css" = get_asset_url("spritesheet_[name].css"))
for(var/size_id in sizes)
.["[name]_[size_id].png"] = get_asset_url("[name]_[size_id].png")
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
for(var/size_id in sizes_to_strip)
var/size = sizes[size_id]
if (size[SPRSZ_STRIPPED])
continue
#ifdef RUST_G
// save flattened version
var/fname = "data/spritesheets/[name]_[size_id].png"
fcopy(size[SPRSZ_ICON], fname)
var/error = call(RUST_G, "dmi_strip_metadata")(fname)
if(length(error))
stack_trace("Failed to strip [name]_[size_id].png: [error]")
size[SPRSZ_STRIPPED] = icon(fname)
fdel(fname)
#else
#warn It looks like you don't have RUST_G enabled. Without RUST_G, the RPD icons will not function, so it strongly recommended you reenable it.
#endif
/datum/asset/spritesheet/proc/generate_css()
var/list/out = list()
for (var/size_id in sizes)
var/size = sizes[size_id]
var/icon/tiny = size[SPRSZ_ICON]
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[get_asset_url("[name]_[size_id].png")]') no-repeat;}"
for (var/sprite_id in sprites)
var/sprite = sprites[sprite_id]
var/size_id = sprite[SPR_SIZE]
var/idx = sprite[SPR_IDX]
var/size = sizes[size_id]
var/icon/tiny = size[SPRSZ_ICON]
var/icon/big = size[SPRSZ_STRIPPED]
var/per_line = big.Width() / tiny.Width()
var/x = (idx % per_line) * tiny.Width()
var/y = round(idx / per_line) * tiny.Height()
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
return out.Join("\n")
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
return
var/size_id = "[I.Width()]x[I.Height()]"
var/size = sizes[size_id]
if (sprites[sprite_name])
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
if (size)
var/position = size[SPRSZ_COUNT]++
var/icon/sheet = size[SPRSZ_ICON]
size[SPRSZ_STRIPPED] = null
sheet.Insert(I, icon_state=sprite_name)
sprites[sprite_name] = list(size_id, position)
else
sizes[size_id] = size = list(1, I, null)
sprites[sprite_name] = list(size_id, 0)
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
if (length(prefix))
prefix = "[prefix]-"
if (!directions)
directions = list(SOUTH)
for (var/icon_state_name in icon_states(I))
for (var/direction in directions)
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
/datum/asset/spritesheet/proc/css_tag()
return {"<link rel="stylesheet" href="[css_filename()]" />"}
/datum/asset/spritesheet/proc/css_filename()
return get_asset_url("spritesheet_[name].css")
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
var/sprite = sprites[sprite_name]
if (!sprite)
return null
var/size_id = sprite[SPR_SIZE]
return {"<span class="[name][size_id] [sprite_name]"></span>"}
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
var/sprite = sprites[sprite_name]
if (!sprite)
return null
var/size_id = sprite[SPR_SIZE]
return {"[name][size_id] [sprite_name]"}
#undef SPR_SIZE
#undef SPR_IDX
#undef SPRSZ_COUNT
#undef SPRSZ_ICON
#undef SPRSZ_STRIPPED
/datum/asset/spritesheet/simple
_abstract = /datum/asset/spritesheet/simple
var/list/assets
/datum/asset/spritesheet/simple/register()
for (var/key in assets)
Insert(key, assets[key])
..()
//Generates assets based on iconstates of a single icon
/datum/asset/simple/icon_states
_abstract = /datum/asset/simple/icon_states
var/icon
var/list/directions = list(SOUTH)
var/frame = 1
var/movement_states = FALSE
var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
/datum/asset/simple/icon_states/register(_icon = icon)
for(var/icon_state_name in icon_states(_icon))
for(var/direction in directions)
var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
if (!asset)
continue
asset = fcopy_rsc(asset) //dedupe
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
if (generic_icon_names)
asset_name = "[generate_asset_name(asset)].png"
register_asset(asset_name, asset)
/datum/asset/simple/icon_states/multiple_icons
_abstract = /datum/asset/simple/icon_states/multiple_icons
var/list/icons
/datum/asset/simple/icon_states/multiple_icons/register()
for(var/i in icons)
..(i)

View File

@@ -0,0 +1,445 @@
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/tgui
assets = list(
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
)
// /datum/asset/simple/headers
// assets = list(
// "alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
// "alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
// "batt_5.gif" = 'icons/program_icons/batt_5.gif',
// "batt_20.gif" = 'icons/program_icons/batt_20.gif',
// "batt_40.gif" = 'icons/program_icons/batt_40.gif',
// "batt_60.gif" = 'icons/program_icons/batt_60.gif',
// "batt_80.gif" = 'icons/program_icons/batt_80.gif',
// "batt_100.gif" = 'icons/program_icons/batt_100.gif',
// "charging.gif" = 'icons/program_icons/charging.gif',
// "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
// "downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
// "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
// "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
// "power_norm.gif" = 'icons/program_icons/power_norm.gif',
// "power_warn.gif" = 'icons/program_icons/power_warn.gif',
// "sig_high.gif" = 'icons/program_icons/sig_high.gif',
// "sig_low.gif" = 'icons/program_icons/sig_low.gif',
// "sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
// "sig_none.gif" = 'icons/program_icons/sig_none.gif',
// "smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
// "smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
// "smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
// "smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
// "smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
// "smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
// "smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
// "borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
// )
// /datum/asset/simple/radar_assets
// assets = list(
// "ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png',
// "ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png',
// "ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png'
// )
// /datum/asset/spritesheet/simple/pda
// name = "pda"
// assets = list(
// "atmos" = 'icons/pda_icons/pda_atmos.png',
// "back" = 'icons/pda_icons/pda_back.png',
// "bell" = 'icons/pda_icons/pda_bell.png',
// "blank" = 'icons/pda_icons/pda_blank.png',
// "boom" = 'icons/pda_icons/pda_boom.png',
// "bucket" = 'icons/pda_icons/pda_bucket.png',
// "medbot" = 'icons/pda_icons/pda_medbot.png',
// "floorbot" = 'icons/pda_icons/pda_floorbot.png',
// "cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
// "crate" = 'icons/pda_icons/pda_crate.png',
// "cuffs" = 'icons/pda_icons/pda_cuffs.png',
// "eject" = 'icons/pda_icons/pda_eject.png',
// "flashlight" = 'icons/pda_icons/pda_flashlight.png',
// "honk" = 'icons/pda_icons/pda_honk.png',
// "mail" = 'icons/pda_icons/pda_mail.png',
// "medical" = 'icons/pda_icons/pda_medical.png',
// "menu" = 'icons/pda_icons/pda_menu.png',
// "mule" = 'icons/pda_icons/pda_mule.png',
// "notes" = 'icons/pda_icons/pda_notes.png',
// "power" = 'icons/pda_icons/pda_power.png',
// "rdoor" = 'icons/pda_icons/pda_rdoor.png',
// "reagent" = 'icons/pda_icons/pda_reagent.png',
// "refresh" = 'icons/pda_icons/pda_refresh.png',
// "scanner" = 'icons/pda_icons/pda_scanner.png',
// "signaler" = 'icons/pda_icons/pda_signaler.png',
// "skills" = 'icons/pda_icons/pda_skills.png',
// "status" = 'icons/pda_icons/pda_status.png',
// "dronephone" = 'icons/pda_icons/pda_dronephone.png',
// "emoji" = 'icons/pda_icons/pda_emoji.png'
// )
// /datum/asset/spritesheet/simple/paper
// name = "paper"
// assets = list(
// "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
// "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
// "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
// "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
// "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
// "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
// "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
// "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
// "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
// "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
// "stamp-law" = 'icons/stamp_icons/large_stamp-law.png',
// "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png',
// "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png',
// "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png',
// "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png'
// )
// /datum/asset/simple/irv
// assets = list(
// "jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
// )
// /datum/asset/group/irv
// children = list(
// /datum/asset/simple/jquery,
// /datum/asset/simple/irv
// )
/datum/asset/simple/generic
assets = list(
"search.js" = 'html/search.js',
"panels.css" = 'html/panels.css',
"loading.gif" = 'html/images/loading.gif',
"ntlogo.png" = 'html/images/ntlogo.png',
"sglogo.png" = 'html/images/sglogo.png',
"talisman.png" = 'html/images/talisman.png',
"paper_bg.png" = 'html/images/paper_bg.png',
"no_image32.png" = 'html/images/no_image32.png',
)
/datum/asset/simple/changelog
assets = list(
"88x31.png" = 'html/88x31.png',
"bug-minus.png" = 'html/bug-minus.png',
"cross-circle.png" = 'html/cross-circle.png',
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
"image-minus.png" = 'html/image-minus.png',
"image-plus.png" = 'html/image-plus.png',
"map-pencil.png" = 'html/map-pencil.png',
"music-minus.png" = 'html/music-minus.png',
"music-plus.png" = 'html/music-plus.png',
"tick-circle.png" = 'html/tick-circle.png',
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
"spell-check.png" = 'html/spell-check.png',
"burn-exclamation.png" = 'html/burn-exclamation.png',
"chevron.png" = 'html/chevron.png',
"chevron-expand.png" = 'html/chevron-expand.png',
"changelog.css" = 'html/changelog.css',
"changelog.js" = 'html/changelog.js',
"changelog.html" = 'html/changelog.html'
)
// /datum/asset/group/goonchat
// children = list(
// /datum/asset/simple/jquery,
// /datum/asset/simple/goonchat,
// /datum/asset/spritesheet/goonchat,
// /datum/asset/simple/fontawesome
// )
// /datum/asset/simple/jquery
// assets = list(
// "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
// )
// /datum/asset/simple/goonchat
// assets = list(
// "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
// "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
// "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
// "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css',
// )
/datum/asset/simple/fontawesome
assets = list(
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
)
// /datum/asset/spritesheet/goonchat
// name = "chat"
// /datum/asset/spritesheet/goonchat/register()
// InsertAll("emoji", 'icons/emoji.dmi')
// // pre-loading all lanugage icons also helps to avoid meta
// InsertAll("language", 'icons/misc/language.dmi')
// // catch languages which are pulling icons from another file
// for(var/path in typesof(/datum/language))
// var/datum/language/L = path
// var/icon = initial(L.icon)
// if (icon != 'icons/misc/language.dmi')
// var/icon_state = initial(L.icon_state)
// Insert("language-[icon_state]", icon, icon_state=icon_state)
// ..()
// /datum/asset/simple/permissions
// assets = list(
// "padlock.png" = 'html/padlock.png'
// )
// /datum/asset/simple/notes
// assets = list(
// "high_button.png" = 'html/high_button.png',
// "medium_button.png" = 'html/medium_button.png',
// "minor_button.png" = 'html/minor_button.png',
// "none_button.png" = 'html/none_button.png',
// )
// /datum/asset/simple/arcade
// assets = list(
// "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
// "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
// "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
// "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
// "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
// "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
// )
// /datum/asset/spritesheet/simple/achievements
// name ="achievements"
// assets = list(
// "default" = 'icons/UI_Icons/Achievements/default.png',
// "basemisc" = 'icons/UI_Icons/Achievements/basemisc.png',
// "baseboss" = 'icons/UI_Icons/Achievements/baseboss.png',
// "baseskill" = 'icons/UI_Icons/Achievements/baseskill.png',
// "bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png',
// "colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png',
// "hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png',
// "legion" = 'icons/UI_Icons/Achievements/Boss/legion.png',
// "miner" = 'icons/UI_Icons/Achievements/Boss/miner.png',
// "swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png',
// "tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png',
// "featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png',
// "helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png',
// "jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png',
// "meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png',
// "timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png',
// "upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png',
// "clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png',
// "clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png',
// "rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
// "snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
// "mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
// )
// /datum/asset/spritesheet/simple/pills
// name ="pills"
// assets = list(
// "pill1" = 'icons/UI_Icons/Pills/pill1.png',
// "pill2" = 'icons/UI_Icons/Pills/pill2.png',
// "pill3" = 'icons/UI_Icons/Pills/pill3.png',
// "pill4" = 'icons/UI_Icons/Pills/pill4.png',
// "pill5" = 'icons/UI_Icons/Pills/pill5.png',
// "pill6" = 'icons/UI_Icons/Pills/pill6.png',
// "pill7" = 'icons/UI_Icons/Pills/pill7.png',
// "pill8" = 'icons/UI_Icons/Pills/pill8.png',
// "pill9" = 'icons/UI_Icons/Pills/pill9.png',
// "pill10" = 'icons/UI_Icons/Pills/pill10.png',
// "pill11" = 'icons/UI_Icons/Pills/pill11.png',
// "pill12" = 'icons/UI_Icons/Pills/pill12.png',
// "pill13" = 'icons/UI_Icons/Pills/pill13.png',
// "pill14" = 'icons/UI_Icons/Pills/pill14.png',
// "pill15" = 'icons/UI_Icons/Pills/pill15.png',
// "pill16" = 'icons/UI_Icons/Pills/pill16.png',
// "pill17" = 'icons/UI_Icons/Pills/pill17.png',
// "pill18" = 'icons/UI_Icons/Pills/pill18.png',
// "pill19" = 'icons/UI_Icons/Pills/pill19.png',
// "pill20" = 'icons/UI_Icons/Pills/pill20.png',
// "pill21" = 'icons/UI_Icons/Pills/pill21.png',
// "pill22" = 'icons/UI_Icons/Pills/pill22.png',
// )
// //this exists purely to avoid meta by pre-loading all language icons.
// /datum/asset/language/register()
// for(var/path in typesof(/datum/language))
// set waitfor = FALSE
// var/datum/language/L = new path ()
// L.get_icon()
/datum/asset/spritesheet/pipes
name = "pipes"
/datum/asset/spritesheet/pipes/register()
for(var/each in list('icons/obj/pipe-item.dmi', 'icons/obj/pipes/disposal.dmi'))
InsertAll("", each, global.alldirs)
..()
// // Representative icons for each research design
// /datum/asset/spritesheet/research_designs
// name = "design"
// /datum/asset/spritesheet/research_designs/register()
// for (var/path in subtypesof(/datum/design))
// var/datum/design/D = path
// var/icon_file
// var/icon_state
// var/icon/I
// if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest
// icon_file = initial(D.research_icon)
// icon_state = initial(D.research_icon_state)
// if(!(icon_state in icon_states(icon_file)))
// warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
// continue
// I = icon(icon_file, icon_state, SOUTH)
// else
// // construct the icon and slap it into the resource cache
// var/atom/item = initial(D.build_path)
// if (!ispath(item, /atom))
// // biogenerator outputs to beakers by default
// if (initial(D.build_type) & BIOGENERATOR)
// item = /obj/item/reagent_containers/glass/beaker/large
// else
// continue // shouldn't happen, but just in case
// // circuit boards become their resulting machines or computers
// if (ispath(item, /obj/item/circuitboard))
// var/obj/item/circuitboard/C = item
// var/machine = initial(C.build_path)
// if (machine)
// item = machine
// icon_file = initial(item.icon)
// icon_state = initial(item.icon_state)
// if(!(icon_state in icon_states(icon_file)))
// warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
// continue
// I = icon(icon_file, icon_state, SOUTH)
// // computers (and snowflakes) get their screen and keyboard sprites
// if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
// var/obj/machinery/computer/C = item
// var/screen = initial(C.icon_screen)
// var/keyboard = initial(C.icon_keyboard)
// var/all_states = icon_states(icon_file)
// if (screen && (screen in all_states))
// I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
// if (keyboard && (keyboard in all_states))
// I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
// Insert(initial(D.id), I)
// return ..()
// /datum/asset/spritesheet/vending
// name = "vending"
// /datum/asset/spritesheet/vending/register()
// for (var/k in GLOB.vending_products)
// var/atom/item = k
// if (!ispath(item, /atom))
// continue
// var/icon_file = initial(item.icon)
// var/icon_state = initial(item.icon_state)
// var/icon/I
// var/icon_states_list = icon_states(icon_file)
// if(icon_state in icon_states_list)
// I = icon(icon_file, icon_state, SOUTH)
// var/c = initial(item.color)
// if (!isnull(c) && c != "#FFFFFF")
// I.Blend(c, ICON_MULTIPLY)
// else
// var/icon_states_string
// for (var/an_icon_state in icon_states_list)
// if (!icon_states_string)
// icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
// else
// icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
// stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
// I = icon('icons/turf/floors.dmi', "", SOUTH)
// var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
// Insert(imgid, I)
// return ..()
// /datum/asset/simple/genetics
// assets = list(
// "dna_discovered.gif" = 'html/dna_discovered.gif',
// "dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
// "dna_extra.gif" = 'html/dna_extra.gif'
// )
// /datum/asset/simple/orbit
// assets = list(
// "ghost.png" = 'html/ghost.png'
// )
// /datum/asset/simple/vv
// assets = list(
// "view_variables.css" = 'html/admin/view_variables.css'
// )
// /datum/asset/spritesheet/sheetmaterials
// name = "sheetmaterials"
// /datum/asset/spritesheet/sheetmaterials/register()
// InsertAll("", 'icons/obj/stack_objects.dmi')
// // Special case to handle Bluespace Crystals
// Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
// ..()
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/images/",
"nano/images/modular_computers/",
"nano/js/"
)
var/list/template_dirs = list(
"nano/templates/"
)
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for(var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
register_asset(filename, common[filename])
// Combine all templates into a single bundle.
var/list/template_data = list()
for(var/path in template_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename) - 4) == ".tmpl") // Ignore directories.
template_data[filename] = file2text(path + filename)
var/template_bundle = "function nanouiTemplateBundle(){return [json_encode(template_data)];}"
var/fname = "data/nano_templates_bundle.js"
fdel(fname)
text2file(template_bundle, fname)
register_asset("nano_templates_bundle.js", fcopy_rsc(fname))
fdel(fname)
/datum/asset/nanoui/send(client)
send_asset_list(client, common)

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>
<body>
<script>
//this is used over window.location because window.location has a character limit in IE.
function sendbyond(text) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '?'+text, true);
xhr.send(null);
}
var xhr = new XMLHttpRequest();
xhr.open('GET', 'asset_data.json', true);
xhr.responseType = 'text';
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var status = xhr.status;
if (status >= 200 && status < 400) {
sendbyond('asset_cache_preload_data=' + encodeURIComponent(xhr.responseText));
}
}
};
xhr.send(null);
</script>
</body>
</html>

View File

@@ -1,309 +0,0 @@
/*
Asset cache quick users guide:
Make a datum at the bottom of this file with your assets for your thing.
The simple subsystem will most like be of use for most cases.
Then call get_asset_datum() with the type of the datum you created and store the return
Then call .send(client) on that stored return value.
You can set verify to TRUE if you want send() to sleep until the client has the assets.
*/
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
// This is doubled for the first asset, then added per asset after
#define ASSET_CACHE_SEND_TIMEOUT 7
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
#define ASSET_CACHE_PRELOAD_CONCURRENT 3
/client
var/list/cache = list() // List of all assets sent to this client by the asset cache.
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
var/list/sending = list()
var/last_asset_job = 0 // Last job done.
//This proc sends the asset to the client, but only if it needs it.
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
client = CLIENT_FROM_VAR(client) // Will get client from a mob, or accept a client, or return null
if(!istype(client))
return 0
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
return 0
client << browse_rsc(SSassets.cache[asset_name], asset_name)
if(!verify) // Can't access the asset cache browser, rip.
client.cache += asset_name
return 1
client.sending |= asset_name
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= asset_name
client.cache |= asset_name
client.completed_asset_jobs -= job
return 1
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
client = CLIENT_FROM_VAR(client) // Will get client from a mob, or accept a client, or return null
if(!istype(client))
return 0
var/list/unreceived = asset_list - (client.cache + client.sending)
if(!unreceived || !unreceived.len)
return 0
if(unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
to_chat(client, "Sending Resources...")
for(var/asset in unreceived)
if(asset in SSassets.cache)
client << browse_rsc(SSassets.cache[asset], asset)
if(!verify) // Can't access the asset cache browser, rip.
client.cache += unreceived
return 1
client.sending |= unreceived
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= unreceived
client.cache |= unreceived
client.completed_asset_jobs -= job
return 1
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
//The proc calls procs that sleep for long times.
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
var/concurrent_tracker = 1
for(var/file in files)
if(!client)
break
if(register_asset)
register_asset(file, files[file])
if(concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
concurrent_tracker = 1
send_asset(client, file)
else
concurrent_tracker++
send_asset(client, file, verify = FALSE)
sleep(0) //queuing calls like this too quickly can cause issues in some client versions
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
//if it's an icon or something be careful, you'll have to copy it before further use.
/proc/register_asset(var/asset_name, var/asset)
SSassets.cache[asset_name] = asset
//These datums are used to populate the asset cache, the proc "register()" does this.
//all of our asset datums, used for referring to these later
/var/global/list/asset_datums = list()
//get a assetdatum or make a new one
/proc/get_asset_datum(var/type)
if(!(type in asset_datums))
return new type()
return asset_datums[type]
/datum/asset
var/_abstract = /datum/asset // Marker so we don't instanatiate abstract types
/datum/asset/New()
asset_datums[type] = src
register()
/datum/asset/proc/register()
return
/datum/asset/proc/send(client)
return
//If you don't need anything complicated.
/datum/asset/simple
_abstract = /datum/asset/simple
var/assets = list()
var/verify = FALSE
/datum/asset/simple/register()
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
/datum/asset/simple/send(client)
send_asset_list(client,assets,verify)
//
// iconsheet Assets - For making lots of icon states available at once without sending a thousand tiny files.
//
/datum/asset/iconsheet
_abstract = /datum/asset/iconsheet
var/name // Name of the iconsheet. Asset will be named after this.
var/verify = FALSE
/datum/asset/iconsheet/register(var/list/sprites)
if (!name)
CRASH("iconsheet [type] cannot register without a name")
if (!islist(sprites))
CRASH("iconsheet [type] cannot register without a sprites list")
var/res_name = "iconsheet_[name].css"
var/fname = "data/iconsheets/[res_name]"
fdel(fname)
text2file(generate_css(sprites), fname)
register_asset(res_name, fcopy_rsc(fname))
fdel(fname)
/datum/asset/iconsheet/send(client/C)
if (!name)
return
send_asset_list(C, list("iconsheet_[name].css"), verify)
/datum/asset/iconsheet/proc/generate_css(var/list/sprites)
var/list/out = list(".[name]{display:inline-block;}")
for(var/sprite_id in sprites)
var/icon/I = sprites[sprite_id]
var/data_url = "'data:image/png;base64,[icon2base64(I)]'"
out += ".[name].[sprite_id]{width:[I.Width()]px;height:[I.Height()]px;background-image:url([data_url]);}"
return out.Join("\n")
/datum/asset/iconsheet/proc/build_sprite_list(icon/I, list/directions, prefix = null)
if (length(prefix))
prefix = "[prefix]-"
if (!directions)
directions = list(SOUTH)
var/sprites = list()
for (var/icon_state_name in cached_icon_states(I))
for (var/direction in directions)
var/suffix = (directions.len > 1) ? "-[dir2text(direction)]" : ""
var/sprite_name = "[prefix][icon_state_name][suffix]"
var/icon/sprite = icon(I, icon_state=icon_state_name, dir=direction, frame=1, moving=FALSE)
if (!sprite || !length(cached_icon_states(sprite))) // that direction or state doesn't exist
continue
sprites[sprite_name] = sprite
return sprites
// Get HTML link tag for including the iconsheet css file.
/datum/asset/iconsheet/proc/css_tag()
return "<link rel='stylesheet' href='iconsheet_[name].css' />"
// get HTML tag for showing an icon
/datum/asset/iconsheet/proc/icon_tag(icon_state, dir = SOUTH)
return "<span class='[name] [icon_state]-[dir2text(dir)]'></span>"
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/generic
assets = list(
"search.js" = 'html/search.js',
"panels.css" = 'html/panels.css',
"loading.gif" = 'html/images/loading.gif',
"ntlogo.png" = 'html/images/ntlogo.png',
"sglogo.png" = 'html/images/sglogo.png',
"talisman.png" = 'html/images/talisman.png',
"paper_bg.png" = 'html/images/paper_bg.png',
"no_image32.png" = 'html/images/no_image32.png',
)
/datum/asset/simple/changelog
assets = list(
"88x31.png" = 'html/88x31.png',
"bug-minus.png" = 'html/bug-minus.png',
"cross-circle.png" = 'html/cross-circle.png',
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
"image-minus.png" = 'html/image-minus.png',
"image-plus.png" = 'html/image-plus.png',
"map-pencil.png" = 'html/map-pencil.png',
"music-minus.png" = 'html/music-minus.png',
"music-plus.png" = 'html/music-plus.png',
"tick-circle.png" = 'html/tick-circle.png',
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
"spell-check.png" = 'html/spell-check.png',
"burn-exclamation.png" = 'html/burn-exclamation.png',
"chevron.png" = 'html/chevron.png',
"chevron-expand.png" = 'html/chevron-expand.png',
"changelog.css" = 'html/changelog.css',
"changelog.js" = 'html/changelog.js',
"changelog.html" = 'html/changelog.html'
)
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/images/",
"nano/images/modular_computers/",
"nano/js/"
)
var/list/template_dirs = list(
"nano/templates/"
)
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for(var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
register_asset(filename, common[filename])
// Combine all templates into a single bundle.
var/list/template_data = list()
for(var/path in template_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename) - 4) == ".tmpl") // Ignore directories.
template_data[filename] = file2text(path + filename)
var/template_bundle = "function nanouiTemplateBundle(){return [json_encode(template_data)];}"
var/fname = "data/nano_templates_bundle.js"
fdel(fname)
text2file(template_bundle, fname)
register_asset("nano_templates_bundle.js", fcopy_rsc(fname))
fdel(fname)
/datum/asset/nanoui/send(client)
send_asset_list(client, common)
// VOREStation Add Start - pipes iconsheet asset
/datum/asset/iconsheet/pipes
name = "pipes"
/datum/asset/iconsheet/pipes/register()
var/list/sprites = list()
for (var/each in list('icons/obj/pipe-item.dmi', 'icons/obj/pipes/disposal.dmi'))
sprites += build_sprite_list(each, global.alldirs)
..(sprites)
// VOREStation Add End

View File

@@ -59,3 +59,18 @@
preload_rsc = PRELOAD_RSC preload_rsc = PRELOAD_RSC
var/global/obj/screen/click_catcher/void var/global/obj/screen/click_catcher/void
// List of all asset filenames sent to this client by the asset cache, along with their assoicated md5s
var/list/sent_assets = list()
/// List of all completed blocking send jobs awaiting acknowledgement by send_asset
var/list/completed_asset_jobs = list()
/// Last asset send job id.
var/last_asset_job = 0
var/last_completed_asset_job = 0
///world.time they connected
var/connection_time
///world.realtime they connected
var/connection_realtime
///world.timeofday they connected
var/connection_timeofday

View File

@@ -34,9 +34,11 @@
#endif #endif
// asset_cache
var/asset_cache_job
if(href_list["asset_cache_confirm_arrival"]) if(href_list["asset_cache_confirm_arrival"])
var/job = text2num(href_list["asset_cache_confirm_arrival"]) asset_cache_job = asset_cache_confirm_arrival(href_list["asset_cache_confirm_arrival"])
completed_asset_jobs += job if (!asset_cache_job)
return return
//search the href for script injection //search the href for script injection
@@ -46,6 +48,10 @@
//del(usr) //del(usr)
return return
// Tgui Topic middleware
if(!tgui_Topic(href_list))
return
//Admin PM //Admin PM
if(href_list["priv_msg"]) if(href_list["priv_msg"])
var/client/C = locate(href_list["priv_msg"]) var/client/C = locate(href_list["priv_msg"])
@@ -106,6 +112,15 @@
if(config && config.log_hrefs && href_logfile) if(config && config.log_hrefs && href_logfile)
WRITE_LOG(href_logfile, "[src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]") WRITE_LOG(href_logfile, "[src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]")
//byond bug ID:2256651
if (asset_cache_job && (asset_cache_job in completed_asset_jobs))
to_chat(src, "<span class='danger'>An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)</span>")
src << browse("...", "window=asset_cache_browser")
return
if (href_list["asset_cache_preload_data"])
asset_cache_preload_data(href_list["asset_cache_preload_data"])
return
switch(href_list["_src_"]) switch(href_list["_src_"])
if("holder") hsrc = holder if("holder") hsrc = holder
if("usr") hsrc = mob if("usr") hsrc = mob
@@ -181,6 +196,10 @@
. = ..() //calls mob.Login() . = ..() //calls mob.Login()
prefs.sanitize_preferences() prefs.sanitize_preferences()
connection_time = world.time
connection_realtime = world.realtime
connection_timeofday = world.timeofday
if(custom_event_msg && custom_event_msg != "") if(custom_event_msg && custom_event_msg != "")
to_chat(src, "<h1 class='alert'>Custom Event</h1>") to_chat(src, "<h1 class='alert'>Custom Event</h1>")
to_chat(src, "<h2 class='alert'>A custom event is taking place. OOC Info:</h2>") to_chat(src, "<h2 class='alert'>A custom event is taking place. OOC Info:</h2>")
@@ -408,8 +427,12 @@
//send resources to the client. It's here in its own proc so we can move it around easiliy if need be //send resources to the client. It's here in its own proc so we can move it around easiliy if need be
/client/proc/send_resources() /client/proc/send_resources()
spawn (10) //removing this spawn causes all clients to not get verbs. spawn (10) //removing this spawn causes all clients to not get verbs.
//load info on what assets the client has
src << browse('code/modules/asset_cache/validate_assets.html', "window=asset_cache_browser")
//Precache the client with all other assets slowly, so as to not block other browse() calls //Precache the client with all other assets slowly, so as to not block other browse() calls
getFilesSlow(src, SSassets.preload, register_asset = FALSE) addtimer(CALLBACK(GLOBAL_PROC, /proc/getFilesSlow, src, SSassets.preload, FALSE), 5 SECONDS)
mob/proc/MayRespawn() mob/proc/MayRespawn()
return 0 return 0

View File

@@ -9,6 +9,8 @@
S["ooccolor"] >> pref.ooccolor S["ooccolor"] >> pref.ooccolor
S["tooltipstyle"] >> pref.tooltipstyle S["tooltipstyle"] >> pref.tooltipstyle
S["client_fps"] >> pref.client_fps S["client_fps"] >> pref.client_fps
S["tgui_fancy"] >> pref.tgui_fancy
S["tgui_lock"] >> pref.tgui_lock
/datum/category_item/player_setup_item/player_global/ui/save_preferences(var/savefile/S) /datum/category_item/player_setup_item/player_global/ui/save_preferences(var/savefile/S)
S["UI_style"] << pref.UI_style S["UI_style"] << pref.UI_style
@@ -17,6 +19,8 @@
S["ooccolor"] << pref.ooccolor S["ooccolor"] << pref.ooccolor
S["tooltipstyle"] << pref.tooltipstyle S["tooltipstyle"] << pref.tooltipstyle
S["client_fps"] << pref.client_fps S["client_fps"] << pref.client_fps
S["tgui_fancy"] << pref.tgui_fancy
S["tgui_lock"] << pref.tgui_lock
/datum/category_item/player_setup_item/player_global/ui/sanitize_preferences() /datum/category_item/player_setup_item/player_global/ui/sanitize_preferences()
pref.UI_style = sanitize_inlist(pref.UI_style, all_ui_styles, initial(pref.UI_style)) pref.UI_style = sanitize_inlist(pref.UI_style, all_ui_styles, initial(pref.UI_style))
@@ -25,20 +29,24 @@
pref.ooccolor = sanitize_hexcolor(pref.ooccolor, initial(pref.ooccolor)) pref.ooccolor = sanitize_hexcolor(pref.ooccolor, initial(pref.ooccolor))
pref.tooltipstyle = sanitize_inlist(pref.tooltipstyle, all_tooltip_styles, initial(pref.tooltipstyle)) pref.tooltipstyle = sanitize_inlist(pref.tooltipstyle, all_tooltip_styles, initial(pref.tooltipstyle))
pref.client_fps = sanitize_integer(pref.client_fps, 0, MAX_CLIENT_FPS, initial(pref.client_fps)) pref.client_fps = sanitize_integer(pref.client_fps, 0, MAX_CLIENT_FPS, initial(pref.client_fps))
pref.tgui_fancy = sanitize_integer(pref.tgui_fancy, 0, 1, initial(pref.tgui_fancy))
pref.tgui_lock = sanitize_integer(pref.tgui_lock, 0, 1, initial(pref.tgui_lock))
/datum/category_item/player_setup_item/player_global/ui/content(var/mob/user) /datum/category_item/player_setup_item/player_global/ui/content(var/mob/user)
. = "<b>UI Style:</b> <a href='?src=\ref[src];select_style=1'><b>[pref.UI_style]</b></a><br>" . = "<b>UI Style:</b> <a href='?src=\ref[src];select_style=1'><b>[pref.UI_style]</b></a><br>"
. += "<b>Custom UI</b> (recommended for White UI):<br>" . += "<b>Custom UI</b> (recommended for White UI):<br>"
. += "-Color: <a href='?src=\ref[src];select_color=1'><b>[pref.UI_style_color]</b></a><3E>[color_square(hex = pref.UI_style_color)]<5D><a href='?src=\ref[src];reset=ui'>reset</a><br>" . += "-Color: <a href='?src=\ref[src];select_color=1'><b>[pref.UI_style_color]</b></a><3E>[color_square(hex = pref.UI_style_color)]<5D><a href='?src=\ref[src];reset=ui'>reset</a><br>"
. += "-Alpha(transparency): <a href='?src=\ref[src];select_alpha=1'><b>[pref.UI_style_alpha]</b></a><3E><a href='?src=\ref[src];reset=alpha'>reset</a><br>" . += "-Alpha(transparency): <a href='?src=\ref[src];select_alpha=1'><b>[pref.UI_style_alpha]</b></a><3E><a href='?src=\ref[src];reset=alpha'>reset</a><br>"
. += "<b>Tooltip Style:</b> <a href='?src=\ref[src];select_tooltip_style=1'><b>[pref.tooltipstyle]</b></a><br>" . += "<b>Tooltip Style:</b> <a href='?src=\ref[src];select_tooltip_style=1'><b>[pref.tooltipstyle]</b></a><br>"
. += "<b>Client FPS:</b> <a href='?src=\ref[src];select_client_fps=1'><b>[pref.client_fps]</b></a><br>" . += "<b>Client FPS:</b> <a href='?src=\ref[src];select_client_fps=1'><b>[pref.client_fps]</b></a><br>"
. += "<b>tgui Window Mode:</b> <a href='?src=\ref[src];tgui_fancy=1'><b>[(pref.tgui_fancy) ? "Fancy (default)" : "Compatible (slower)"]</b></a><br>"
. += "<b>tgui Window Placement:</b> <a href='?src=\ref[src];tgui_lock=1'><b>[(pref.tgui_lock) ? "Primary Monitor" : "Free (default)"]</b></a><br>"
if(can_select_ooc_color(user)) if(can_select_ooc_color(user))
. += "<b>OOC Color:</b><3E>" . += "<b>OOC Color:</b><3E>"
if(pref.ooccolor == initial(pref.ooccolor)) if(pref.ooccolor == initial(pref.ooccolor))
. += "<a href='?src=\ref[src];select_ooc_color=1'><b>Using Default</b></a><br>" . += "<a href='?src=\ref[src];select_ooc_color=1'><b>Using Default</b></a><br>"
else else
. += "<a href='?src=\ref[src];select_ooc_color=1'><b>[pref.ooccolor]</b></a> [color_square(hex = pref.ooccolor)]<5D><a href='?src=\ref[src];reset=ooc'>reset</a><br>" . += "<a href='?src=\ref[src];select_ooc_color=1'><b>[pref.ooccolor]</b></a> [color_square(hex = pref.ooccolor)]<5D><a href='?src=\ref[src];reset=ooc'>reset</a><br>"
/datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) /datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user)
if(href_list["select_style"]) if(href_list["select_style"])
@@ -80,6 +88,14 @@
pref.client.fps = fps_new pref.client.fps = fps_new
return TOPIC_REFRESH return TOPIC_REFRESH
else if(href_list["tgui_fancy"])
pref.tgui_fancy = !pref.tgui_fancy
return TOPIC_REFRESH
else if(href_list["tgui_lock"])
pref.tgui_lock = !pref.tgui_lock
return TOPIC_REFRESH
else if(href_list["reset"]) else if(href_list["reset"])
switch(href_list["reset"]) switch(href_list["reset"])
if("ui") if("ui")

View File

@@ -21,3 +21,7 @@
display_name = "sterile mask" display_name = "sterile mask"
path = /obj/item/clothing/mask/surgical path = /obj/item/clothing/mask/surgical
cost = 2 cost = 2
/datum/gear/mask/veil
display_name = "black veil"
path = /obj/item/clothing/mask/veil

View File

@@ -557,3 +557,27 @@
/datum/gear/uniform/haltertop /datum/gear/uniform/haltertop
display_name = "halter top" display_name = "halter top"
path = /obj/item/clothing/under/haltertop path = /obj/item/clothing/under/haltertop
/datum/gear/uniform/revealingdress
display_name = "revealing dress"
path = /obj/item/clothing/under/dress/revealingdress
/datum/gear/uniform/rippedpunk
display_name = "ripped punk jeans"
path = /obj/item/clothing/under/rippedpunk
/datum/gear/uniform/gothic
display_name = "gothic dress"
path = /obj/item/clothing/under/dress/gothic
/datum/gear/uniform/formalred
display_name = "formal red dress"
path = /obj/item/clothing/under/dress/formalred
/datum/gear/uniform/pentagram
display_name = "pentagram dress"
path = /obj/item/clothing/under/dress/pentagram
/datum/gear/uniform/yellowswoop
display_name = "yellow swooped dress"
path = /obj/item/clothing/under/dress/yellowswoop

View File

@@ -24,6 +24,9 @@ datum/preferences
var/tooltipstyle = "Midnight" //Style for popup tooltips var/tooltipstyle = "Midnight" //Style for popup tooltips
var/client_fps = 0 var/client_fps = 0
var/tgui_fancy = TRUE
var/tgui_lock = FALSE
//character preferences //character preferences
var/real_name //our character's name var/real_name //our character's name
var/be_random_name = 0 //whether we are a random name every round var/be_random_name = 0 //whether we are a random name every round

View File

@@ -8,6 +8,8 @@
icon_state = "glasses" icon_state = "glasses"
var/datum/nano_module/arscreen var/datum/nano_module/arscreen
var/arscreen_path var/arscreen_path
var/datum/tgui_module/tgarscreen
var/tgarscreen_path
var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection
enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED) enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
plane_slots = list(slot_glasses) plane_slots = list(slot_glasses)
@@ -16,21 +18,33 @@
..() ..()
if(arscreen_path) if(arscreen_path)
arscreen = new arscreen_path(src) arscreen = new arscreen_path(src)
if(tgarscreen_path)
tgarscreen = new tgarscreen_path(src)
/obj/item/clothing/glasses/omnihud/Destroy() /obj/item/clothing/glasses/omnihud/Destroy()
QDEL_NULL(arscreen) QDEL_NULL(arscreen)
QDEL_NULL(tgarscreen)
. = ..() . = ..()
/obj/item/clothing/glasses/omnihud/dropped() /obj/item/clothing/glasses/omnihud/dropped()
if(arscreen) if(arscreen)
SSnanoui.close_uis(src) SSnanoui.close_uis(src)
if(tgarscreen)
SStgui.close_uis(src)
..() ..()
/obj/item/clothing/glasses/omnihud/emp_act(var/severity) /obj/item/clothing/glasses/omnihud/emp_act(var/severity)
if(arscreen)
SSnanoui.close_uis(src)
if(tgarscreen)
SStgui.close_uis(src)
var/disconnect_ar = arscreen var/disconnect_ar = arscreen
var/disconnect_tgar = tgarscreen
arscreen = null arscreen = null
tgarscreen = null
spawn(20 SECONDS) spawn(20 SECONDS)
arscreen = disconnect_ar arscreen = disconnect_ar
tgarscreen = disconnect_tgar
..() ..()
/obj/item/clothing/glasses/omnihud/proc/flashed() /obj/item/clothing/glasses/omnihud/proc/flashed()
@@ -71,12 +85,12 @@
These have been upgraded with medical records access and virus database integration." These have been upgraded with medical records access and virus database integration."
mode = "med" mode = "med"
action_button_name = "AR Console (Crew Monitor)" action_button_name = "AR Console (Crew Monitor)"
arscreen_path = /datum/nano_module/program/crew_monitor tgarscreen_path = /datum/tgui_module/crew_monitor/glasses
enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_AUGMENTED) enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_AUGMENTED)
ar_interact(var/mob/living/carbon/human/user) ar_interact(var/mob/living/carbon/human/user)
if(arscreen) if(tgarscreen)
arscreen.ui_interact(user,"main",null,1,glasses_state) tgarscreen.tgui_interact(user)
return 1 return 1
/obj/item/clothing/glasses/omnihud/sec /obj/item/clothing/glasses/omnihud/sec

View File

@@ -288,3 +288,10 @@
desc = "A fine black bandana with nanotech lining and a skull emblem. Can be worn on the head or face." desc = "A fine black bandana with nanotech lining and a skull emblem. Can be worn on the head or face."
icon_state = "bandskull" icon_state = "bandskull"
item_state_slots = list(slot_r_hand_str = "bandskull", slot_l_hand_str = "bandskull") item_state_slots = list(slot_r_hand_str = "bandskull", slot_l_hand_str = "bandskull")
/obj/item/clothing/mask/veil
name = "black veil"
desc = "A black veil, typically worn at funerals or by goths."
w_class = ITEMSIZE_TINY
body_parts_covered = FACE
icon_state = "veil"

View File

@@ -535,6 +535,37 @@
desc = "A red and white dress themed after some winter holidays. Tastefully festive!" desc = "A red and white dress themed after some winter holidays. Tastefully festive!"
icon_state = "festivedress" icon_state = "festivedress"
/obj/item/clothing/under/dress/revealingdress
name = "revealing dress"
desc = "A very revealing black and blue dress. Is this work appropriate?"
icon_state = "revealingdress"
index = 1
/obj/item/clothing/under/dress/gothic
name = "gothic dress"
desc = "A black dress with a sheer mesh over it, tastefully old school goth."
icon_state = "gothic"
index = 1
/obj/item/clothing/under/dress/formalred
name = "formal red dress"
desc = "A very formal red dress, for those fancy galas."
icon_state = "formalred"
flags_inv = HIDESHOES
index = 1
/obj/item/clothing/under/dress/pentagram
name = "pentagram dress"
desc = "A black dress with straps over the chest in the shape of a pentagram."
icon_state = "pentagram"
index = 1
obj/item/clothing/under/dress/yellowswoop
name = "yellow swooped dress"
desc = "A yellow dress that swoops to the side."
icon_state = "yellowswoop"
index = 1
/* /*
* wedding stuff * wedding stuff
*/ */
@@ -767,6 +798,12 @@ Uniforms and such
desc = "Jean shorts and a black halter top. Perfect for casual Fridays!" desc = "Jean shorts and a black halter top. Perfect for casual Fridays!"
icon_state = "haltertop" icon_state = "haltertop"
/obj/item/clothing/under/rippedpunk
name = "ripped punk jeans"
desc = "Black ripped jeans and a fishnet top. How punk."
icon_state = "rippedpunk"
index = 1
/* /*
* swimsuit * swimsuit
*/ */

View File

@@ -77,7 +77,7 @@
// This will actually protect it from further damage. // This will actually protect it from further damage.
if(prob(25)) if(prob(25))
A.energy_fail(rand(60, 120)) A.energy_fail(rand(60, 120))
log_debug("ELECTRICAL EVENT: Disabled \the [A]'s power for a temporary amount of time.") // log_debug("ELECTRICAL EVENT: Disabled \the [A]'s power for a temporary amount of time.")
playsound(A, 'sound/machines/defib_success.ogg', 50, 1) playsound(A, 'sound/machines/defib_success.ogg', 50, 1)
apcs_disabled++ apcs_disabled++
return return
@@ -85,7 +85,7 @@
// Decent chance to overload lighting circuit. // Decent chance to overload lighting circuit.
if(prob(30)) if(prob(30))
A.overload_lighting() A.overload_lighting()
log_debug("ELECTRICAL EVENT: Overloaded \the [A]'s lighting.") // log_debug("ELECTRICAL EVENT: Overloaded \the [A]'s lighting.")
playsound(A, 'sound/effects/lightningshock.ogg', 50, 1) playsound(A, 'sound/effects/lightningshock.ogg', 50, 1)
apcs_overloaded++ apcs_overloaded++
@@ -93,7 +93,7 @@
if(prob(5)) if(prob(5))
A.emagged = TRUE A.emagged = TRUE
A.update_icon() A.update_icon()
log_debug("ELECTRICAL EVENT: Emagged \the [A].") // log_debug("ELECTRICAL EVENT: Emagged \the [A].")
playsound(A, 'sound/machines/chime.ogg', 50, 1) playsound(A, 'sound/machines/chime.ogg', 50, 1)
apcs_emagged++ apcs_emagged++

View File

@@ -40,13 +40,13 @@
var/list/activity = list() var/list/activity = list()
for(var/department in departments) for(var/department in departments)
activity[department] = assess_department(department) activity[department] = assess_department(department)
log_debug("Assessing department [department]. They have activity of [activity[department]].") // log_debug("Assessing department [department]. They have activity of [activity[department]].")
var/list/most_active_departments = list() // List of winners. var/list/most_active_departments = list() // List of winners.
var/highest_activity = null // Department who is leading in activity, if one exists. var/highest_activity = null // Department who is leading in activity, if one exists.
var/highest_number = 0 // Activity score needed to beat to be the most active department. var/highest_number = 0 // Activity score needed to beat to be the most active department.
for(var/i = 1, i <= cutoff_number, i++) for(var/i = 1, i <= cutoff_number, i++)
log_debug("Doing [i]\th round of counting.") // log_debug("Doing [i]\th round of counting.")
for(var/department in activity) for(var/department in activity)
if(department in department_blacklist) // Blacklisted? if(department in department_blacklist) // Blacklisted?
continue continue
@@ -57,7 +57,7 @@
if(highest_activity) // Someone's a winner. if(highest_activity) // Someone's a winner.
most_active_departments.Add(highest_activity) // Add to the list of most active. most_active_departments.Add(highest_activity) // Add to the list of most active.
activity.Remove(highest_activity) // Remove them from the other list so they don't win more than once. activity.Remove(highest_activity) // Remove them from the other list so they don't win more than once.
log_debug("[highest_activity] has won the [i]\th round of activity counting.") // log_debug("[highest_activity] has won the [i]\th round of activity counting.")
highest_activity = null // Now reset for the next round. highest_activity = null // Now reset for the next round.
highest_number = 0 highest_number = 0
//todo: finish //todo: finish

View File

@@ -37,7 +37,6 @@
/obj/machinery/camera/deactivate(user as mob, var/choice = 1) /obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice) ..(user, choice)
invalidateCameraCache()
if(src.can_use()) if(src.can_use())
cameranet.addCamera(src) cameranet.addCamera(src)
else else

View File

@@ -110,6 +110,21 @@
"ver", "stv", "pro", "ski" "ver", "stv", "pro", "ski"
) )
/datum/language/drudakar
name = LANGUAGE_DRUDAKAR
desc = "The native language of the D'Rudak'Ar, a loosely tied together community of dragons and demi-dragons based in the Diul system. Features include many hard consonants and rolling 'r's."
speech_verb = "gaos"
ask_verb = "gaos"
exclaim_verb = "GAOS"
whisper_verb = "gaos"
colour = "drudakar"
key = "K"
syllables = list(
"gok", "rha", "rou", "gao", "do", "ra", "bo", "lah", "draz", "khi", "zah", "lah", "ora", "ille",
"ghlas", "ghlai", "tyur", "vah", "bao", "raag", "drag", "zhi", "dahl", "tiyr", "vahl", "nyem",
"roar", "hyaa", "ma", "ha", "ya", "shi", "yo", "go"
)
/datum/language/unathi /datum/language/unathi
flags = 0 flags = 0
/datum/language/tajaran /datum/language/tajaran

View File

@@ -1,3 +1,13 @@
// Medbot Info
#define MEDBOT_PANIC_NONE 0
#define MEDBOT_PANIC_LOW 15
#define MEDBOT_PANIC_MED 35
#define MEDBOT_PANIC_HIGH 55
#define MEDBOT_PANIC_FUCK 70
#define MEDBOT_PANIC_ENDING 90
#define MEDBOT_PANIC_END 100
/mob/living/bot/medbot /mob/living/bot/medbot
name = "Medibot" name = "Medibot"
desc = "A little medical robot. He looks somewhat underwhelmed." desc = "A little medical robot. He looks somewhat underwhelmed."
@@ -24,6 +34,15 @@
var/treatment_emag = "toxin" var/treatment_emag = "toxin"
var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds? var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds?
// Are we tipped over?
var/is_tipped = FALSE
//How panicked we are about being tipped over (why would you do this?)
var/tipped_status = MEDBOT_PANIC_NONE
//The name we got when we were tipped
var/tipper_name
//The last time we were tipped/righted and said a voice line, to avoid spam
var/last_tipping_action_voice = 0
/mob/living/bot/medbot/mysterious /mob/living/bot/medbot/mysterious
name = "\improper Mysterious Medibot" name = "\improper Mysterious Medibot"
desc = "International Medibot of mystery." desc = "International Medibot of mystery."
@@ -34,6 +53,9 @@
treatment_tox = "anti_toxin" treatment_tox = "anti_toxin"
/mob/living/bot/medbot/handleIdle() /mob/living/bot/medbot/handleIdle()
if(is_tipped) // Don't handle idle things if we're incapacitated!
return
if(vocal && prob(1)) if(vocal && prob(1))
var/message_options = list( var/message_options = list(
"Radar, put a mask on!" = 'sound/voice/medbot/mradar.ogg', "Radar, put a mask on!" = 'sound/voice/medbot/mradar.ogg',
@@ -47,6 +69,9 @@
playsound(src, message_options[message], 50, 0) playsound(src, message_options[message], 50, 0)
/mob/living/bot/medbot/handleAdjacentTarget() /mob/living/bot/medbot/handleAdjacentTarget()
if(is_tipped) // Don't handle targets if we're incapacitated!
return
UnarmedAttack(target) UnarmedAttack(target)
/mob/living/bot/medbot/handlePanic() // Speed modification based on alert level. /mob/living/bot/medbot/handlePanic() // Speed modification based on alert level.
@@ -76,6 +101,9 @@
return . return .
/mob/living/bot/medbot/lookForTargets() /mob/living/bot/medbot/lookForTargets()
if(is_tipped) // Don't look for targets if we're incapacitated!
return
for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient! for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
if(confirmTarget(H)) if(confirmTarget(H))
target = H target = H
@@ -162,7 +190,28 @@
else else
icon_state = "medibot[on]" icon_state = "medibot[on]"
/mob/living/bot/medbot/attack_hand(var/mob/user) /mob/living/bot/medbot/attack_hand(mob/living/carbon/human/H)
if(H.a_intent == I_DISARM && !is_tipped)
H.visible_message("<span class='danger'>[H] begins tipping over [src].</span>", "<span class='warning'>You begin tipping over [src]...</span>")
if(world.time > last_tipping_action_voice + 15 SECONDS)
last_tipping_action_voice = world.time // message for tipping happens when we start interacting, message for righting comes after finishing
var/list/messagevoice = list("Hey, wait..." = 'sound/voice/medbot/hey_wait.ogg',"Please don't..." = 'sound/voice/medbot/please_dont.ogg',"I trusted you..." = 'sound/voice/medbot/i_trusted_you.ogg', "Nooo..." = 'sound/voice/medbot/nooo.ogg', "Oh fuck-" = 'sound/voice/medbot/oh_fuck.ogg')
var/message = pick(messagevoice)
say(message)
playsound(src, messagevoice[message], 70, FALSE)
if(do_after(H, 3 SECONDS, target=src))
tip_over(H)
else if(H.a_intent == I_HELP && is_tipped)
H.visible_message("<span class='notice'>[H] begins righting [src].</span>", "<span class='notice'>You begin righting [src]...</span>")
if(do_after(H, 3 SECONDS, target=src))
set_right(H)
else
interact()
/mob/living/bot/medbot/proc/interact(mob/user)
var/dat var/dat
dat += "<TT><B>Automatic Medical Unit v1.0</B></TT><BR><BR>" dat += "<TT><B>Automatic Medical Unit v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>" dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
@@ -301,6 +350,89 @@
qdel(src) qdel(src)
return return
/mob/living/bot/medbot/handleRegular()
. = ..()
if(is_tipped)
handle_panic()
return
/mob/living/bot/medbot/proc/tip_over(mob/user)
playsound(src, 'sound/machines/warning-buzzer.ogg', 50)
user.visible_message("<span class='danger'>[user] tips over [src]!</span>", "<span class='danger'>You tip [src] over!</span>")
is_tipped = TRUE
tipper_name = user.name
var/matrix/mat = transform
transform = mat.Turn(180)
/mob/living/bot/medbot/proc/set_right(mob/user)
var/list/messagevoice
if(user)
user.visible_message("<span class='notice'>[user] sets [src] right-side up!</span>", "<span class='green'>You set [src] right-side up!</span>")
if(user.name == tipper_name)
messagevoice = list("I forgive you." = 'sound/voice/medbot/forgive.ogg')
else
messagevoice = list("Thank you!" = 'sound/voice/medbot/thank_you.ogg', "You are a good person." = 'sound/voice/medbot/youre_good.ogg')
else
visible_message("<span class='notice'>[src] manages to [pick("writhe", "wriggle", "wiggle")] enough to right itself.</span>")
messagevoice = list("Fuck you." = 'sound/voice/medbot/fuck_you.ogg', "Your behavior has been reported, have a nice day." = 'sound/voice/medbot/reported.ogg')
tipper_name = null
if(world.time > last_tipping_action_voice + 15 SECONDS)
last_tipping_action_voice = world.time
var/message = pick(messagevoice)
say(message)
playsound(src, messagevoice[message], 70)
tipped_status = MEDBOT_PANIC_NONE
is_tipped = FALSE
transform = matrix()
// if someone tipped us over, check whether we should ask for help or just right ourselves eventually
/mob/living/bot/medbot/proc/handle_panic()
tipped_status++
var/list/messagevoice
switch(tipped_status)
if(MEDBOT_PANIC_LOW)
messagevoice = list("I require assistance." = 'sound/voice/medbot/i_require_asst.ogg')
if(MEDBOT_PANIC_MED)
messagevoice = list("Please put me back." = 'sound/voice/medbot/please_put_me_back.ogg')
if(MEDBOT_PANIC_HIGH)
messagevoice = list("Please, I am scared!" = 'sound/voice/medbot/please_im_scared.ogg')
if(MEDBOT_PANIC_FUCK)
messagevoice = list("I don't like this, I need help!" = 'sound/voice/medbot/dont_like.ogg', "This hurts, my pain is real!" = 'sound/voice/medbot/pain_is_real.ogg')
if(MEDBOT_PANIC_ENDING)
messagevoice = list("Is this the end?" = 'sound/voice/medbot/is_this_the_end.ogg', "Nooo!" = 'sound/voice/medbot/nooo.ogg')
if(MEDBOT_PANIC_END)
global_announcer.autosay("PSYCH ALERT: Crewmember [tipper_name] recorded displaying antisocial tendencies torturing bots in [get_area(src)]. Please schedule psych evaluation.", "[src]", "Medical")
set_right() // strong independent medbot
// if(prob(tipped_status)) // Commented out pending introduction of jitter stuff from /tg/
// do_jitter_animation(tipped_status * 0.1)
if(messagevoice)
var/message = pick(messagevoice)
say(message)
playsound(src, messagevoice[message], 70)
else if(prob(tipped_status * 0.2))
playsound(src, 'sound/machines/warning-buzzer.ogg', 30, extrarange=-2)
/mob/living/bot/medbot/examine(mob/user)
. = ..()
if(tipped_status == MEDBOT_PANIC_NONE)
return
switch(tipped_status)
if(MEDBOT_PANIC_NONE to MEDBOT_PANIC_LOW)
. += "It appears to be tipped over, and is quietly waiting for someone to set it right."
if(MEDBOT_PANIC_LOW to MEDBOT_PANIC_MED)
. += "It is tipped over and requesting help."
if(MEDBOT_PANIC_MED to MEDBOT_PANIC_HIGH)
. += "They are tipped over and appear visibly distressed." // now we humanize the medbot as a they, not an it
if(MEDBOT_PANIC_HIGH to MEDBOT_PANIC_FUCK)
. += "<span class='warning'>They are tipped over and visibly panicking!</span>"
if(MEDBOT_PANIC_FUCK to INFINITY)
. += "<span class='warning'><b>They are freaking out from being tipped over!</b></span>"
/mob/living/bot/medbot/confirmTarget(var/mob/living/carbon/human/H) /mob/living/bot/medbot/confirmTarget(var/mob/living/carbon/human/H)
if(!..()) if(!..())
return 0 return 0
@@ -430,3 +562,12 @@
S.name = created_name S.name = created_name
user.drop_from_inventory(src) user.drop_from_inventory(src)
qdel(src) qdel(src)
// Undefine these.
#undef MEDBOT_PANIC_NONE
#undef MEDBOT_PANIC_LOW
#undef MEDBOT_PANIC_MED
#undef MEDBOT_PANIC_HIGH
#undef MEDBOT_PANIC_FUCK
#undef MEDBOT_PANIC_ENDING
#undef MEDBOT_PANIC_END

View File

@@ -49,6 +49,21 @@
update_hair() update_hair()
return 1 return 1
/mob/living/carbon/human/proc/change_hair_gradient(var/hair_gradient)
if(!hair_gradient)
return
if(grad_style == hair_gradient)
return
if(!(hair_gradient in GLOB.hair_gradients))
return
grad_style = hair_gradient
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style) /mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style)
if(!facial_hair_style) if(!facial_hair_style)
return return
@@ -105,6 +120,17 @@
update_hair() update_hair()
return 1 return 1
/mob/living/carbon/human/proc/change_grad_color(var/red, var/green, var/blue)
if(red == r_grad && green == g_grad && blue == b_grad)
return
r_grad = red
g_grad = green
b_grad = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue) /mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue)
if(red == r_facial && green == g_facial && blue == b_facial) if(red == r_facial && green == g_facial && blue == b_facial)
return return

View File

@@ -146,6 +146,10 @@
message = "rumbles their throat, puffs their cheeks and croaks." message = "rumbles their throat, puffs their cheeks and croaks."
m_type = 2 m_type = 2
playsound(src, 'sound/voice/Croak.ogg', 50, 0, preference = /datum/client_preference/emote_noises) playsound(src, 'sound/voice/Croak.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
if("gao")
message = "lets out a gao."
m_type = 2
playsound(src, 'sound/voice/gao.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
if("nsay") if("nsay")
nsay() nsay()
return TRUE return TRUE

View File

@@ -88,6 +88,7 @@ var/list/wrapped_species_by_ref = list()
var/list/valid_hairstyles = list() var/list/valid_hairstyles = list()
var/list/valid_facialhairstyles = list() var/list/valid_facialhairstyles = list()
var/list/valid_gradstyles = GLOB.hair_gradients
for(var/hairstyle in hair_styles_list) for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle] var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
if(gender == MALE && S.gender == FEMALE) if(gender == MALE && S.gender == FEMALE)
@@ -112,6 +113,9 @@ var/list/wrapped_species_by_ref = list()
if(valid_hairstyles.len) if(valid_hairstyles.len)
var/new_hair = input("Select a hairstyle.", "Shapeshifter Hair") as null|anything in valid_hairstyles var/new_hair = input("Select a hairstyle.", "Shapeshifter Hair") as null|anything in valid_hairstyles
change_hair(new_hair ? new_hair : "Bald") change_hair(new_hair ? new_hair : "Bald")
if(valid_gradstyles.len)
var/new_hair = input("Select a hair gradient style.", "Shapeshifter Hair") as null|anything in valid_gradstyles
change_hair_gradient(new_hair ? new_hair : "None")
if(valid_facialhairstyles.len) if(valid_facialhairstyles.len)
var/new_hair = input("Select a facial hair style.", "Shapeshifter Hair") as null|anything in valid_facialhairstyles var/new_hair = input("Select a facial hair style.", "Shapeshifter Hair") as null|anything in valid_facialhairstyles
change_facial_hair(new_hair ? new_hair : "Shaved") change_facial_hair(new_hair ? new_hair : "Shaved")
@@ -216,6 +220,10 @@ var/list/wrapped_species_by_ref = list()
if(!new_hair) if(!new_hair)
return return
shapeshifter_set_hair_color(new_hair) shapeshifter_set_hair_color(new_hair)
var/new_grad = input("Please select a new hair gradient color.", "Hair Gradient Colour") as color
if(!new_grad)
return
shapeshifter_set_grad_color(new_grad)
var/new_fhair = input("Please select a new facial hair color.", "Facial Hair Color") as color var/new_fhair = input("Please select a new facial hair color.", "Facial Hair Color") as color
if(!new_fhair) if(!new_fhair)
return return
@@ -225,6 +233,10 @@ var/list/wrapped_species_by_ref = list()
change_hair_color(hex2num(copytext(new_hair, 2, 4)), hex2num(copytext(new_hair, 4, 6)), hex2num(copytext(new_hair, 6, 8))) change_hair_color(hex2num(copytext(new_hair, 2, 4)), hex2num(copytext(new_hair, 4, 6)), hex2num(copytext(new_hair, 6, 8)))
/mob/living/carbon/human/proc/shapeshifter_set_grad_color(var/new_grad)
change_grad_color(hex2num(copytext(new_grad, 2, 4)), hex2num(copytext(new_grad, 4, 6)), hex2num(copytext(new_grad, 6, 8)))
/mob/living/carbon/human/proc/shapeshifter_set_facial_color(var/new_fhair) /mob/living/carbon/human/proc/shapeshifter_set_facial_color(var/new_fhair)
change_facial_hair_color(hex2num(copytext(new_fhair, 2, 4)), hex2num(copytext(new_fhair, 4, 6)), hex2num(copytext(new_fhair, 6, 8))) change_facial_hair_color(hex2num(copytext(new_fhair, 2, 4)), hex2num(copytext(new_fhair, 4, 6)), hex2num(copytext(new_fhair, 6, 8)))

View File

@@ -133,3 +133,4 @@
/datum/trait/colorblind/para_taj/apply(var/datum/species/S,var/mob/living/carbon/human/H) /datum/trait/colorblind/para_taj/apply(var/datum/species/S,var/mob/living/carbon/human/H)
..(S,H) ..(S,H)
H.add_modifier(/datum/modifier/trait/colorblind_taj) H.add_modifier(/datum/modifier/trait/colorblind_taj)

View File

@@ -19,19 +19,19 @@
var_changes = list("metabolic_rate" = 1.4, "hunger_factor" = 0.4, "metabolism" = 0.012) // +40% rate and 8x hunger (Double Teshari) var_changes = list("metabolic_rate" = 1.4, "hunger_factor" = 0.4, "metabolism" = 0.012) // +40% rate and 8x hunger (Double Teshari)
excludes = list(/datum/trait/metabolism_up, /datum/trait/metabolism_down) excludes = list(/datum/trait/metabolism_up, /datum/trait/metabolism_down)
/datum/trait/cold_discomfort /datum/trait/coldadapt
name = "Hot-Blooded" name = "Cold-Adapted"
desc = "You are too hot at the standard 20C. 18C is more suitable. Rolling down your jumpsuit or being unclothed helps." desc = "You are able to withstand much colder temperatures than other species, and can even be comfortable in extremely cold environments. You are also more vulnerable to hot environments as a consequence of these adaptations."
cost = 0 cost = 0
var_changes = list("heat_discomfort_level" = T0C+19) var_changes = list("cold_level_1" = 200, "cold_level_2" = 150, "cold_level_3" = 90, "breath_cold_level_1" = 180, "breath_cold_level_2" = 100, "breath_cold_level_3" = 60, "cold_discomfort_level" = 210, "heat_level_1" = 305, "heat_level_2" = 360, "heat_level_3" = 700, "breath_heat_level_1" = 345, "breath_heat_level_2" = 380, "breath_heat_level_3" = 780, "heat_discomfort_level" = 295)
excludes = list(/datum/trait/hot_discomfort) excludes = list(/datum/trait/hotadapt)
/datum/trait/hot_discomfort /datum/trait/hotadapt
name = "Cold-Blooded" name = "Heat-Adapted"
desc = "You are too cold at the standard 20C. 22C is more suitable. Wearing clothing that covers your legs and torso helps." desc = "You are able to withstand much hotter temperatures than other species, and can even be comfortable in extremely hot environments. You are also more vulnerable to cold environments as a consequence of these adaptations."
cost = 0 cost = 0
var_changes = list("cold_discomfort_level" = T0C+21) var_changes = list("heat_level_1" = 420, "heat_level_2" = 460, "heat_level_3" = 1100, "breath_heat_level_1" = 440, "breath_heat_level_2" = 510, "breath_heat_level_3" = 1500, "heat_discomfort_level" = 390, "cold_level_1" = 280, "cold_level_2" = 220, "cold_level_3" = 140, "breath_cold_level_1" = 260, "breath_cold_level_2" = 240, "breath_cold_level_3" = 120, "cold_discomfort_level" = 280)
excludes = list(/datum/trait/cold_discomfort) excludes = list(/datum/trait/coldadapt)
/datum/trait/autohiss_unathi /datum/trait/autohiss_unathi
name = "Autohiss (Unathi)" name = "Autohiss (Unathi)"

View File

@@ -124,3 +124,9 @@
desc = "You're capable of parkour and can *flip over low objects (most of the time)." desc = "You're capable of parkour and can *flip over low objects (most of the time)."
cost = 2 cost = 2
var_changes = list("agility" = 90) var_changes = list("agility" = 90)
/datum/trait/snowwalker
name = "Snow Walker"
desc = "You are able to move unhindered on snow."
cost = 1
var_changes = list("snow_movement" = -2)

View File

@@ -6,6 +6,7 @@
add_language(LANGUAGE_ECUREUILIAN, 1) add_language(LANGUAGE_ECUREUILIAN, 1)
add_language(LANGUAGE_DAEMON, 1) add_language(LANGUAGE_DAEMON, 1)
add_language(LANGUAGE_ENOCHIAN, 1) add_language(LANGUAGE_ENOCHIAN, 1)
add_language(LANGUAGE_DRUDAKAR, 1)
/mob/AIize(var/move = TRUE) /mob/AIize(var/move = TRUE)
. = ..() . = ..()
@@ -15,3 +16,4 @@
add_language(LANGUAGE_ECUREUILIAN, 1) add_language(LANGUAGE_ECUREUILIAN, 1)
add_language(LANGUAGE_DAEMON, 1) add_language(LANGUAGE_DAEMON, 1)
add_language(LANGUAGE_ENOCHIAN, 1) add_language(LANGUAGE_ENOCHIAN, 1)
add_language(LANGUAGE_DRUDAKAR, 1)

View File

@@ -673,7 +673,7 @@
name = "Digestive Analyzer" name = "Digestive Analyzer"
desc = "A mounted destructive analyzer unit with fuel processor." desc = "A mounted destructive analyzer unit with fuel processor."
icon_state = "analyzer" icon_state = "analyzer"
max_item_count = 1 max_item_count = 10
startdrain = 100 startdrain = 100
analyzer = TRUE analyzer = TRUE

View File

@@ -12,7 +12,8 @@
LANGUAGE_CANILUNZT = 0, LANGUAGE_CANILUNZT = 0,
LANGUAGE_ECUREUILIAN= 0, LANGUAGE_ECUREUILIAN= 0,
LANGUAGE_DAEMON = 0, LANGUAGE_DAEMON = 0,
LANGUAGE_ENOCHIAN = 0 LANGUAGE_ENOCHIAN = 0,
LANGUAGE_DRUDAKAR = 0
) )
var/vr_sprites = list() var/vr_sprites = list()
var/pto_type = null var/pto_type = null
@@ -34,7 +35,8 @@
LANGUAGE_CANILUNZT = 1, LANGUAGE_CANILUNZT = 1,
LANGUAGE_ECUREUILIAN= 1, LANGUAGE_ECUREUILIAN= 1,
LANGUAGE_DAEMON = 1, LANGUAGE_DAEMON = 1,
LANGUAGE_ENOCHIAN = 1 LANGUAGE_ENOCHIAN = 1,
LANGUAGE_DRUDAKAR = 1
) )
/hook/startup/proc/robot_modules_vr() /hook/startup/proc/robot_modules_vr()

View File

@@ -2,7 +2,7 @@
var/register_alarms = 1 var/register_alarms = 1
var/datum/nano_module/alarm_monitor/all/alarm_monitor var/datum/nano_module/alarm_monitor/all/alarm_monitor
var/datum/nano_module/atmos_control/atmos_control var/datum/nano_module/atmos_control/atmos_control
var/datum/nano_module/program/crew_monitor/crew_monitor var/datum/tgui_module/crew_monitor/robot/crew_monitor
var/datum/nano_module/law_manager/law_manager var/datum/nano_module/law_manager/law_manager
var/datum/nano_module/power_monitor/power_monitor var/datum/nano_module/power_monitor/power_monitor
var/datum/nano_module/rcon/rcon var/datum/nano_module/rcon/rcon
@@ -67,7 +67,7 @@
set category = "Subystems" set category = "Subystems"
set name = "Crew Monitor" set name = "Crew Monitor"
crew_monitor.ui_interact(usr, state = self_state) crew_monitor.tgui_interact(usr)
/**************** /****************
* Law Manager * * Law Manager *

View File

@@ -11,6 +11,8 @@
maxHealth = 5 maxHealth = 5
health = 5 health = 5
movement_cooldown = 1.5
mob_size = MOB_MINISCULE mob_size = MOB_MINISCULE
pass_flags = PASSTABLE pass_flags = PASSTABLE
// can_pull_size = ITEMSIZE_TINY // can_pull_size = ITEMSIZE_TINY
@@ -101,15 +103,13 @@
/mob/living/simple_mob/animal/passive/mouse/rat /mob/living/simple_mob/animal/passive/mouse/rat
name = "rat" name = "rat"
body_color = "rat"
icon_state = "mouse_rat"
maxHealth = 20 maxHealth = 20
health = 20 health = 20
ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
/mob/living/simple_mob/animal/passive/mouse/rat/Initialize()
..()
adjust_scale(1.2)
//TOM IS ALIVE! SQUEEEEEEEE~K :) //TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_mob/animal/passive/mouse/brown/Tom /mob/living/simple_mob/animal/passive/mouse/brown/Tom
name = "Tom" name = "Tom"

View File

@@ -5,6 +5,7 @@
icon_state = "panther" icon_state = "panther"
icon_living = "panther" icon_living = "panther"
icon_rest = "panther-rest"
icon_dead = "panther-dead" icon_dead = "panther-dead"
icon = 'icons/mob/vore64x64.dmi' icon = 'icons/mob/vore64x64.dmi'
vis_height = 64 vis_height = 64

View File

@@ -1,5 +1,6 @@
/mob/Logout() /mob/Logout()
SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
SStgui.on_logout(src) // Cleanup any TGUIs the user has open
player_list -= src player_list -= src
disconnect_time = world.realtime //VOREStation Addition: logging when we disappear. disconnect_time = world.realtime //VOREStation Addition: logging when we disappear.
update_client_z(null) update_client_z(null)

View File

@@ -163,6 +163,7 @@
idle_threads.Add(active_program) idle_threads.Add(active_program)
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program) SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program)
SStgui.close_uis(active_program.TM ? active_program.TM : active_program)
active_program = null active_program = null
update_icon() update_icon()
if(istype(user)) if(istype(user))
@@ -202,7 +203,6 @@
minimize_program(user) minimize_program(user)
if(P.run_program(user)) if(P.run_program(user))
active_program = P
update_icon() update_icon()
return 1 return 1

View File

@@ -5,8 +5,13 @@
var/required_access = null // List of required accesses to run/download the program. var/required_access = null // List of required accesses to run/download the program.
var/requires_access_to_run = 1 // Whether the program checks for required_access when run. var/requires_access_to_run = 1 // Whether the program checks for required_access when run.
var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading. var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading.
// NanoModule
var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact. var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program. var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program.
// TGUIModule
var/datum/tgui_module/TM = null // If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement tgui_interact.
var/tguimodule_path = null // Path to tguimodule, make sure to set this if implementing new program.
// Etc Program stuff
var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
var/obj/item/modular_computer/computer // Device that runs this program. var/obj/item/modular_computer/computer // Device that runs this program.
var/filedesc = "Unknown Program" // User-friendly name of this program. var/filedesc = "Unknown Program" // User-friendly name of this program.
@@ -125,9 +130,14 @@
// When implementing new program based device, use this to run the program. // When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(var/mob/living/user) /datum/computer_file/program/proc/run_program(var/mob/living/user)
if(can_run(user, 1) || !requires_access_to_run) if(can_run(user, 1) || !requires_access_to_run)
computer.active_program = src
if(nanomodule_path) if(nanomodule_path)
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src) NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
NM.using_access = user.GetAccess() NM.using_access = user.GetAccess()
if(tguimodule_path)
TM = new tguimodule_path(src)
TM.using_access = user.GetAccess()
TM.tgui_interact(user)
if(requires_ntnet && network_destination) if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].") generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE program_state = PROGRAM_STATE_ACTIVE
@@ -139,9 +149,11 @@
program_state = PROGRAM_STATE_KILLED program_state = PROGRAM_STATE_KILLED
if(network_destination) if(network_destination)
generate_network_log("Connection to [network_destination] closed.") generate_network_log("Connection to [network_destination] closed.")
if(NM) QDEL_NULL(NM)
qdel(NM) if(TM)
NM = null SStgui.close_uis(TM)
qdel(TM)
TM = null
return 1 return 1
// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation. // This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation.
@@ -154,9 +166,11 @@
if(istype(NM)) if(istype(NM))
NM.ui_interact(user, ui_key, null, force_open) NM.ui_interact(user, ui_key, null, force_open)
return 0 return 0
if(istype(TM))
TM.tgui_interact(user)
return 0
return 1 return 1
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: // CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
// Topic calls are automagically forwarded from NanoModule this program contains. // Topic calls are automagically forwarded from NanoModule this program contains.
// Calls beginning with "PRG_" are reserved for programs handling. // Calls beginning with "PRG_" are reserved for programs handling.

View File

@@ -1,7 +1,7 @@
/datum/computer_file/program/camera_monitor/hacked /datum/computer_file/program/camera_monitor/hacked
filename = "camcrypt" filename = "camcrypt"
filedesc = "Camera Decryption Tool" filedesc = "Camera Decryption Tool"
nanomodule_path = /datum/nano_module/camera_monitor/hacked tguimodule_path = /datum/tgui_module/camera/ntos/hacked
program_icon_state = "hostile" program_icon_state = "hostile"
program_key_state = "security_key" program_key_state = "security_key"
program_menu_icon = "zoomin" program_menu_icon = "zoomin"
@@ -15,25 +15,8 @@
if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms. if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms.
return return
var/datum/nano_module/camera_monitor/hacked/HNM = NM
// The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick. // The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick.
if(HNM && HNM.current_network && (HNM.current_network in using_map.station_networks) && prob(0.1)) if(prob(0.1))
if(ntnet_global.intrusion_detection_enabled) if(ntnet_global.intrusion_detection_enabled)
ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network [HNM.current_network] by device with NID [computer.network_card.get_network_tag()]") ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network by device with NID [computer.network_card.get_network_tag()]")
ntnet_global.intrusion_detection_alarm = 1 ntnet_global.intrusion_detection_alarm = 1
/datum/nano_module/camera_monitor/hacked
name = "Hacked Camera Monitoring Program"
//available_to_ai = FALSE
/datum/nano_module/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access)
return 1
// The hacked variant has access to all commonly used networks.
/datum/nano_module/camera_monitor/hacked/modify_networks_list(var/list/networks)
networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
return networks

View File

@@ -30,7 +30,7 @@
/datum/computer_file/program/camera_monitor /datum/computer_file/program/camera_monitor
filename = "cammon" filename = "cammon"
filedesc = "Camera Monitoring" filedesc = "Camera Monitoring"
nanomodule_path = /datum/nano_module/camera_monitor tguimodule_path = /datum/tgui_module/camera/ntos
program_icon_state = "cameras" program_icon_state = "cameras"
program_key_state = "generic_key" program_key_state = "generic_key"
program_menu_icon = "search" program_menu_icon = "search"
@@ -39,163 +39,11 @@
available_on_ntnet = 1 available_on_ntnet = 1
requires_ntnet = 1 requires_ntnet = 1
/datum/nano_module/camera_monitor
name = "Camera Monitoring program"
var/obj/machinery/camera/current_camera = null
var/current_network = null
/datum/nano_module/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
var/list/data = host.initial_data()
data["current_camera"] = current_camera ? current_camera.nano_structure() : null
data["current_network"] = current_network
var/list/all_networks[0]
for(var/network in using_map.station_networks)
if(can_access_network(user, get_camera_access(network), 1))
all_networks.Add(list(list(
"tag" = network,
"has_access" = 1
)))
for(var/network in using_map.secondary_networks)
if(can_access_network(user, get_camera_access(network), 0))
all_networks.Add(list(list(
"tag" = network,
"has_access" = 1
)))
all_networks = modify_networks_list(all_networks)
data["networks"] = all_networks
var/list/map_levels = using_map.get_map_levels(get_z(nano_host()), TRUE, om_range = DEFAULT_OVERMAP_RANGE)
if(current_network)
data["cameras"] = camera_repository.cameras_in_network(current_network, map_levels)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "mod_sec_camera.tmpl", "Camera Monitoring", 900, 800)
// ui.auto_update_layout = 1 // Disabled as with suit sensors monitor - breaks the UI map. Re-enable once it's fixed somehow.
ui.add_template("mapContent", "sec_camera_map_content.tmpl")
ui.add_template("mapHeader", "mod_sec_camera_map_header.tmpl")
ui.set_initial_data(data)
ui.open()
// Intended to be overriden by subtypes to manually add non-station networks to the list.
/datum/nano_module/camera_monitor/proc/modify_networks_list(var/list/networks)
return networks
/datum/nano_module/camera_monitor/proc/can_access_network(var/mob/user, var/network_access, var/station_network = 0)
// No access passed, or 0 which is considered no access requirement. Allow it.
if(!network_access)
return 1
if(station_network)
return check_access(user, network_access) || check_access(user, access_security) || check_access(user, access_heads)
else
return check_access(user, network_access)
/datum/nano_module/camera_monitor/Topic(href, href_list)
if(..())
return 1
if(href_list["switch_camera"])
var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras
if(!C)
return
if(!(current_network in C.network))
return
switch_to_camera(usr, C)
return 1
else if(href_list["switch_network"])
// Either security access, or access to the specific camera network's department is required in order to access the network.
if(can_access_network(usr, get_camera_access(href_list["switch_network"]), (href_list["switch_network"] in using_map.station_networks)))
current_network = href_list["switch_network"]
else
to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.")
return 1
else if(href_list["reset"])
reset_current()
usr.reset_view(current_camera)
return 1
/datum/nano_module/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
//don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
if(isAI(user))
var/mob/living/silicon/ai/A = user
// Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
if(!A.is_in_chassis())
return 0
A.eyeobj.setLoc(get_turf(C))
A.client.eye = A.eyeobj
return 1
set_current(C)
user.machine = nano_host()
user.reset_view(C)
return 1
/datum/nano_module/camera_monitor/proc/set_current(var/obj/machinery/camera/C)
if(current_camera == C)
return
if(current_camera)
reset_current()
current_camera = C
if(current_camera)
var/mob/living/L = current_camera.loc
if(istype(L))
L.tracking_initiated()
/datum/nano_module/camera_monitor/proc/reset_current()
if(current_camera)
var/mob/living/L = current_camera.loc
if(istype(L))
L.tracking_cancelled()
current_camera = null
/datum/nano_module/camera_monitor/check_eye(var/mob/user as mob)
if(!current_camera)
return 0
var/viewflag = current_camera.check_eye(user)
if ( viewflag < 0 ) //camera doesn't work
reset_current()
return viewflag
// ERT Variant of the program // ERT Variant of the program
/datum/computer_file/program/camera_monitor/ert /datum/computer_file/program/camera_monitor/ert
filename = "ntcammon" filename = "ntcammon"
filedesc = "Advanced Camera Monitoring" filedesc = "Advanced Camera Monitoring"
extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys." extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys."
size = 14 size = 14
nanomodule_path = /datum/nano_module/camera_monitor/ert tguimodule_path = /datum/tgui_module/camera/ntos/ert
available_on_ntnet = 0 available_on_ntnet = 0
/datum/nano_module/camera_monitor/ert
name = "Advanced Camera Monitoring Program"
//available_to_ai = FALSE
// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it.
/datum/nano_module/camera_monitor/ert/modify_networks_list(var/list/networks)
..()
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
return networks
/datum/nano_module/camera_monitor/apply_visual(mob/M)
if(current_camera)
current_camera.apply_visual(M)
else
remove_visual(M)
/datum/nano_module/camera_monitor/remove_visual(mob/M)
if(current_camera)
current_camera.remove_visual(M)

View File

@@ -1,7 +1,7 @@
/datum/computer_file/program/suit_sensors /datum/computer_file/program/suit_sensors
filename = "sensormonitor" filename = "sensormonitor"
filedesc = "Suit Sensors Monitoring" filedesc = "Suit Sensors Monitoring"
nanomodule_path = /datum/nano_module/program/crew_monitor tguimodule_path = /datum/tgui_module/crew_monitor/ntos
program_icon_state = "crew" program_icon_state = "crew"
program_key_state = "med_key" program_key_state = "med_key"
program_menu_icon = "heart" program_menu_icon = "heart"
@@ -10,68 +10,3 @@
requires_ntnet = 1 requires_ntnet = 1
network_destination = "crew lifesigns monitoring system" network_destination = "crew lifesigns monitoring system"
size = 11 size = 11
/datum/nano_module/program/crew_monitor
name = "Crew monitor"
/datum/nano_module/program/crew_monitor/Topic(href, href_list)
if(..()) return 1
var/turf/T = get_turf(nano_host()) // TODO: Allow setting any using_map.contact_levels from the interface.
if (!T || !(T.z in using_map.player_levels))
to_chat(usr, "<span class='warning'>Unable to establish a connection</span>: You're too far away from the station!")
return 0
if(href_list["track"])
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
var/mob/living/carbon/human/H = locate(href_list["track"]) in mob_list
if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
AI.ai_actual_track(H)
return 1
/datum/nano_module/program/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
var/list/data = host.initial_data()
data["isAI"] = isAI(user)
var/z = get_z(nano_host())
var/list/map_levels = using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)
data["map_levels"] = map_levels
data["crewmembers"] = list()
for(var/zlevel in map_levels)
data["crewmembers"] += crew_repository.health_data(zlevel)
if(!data["map_levels"].len)
to_chat(user, "<span class='warning'>The crew monitor doesn't seem like it'll work here.</span>")
if(program)
program.kill_program()
if(ui)
ui.close()
return
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800, state = state)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
if(!(ui.map_z_level in data["map_levels"]))
ui.set_map_z_level(data["map_levels"][1])
ui.set_initial_data(data)
ui.open()
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
/*/datum/nano_module/program/crew_monitor/proc/scan()
for(var/mob/living/carbon/human/H in mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if (C.has_sensor)
tracked |= C
return 1
*/

View File

@@ -5,7 +5,7 @@
access = access_medical access = access_medical
cost = 625 cost = 625
p_drain = 0.025 p_drain = 0.025
var/datum/nano_module/program/crew_monitor/arscreen var/datum/tgui_module/crew_monitor/nif/arscreen
New() New()
..() ..()
@@ -17,7 +17,7 @@
activate() activate()
if((. = ..())) if((. = ..()))
arscreen.ui_interact(nif.human,"main",null,1,nif_state) arscreen.tgui_interact(nif.human)
return TRUE return TRUE
deactivate() deactivate()

View File

@@ -212,7 +212,6 @@
// leave the disposal // leave the disposal
/obj/machinery/disposal/proc/go_out(mob/user) /obj/machinery/disposal/proc/go_out(mob/user)
if (user.client) if (user.client)
user.client.eye = user.client.mob user.client.eye = user.client.mob
user.client.perspective = MOB_PERSPECTIVE user.client.perspective = MOB_PERSPECTIVE
@@ -222,11 +221,11 @@
// ai as human but can't flush // ai as human but can't flush
/obj/machinery/disposal/attack_ai(mob/user as mob) /obj/machinery/disposal/attack_ai(mob/user as mob)
interact(user, 1) add_hiddenprint(user)
tgui_interact(user)
// human interact with machine // human interact with machine
/obj/machinery/disposal/attack_hand(mob/user as mob) /obj/machinery/disposal/attack_hand(mob/user as mob)
if(stat & BROKEN) if(stat & BROKEN)
return return
@@ -236,91 +235,147 @@
// Clumsy folks can only flush it. // Clumsy folks can only flush it.
if(user.IsAdvancedToolUser(1)) if(user.IsAdvancedToolUser(1))
interact(user, 0) tgui_interact(user)
else else
flush = !flush flush = !flush
update() update()
return return
// user interaction // user interaction
/obj/machinery/disposal/interact(mob/user, var/ai=0) /obj/machinery/disposal/tgui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "DisposalBin")
ui.open()
src.add_fingerprint(user) /obj/machinery/disposal/tgui_data(mob/user)
if(stat & BROKEN) var/list/data = list()
user.unset_machine()
return
var/dat = "<head><title>Waste Disposal Unit</title></head><body><TT><B>Waste Disposal Unit</B><HR>" data["isAI"] = isAI(user)
data["flushing"] = flush
data["mode"] = mode
data["pressure"] = round(clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100),1)
if(!ai) // AI can't pull flush handle return data
if(flush)
dat += "Disposal handle: <A href='?src=\ref[src];handle=0'>Disengage</A> <B>Engaged</B>"
else
dat += "Disposal handle: <B>Disengaged</B> <A href='?src=\ref[src];handle=1'>Engage</A>"
dat += "<BR><HR><A href='?src=\ref[src];eject=1'>Eject contents</A><HR>" /obj/machinery/disposal/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(mode <= 0)
dat += "Pump: <B>Off</B> <A href='?src=\ref[src];pump=1'>On</A><BR>"
else if(mode == 1)
dat += "Pump: <A href='?src=\ref[src];pump=0'>Off</A> <B>On</B> (pressurizing)<BR>"
else
dat += "Pump: <A href='?src=\ref[src];pump=0'>Off</A> <B>On</B> (idle)<BR>"
var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE)
dat += "Pressure: [round(per, 1)]%<BR></body>"
user.set_machine(src)
user << browse(dat, "window=disposal;size=360x170")
onclose(user, "disposal")
// handle machine interaction
/obj/machinery/disposal/Topic(href, href_list)
if(usr.loc == src)
to_chat(usr, "<font color='red'>You cannot reach the controls from inside.</font>")
return
if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
to_chat(usr, "<font color='red'>The disposal units power is disabled.</font>")
return
if(..()) if(..())
return return
if(usr.loc == src)
to_chat(usr, "<span class='warning'>You cannot reach the controls from inside.</span>")
return
if(mode==-1 && action != "eject") // If the mode is -1, only allow ejection
to_chat(usr, "<span class='warning'>The disposal units power is disabled.</span>")
return
if(stat & BROKEN) if(stat & BROKEN)
return return
if(usr.stat || usr.restrained() || src.flushing)
add_fingerprint(usr)
if(flushing)
return return
if(istype(src.loc, /turf)) if(isturf(loc))
usr.set_machine(src) if(action == "pumpOn")
if(href_list["close"])
usr.unset_machine()
usr << browse(null, "window=disposal")
return
if(href_list["pump"])
if(text2num(href_list["pump"]))
mode = 1 mode = 1
else update()
if(action == "pumpOff")
mode = 0 mode = 0
update() update()
if(!isAI(usr)) if(!issilicon(usr))
if(href_list["handle"]) if(action == "engageHandle")
flush = text2num(href_list["handle"]) flush = 1
update()
if(action == "disengageHandle")
flush = 0
update() update()
if(href_list["eject"]) if(action == "eject")
eject() eject()
else
usr << browse(null, "window=disposal") return TRUE
usr.unset_machine()
return
return // src.add_fingerprint(user)
// if(stat & BROKEN)
// user.unset_machine()
// return
// var/dat = "<head><title>Waste Disposal Unit</title></head><body><TT><B>Waste Disposal Unit</B><HR>"
// if(!ai) // AI can't pull flush handle
// if(flush)
// dat += "Disposal handle: <A href='?src=\ref[src];handle=0'>Disengage</A> <B>Engaged</B>"
// else
// dat += "Disposal handle: <B>Disengaged</B> <A href='?src=\ref[src];handle=1'>Engage</A>"
// dat += "<BR><HR><A href='?src=\ref[src];eject=1'>Eject contents</A><HR>"
// if(mode <= 0)
// dat += "Pump: <B>Off</B> <A href='?src=\ref[src];pump=1'>On</A><BR>"
// else if(mode == 1)
// dat += "Pump: <A href='?src=\ref[src];pump=0'>Off</A> <B>On</B> (pressurizing)<BR>"
// else
// dat += "Pump: <A href='?src=\ref[src];pump=0'>Off</A> <B>On</B> (idle)<BR>"
// var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE)
// dat += "Pressure: [round(per, 1)]%<BR></body>"
// user.set_machine(src)
// user << browse(dat, "window=disposal;size=360x170")
// onclose(user, "disposal")
// handle machine interaction
// /obj/machinery/disposal/Topic(href, href_list)
// if(usr.loc == src)
// to_chat(usr, "<font color='red'>You cannot reach the controls from inside.</font>")
// return
// if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
// to_chat(usr, "<font color='red'>The disposal units power is disabled.</font>")
// return
// if(..())
// return
// if(stat & BROKEN)
// return
// if(usr.stat || usr.restrained() || src.flushing)
// return
// if(istype(src.loc, /turf))
// usr.set_machine(src)
// if(href_list["close"])
// usr.unset_machine()
// usr << browse(null, "window=disposal")
// return
// if(href_list["pump"])
// if(text2num(href_list["pump"]))
// mode = 1
// else
// mode = 0
// update()
// if(!isAI(usr))
// if(href_list["handle"])
// flush = text2num(href_list["handle"])
// update()
// if(href_list["eject"])
// eject()
// else
// usr << browse(null, "window=disposal")
// usr.unset_machine()
// return
// return
// eject the contents of the disposal unit // eject the contents of the disposal unit
/obj/machinery/disposal/proc/eject() /obj/machinery/disposal/proc/eject()

View File

@@ -0,0 +1,191 @@
/**
* tgui external
*
* Contains all external tgui declarations.
*/
/**
* public
*
* Used to open and update UIs.
* If this proc is not implemented properly, the UI will not update correctly.
*
* required user mob The mob who opened/is using the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
*/
/datum/proc/tgui_interact(mob/user, datum/tgui/ui = null)
return FALSE // Not implemented.
/**
* public
*
* Data to be sent to the UI.
* This must be implemented for a UI to work.
*
* required user mob The mob interacting with the UI.
*
* return list Data to be sent to the UI.
*/
/datum/proc/tgui_data(mob/user)
return list() // Not implemented.
/**
* public
*
* Static Data to be sent to the UI.
* Static data differs from normal data in that it's large data that should be
* sent infrequently. This is implemented optionally for heavy uis that would
* be sending a lot of redundant data frequently. Gets squished into one
* object on the frontend side, but the static part is cached.
*
* required user mob The mob interacting with the UI.
*
* return list Statuic Data to be sent to the UI.
*/
/datum/proc/tgui_static_data(mob/user)
return list()
/**
* public
*
* Forces an update on static data. Should be done manually whenever something
* happens to change static data.
*
* required user the mob currently interacting with the ui
* optional ui ui to be updated
*/
/datum/proc/update_tgui_static_data(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
// If there was no ui to update, there's no static data to update either.
if(!ui)
ui = SStgui.get_open_ui(user, src)
if(ui)
ui.send_full_update()
/**
* public
*
* Called on a UI when the UI receieves a href.
* Think of this as Topic().
*
* required action string The action/button that has been invoked by the user.
* required params list A list of parameters attached to the button.
*
* return bool If the UI should be updated or not.
*/
/datum/proc/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
// If UI is not interactive or usr calling Topic is not the UI user, bail.
if(!ui || ui.status != STATUS_INTERACTIVE)
return TRUE
/**
* public
*
* Called on an object when a tgui object is being created, allowing you to
* push various assets to tgui, for examples spritesheets.
*
* return list List of asset datums or file paths.
*/
/datum/proc/ui_assets(mob/user)
return list()
/**
* private
*
* The UI's host object (usually src_object).
* This allows modules/datums to have the UI attached to them,
* and be a part of another object.
*/
/datum/proc/tgui_host(mob/user)
return src // Default src.
/**
* private
*
* The UI's state controller to be used for created uis
* This is a proc over a var for memory reasons
*/
/datum/proc/tgui_state(mob/user)
return GLOB.tgui_default_state
/**
* global
*
* Associative list of JSON-encoded shared states that were set by
* tgui clients.
*/
/datum/var/list/tgui_shared_states
/**
* global
*
* Tracks open UIs for a user.
*/
/mob/var/list/tgui_open_uis = list()
/**
* global
*
* Tracks open windows for a user.
*/
/client/var/list/tgui_windows = list()
/**
* public
*
* Called on a UI's object when the UI is closed, not to be confused with
* client/verb/uiclose(), which closes the ui window
*/
/datum/proc/tgui_close(mob/user)
/**
* verb
*
* Called by UIs when they are closed.
* Must be a verb so winset() can call it.
*
* required uiref ref The UI that was closed.
*/
/client/verb/tguiclose(window_id as text)
// Name the verb, and hide it from the user panel.
set name = "uiclose"
set hidden = TRUE
var/mob/user = src && src.mob
if(!user)
return
// Close all tgui datums based on window_id.
SStgui.force_close_window(user, window_id)
/**
* Middleware for /client/Topic.
*
* return bool Whether the topic is passed (TRUE), or cancelled (FALSE).
*/
/proc/tgui_Topic(href_list)
// Skip non-tgui topics
if(!href_list["tgui"])
return TRUE
var/type = href_list["type"]
// Unconditionally collect tgui logs
if(type == "log")
log_tgui(usr, href_list["message"])
// Locate window
var/window_id = href_list["window_id"]
var/datum/tgui_window/window
if(window_id)
window = usr.client.tgui_windows[window_id]
if(!window)
log_tgui(usr, "Error: Couldn't find the window datum, force closing.")
SStgui.force_close_window(usr, window_id)
return FALSE
// Decode payload
var/payload
if(href_list["payload"])
payload = json_decode(href_list["payload"])
// Pass message to window
if(window)
window.on_message(type, payload, href_list)
return FALSE

View File

@@ -0,0 +1,46 @@
/*
TGUI MODULES
This allows for datum-based TGUIs that can be hooked into objects.
This is useful for things such as the power monitor, which needs to exist on a physical console in the world, but also as a virtual device the AI can use
Code is pretty much ripped verbatim from nano modules, but with un-needed stuff removed
*/
/datum/tgui_module
var/name
var/datum/host
var/list/using_access
var/tgui_id
/datum/tgui_module/New(var/host)
src.host = host
/datum/tgui_module/tgui_host()
return host ? host : src
/datum/tgui_module/tgui_close(mob/user)
if(host)
host.tgui_close(user)
/datum/tgui_module/proc/check_access(mob/user, access)
if(!access)
return 1
if(using_access)
if(access in using_access)
return 1
else
return 0
if(!istype(user))
return 0
var/obj/item/weapon/card/id/I = user.GetIdCard()
if(!I)
return 0
if(access in I.access)
return 1
return 0

View File

@@ -0,0 +1,295 @@
/datum/tgui_module/camera
name = "Security Cameras"
tgui_id = "CameraConsole"
var/access_based = FALSE
var/list/network = list()
var/list/additional_networks = list()
var/obj/machinery/camera/active_camera
var/list/concurrent_users = list()
// Stuff needed to render the map
var/map_name
var/const/default_map_size = 15
var/obj/screen/map_view/cam_screen
/// All the plane masters that need to be applied.
var/list/cam_plane_masters
var/obj/screen/background/cam_background
var/obj/screen/background/cam_foreground
var/obj/screen/skybox/local_skybox
// Needed for moving camera support
var/camera_diff_x = -1
var/camera_diff_y = -1
var/camera_diff_z = -1
/datum/tgui_module/camera/New(host, list/network_computer)
. = ..()
if(!LAZYLEN(network_computer))
access_based = TRUE
else
network = network_computer
map_name = "camera_console_[REF(src)]_map"
// Initialize map objects
cam_screen = new
cam_screen.name = "screen"
cam_screen.assigned_map = map_name
cam_screen.del_on_map_removal = FALSE
cam_screen.screen_loc = "[map_name]:1,1"
cam_plane_masters = list()
for(var/plane in subtypesof(/obj/screen/plane_master))
var/obj/screen/instance = new plane()
instance.assigned_map = map_name
instance.del_on_map_removal = FALSE
instance.screen_loc = "[map_name]:CENTER"
cam_plane_masters += instance
local_skybox = new()
local_skybox.assigned_map = map_name
local_skybox.del_on_map_removal = FALSE
local_skybox.screen_loc = "[map_name]:CENTER,CENTER"
cam_plane_masters += local_skybox
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE
var/mutable_appearance/scanlines = mutable_appearance('icons/effects/static.dmi', "scanlines")
scanlines.alpha = 50
scanlines.layer = FULLSCREEN_LAYER
var/mutable_appearance/noise = mutable_appearance('icons/effects/static.dmi', "1 light")
noise.layer = FULLSCREEN_LAYER
cam_foreground = new
cam_foreground.assigned_map = map_name
cam_foreground.del_on_map_removal = FALSE
cam_foreground.plane = PLANE_FULLSCREEN
cam_foreground.add_overlay(scanlines)
cam_foreground.add_overlay(noise)
/datum/tgui_module/camera/Destroy()
qdel(cam_screen)
QDEL_LIST(cam_plane_masters)
qdel(cam_background)
qdel(cam_foreground)
return ..()
/datum/tgui_module/camera/tgui_interact(mob/user, datum/tgui/ui = null)
// Update UI
ui = SStgui.try_update_ui(user, src, ui)
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
if(!ui)
var/user_ref = REF(user)
var/is_living = isliving(user)
// Ghosts shouldn't count towards concurrent users, which produces
// an audible terminal_on click.
if(is_living)
concurrent_users += user_ref
// Turn on the console
if(length(concurrent_users) == 1 && is_living)
playsound(tgui_host(), 'sound/machines/terminal_on.ogg', 25, FALSE)
// Register map objects
user.client.register_map_obj(cam_screen)
for(var/plane in cam_plane_masters)
user.client.register_map_obj(plane)
user.client.register_map_obj(cam_background)
user.client.register_map_obj(cam_foreground)
// Open UI
ui = new(user, src, tgui_id, name)
ui.open()
/datum/tgui_module/camera/tgui_data()
var/list/data = list()
data["activeCamera"] = null
if(active_camera)
differential_check()
data["activeCamera"] = list(
name = active_camera.c_tag,
status = active_camera.status,
)
return data
/datum/tgui_module/camera/tgui_static_data(mob/user)
var/list/data = list()
data["mapRef"] = map_name
var/list/cameras = get_available_cameras(user)
data["cameras"] = list()
data["allNetworks"] = list()
for(var/i in cameras)
var/obj/machinery/camera/C = cameras[i]
data["cameras"] += list(list(
name = C.c_tag,
networks = C.network
))
data["allNetworks"] |= C.network
return data
/datum/tgui_module/camera/tgui_act(action, params)
if(..())
return
if(action == "switch_camera")
var/c_tag = params["name"]
var/list/cameras = get_available_cameras(usr)
var/obj/machinery/camera/C = cameras["[ckey(c_tag)]"]
active_camera = C
playsound(tgui_host(), get_sfx("terminal_type"), 25, FALSE)
reload_cameraview()
return TRUE
/datum/tgui_module/camera/proc/differential_check()
var/turf/T = get_turf(active_camera)
if(T)
var/new_x = T.x
var/new_y = T.y
var/new_z = T.z
if((new_x != camera_diff_x) || (new_y != camera_diff_y) || (new_z != camera_diff_z))
reload_cameraview()
/datum/tgui_module/camera/proc/reload_cameraview()
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
return TRUE
var/turf/camTurf = get_turf(active_camera)
camera_diff_x = camTurf.x
camera_diff_y = camTurf.y
camera_diff_z = camTurf.z
var/list/visible_turfs = list()
for(var/turf/T in (active_camera.isXRay() \
? range(active_camera.view_range, camTurf) \
: view(active_camera.view_range, camTurf)))
visible_turfs += T
var/list/bbox = get_bbox_of_atoms(visible_turfs)
var/size_x = bbox[3] - bbox[1] + 1
var/size_y = bbox[4] - bbox[2] + 1
cam_screen.vis_contents = visible_turfs
cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, size_x, size_y)
cam_foreground.fill_rect(1, 1, size_x, size_y)
local_skybox.cut_overlays()
local_skybox.add_overlay(SSskybox.get_skybox(get_z(camTurf)))
local_skybox.scale_to_view(size_x)
local_skybox.set_position("CENTER", "CENTER", (world.maxx>>1) - camTurf.x, (world.maxy>>1) - camTurf.y)
// Returns the list of cameras accessible from this computer
// This proc operates in two distinct ways depending on the context in which the module is created.
// It can either return a list of cameras sharing the same the internal `network` variable, or
// It can scan all station networks and determine what cameras to show based on the access of the user.
/datum/tgui_module/camera/proc/get_available_cameras(mob/user)
var/list/all_networks = list()
// Access Based
if(access_based)
for(var/network in using_map.station_networks)
if(can_access_network(user, get_camera_access(network), 1))
all_networks.Add(network)
for(var/network in using_map.secondary_networks)
if(can_access_network(user, get_camera_access(network), 0))
all_networks.Add(network)
// Network Based
else
all_networks = network.Copy()
if(additional_networks)
all_networks += additional_networks
var/list/D = list()
for(var/obj/machinery/camera/C in cameranet.cameras)
if(!C.network)
stack_trace("Camera in a cameranet has no camera network")
continue
if(!(islist(C.network)))
stack_trace("Camera in a cameranet has a non-list camera network")
continue
var/list/tempnetwork = C.network & all_networks
if(tempnetwork.len)
D["[ckey(C.c_tag)]"] = C
return D
/datum/tgui_module/camera/proc/can_access_network(mob/user, network_access, station_network = 0)
// No access passed, or 0 which is considered no access requirement. Allow it.
if(!network_access)
return 1
if(station_network)
return check_access(user, network_access) || check_access(user, access_security) || check_access(user, access_heads)
else
return check_access(user, network_access)
/datum/tgui_module/camera/proc/show_camera_static()
cam_screen.vis_contents.Cut()
cam_background.icon_state = "scanline2"
cam_background.fill_rect(1, 1, default_map_size, default_map_size)
local_skybox.cut_overlays()
/datum/tgui_module/camera/tgui_close(mob/user)
. = ..()
var/user_ref = REF(user)
var/is_living = isliving(user)
// living creature or not, we remove you anyway.
concurrent_users -= user_ref
// Unregister map objects
if(user.client)
user.client.clear_map(map_name)
// Turn off the console
if(length(concurrent_users) == 0 && is_living)
active_camera = null
playsound(tgui_host(), 'sound/machines/terminal_off.ogg', 25, FALSE)
// NTOS Version
// Please note, this isn't a very good replacement for converting modular computers 100% to TGUI
// If/when that is done, just move all the PC_ specific data and stuff to the modular computers themselves
// instead of copying this approach here.
/datum/tgui_module/camera/ntos
tgui_id = "NtosCameraConsole"
/datum/tgui_module/camera/ntos/tgui_state()
return GLOB.tgui_ntos_state
/datum/tgui_module/camera/ntos/tgui_static_data()
. = ..()
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
. += host.computer.get_header_data()
/datum/tgui_module/camera/ntos/tgui_act(action, params)
if(..())
return
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
if(action == "PC_exit")
host.computer.kill_program()
return TRUE
if(action == "PC_shutdown")
host.computer.shutdown_computer()
return TRUE
if(action == "PC_minimize")
host.computer.minimize_program(usr)
return TRUE
// ERT Version provides some additional networks.
/datum/tgui_module/camera/ntos/ert
additional_networks = list(NETWORK_ERT, NETWORK_CRESCENT)
// Hacked version also provides some additional networks,
// but we want it to show *all* the networks 24/7, so we convert it into a non-access-based UI.
/datum/tgui_module/camera/ntos/hacked
additional_networks = list(NETWORK_MERCENARY, NETWORK_ERT, NETWORK_CRESCENT)
/datum/tgui_module/camera/ntos/hacked/New(host)
. = ..(host, using_map.station_networks.Copy())

View File

@@ -0,0 +1,100 @@
/datum/tgui_module/crew_monitor
name = "Crew monitor"
tgui_id = "CrewMonitor"
/datum/tgui_module/crew_monitor/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
var/turf/T = get_turf(usr)
if(!T || !(T.z in using_map.player_levels))
to_chat(usr, "<span class='warning'><b>Unable to establish a connection</b>: You're too far away from the station!</span>")
return FALSE
switch(action)
if("track")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
var/mob/living/carbon/human/H = locate(params["track"]) in mob_list
if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
AI.ai_actual_track(H)
return TRUE
if("setZLevel")
ui.set_map_z_level(params["mapZLevel"])
SStgui.update_uis(src)
/datum/tgui_module/crew_monitor/tgui_interact(mob/user, datum/tgui/ui = null)
var/z = get_z(user)
var/list/map_levels = using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)
if(!map_levels.len)
to_chat(user, "<span class='warning'>The crew monitor doesn't seem like it'll work here.</span>")
if(ui)
ui.close()
return null
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, tgui_id, name)
ui.autoupdate = TRUE
ui.open()
/datum/tgui_module/crew_monitor/tgui_data(mob/user, ui_key = "main", datum/tgui_state/state = GLOB.tgui_default_state)
var/data[0]
data["isAI"] = isAI(user)
var/z = get_z(user)
var/list/map_levels = uniquelist(using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE))
data["map_levels"] = map_levels
data["crewmembers"] = list()
for(var/zlevel in map_levels)
data["crewmembers"] += crew_repository.health_data(zlevel)
return data
/datum/tgui_module/crew_monitor/ntos
tgui_id = "NtosCrewMonitor"
/datum/tgui_module/crew_monitor/ntos/tgui_state(mob/user)
return GLOB.tgui_ntos_state
/datum/tgui_module/crew_monitor/ntos/tgui_static_data()
. = ..()
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
. += host.computer.get_header_data()
/datum/tgui_module/crew_monitor/ntos/tgui_act(action, params)
if(..())
return
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
if(action == "PC_exit")
host.computer.kill_program()
return TRUE
if(action == "PC_shutdown")
host.computer.shutdown_computer()
return TRUE
if(action == "PC_minimize")
host.computer.minimize_program(usr)
return TRUE
// Subtype for glasses_state
/datum/tgui_module/crew_monitor/glasses
/datum/tgui_module/crew_monitor/glasses/tgui_state(mob/user)
return GLOB.tgui_glasses_state
// Subtype for self_state
/datum/tgui_module/crew_monitor/robot
/datum/tgui_module/crew_monitor/robot/tgui_state(mob/user)
return GLOB.tgui_self_state
// Subtype for nif_state
/datum/tgui_module/crew_monitor/nif
/datum/tgui_module/crew_monitor/nif/tgui_state(mob/user)
return GLOB.tgui_nif_state

125
code/modules/tgui/states.dm Normal file
View File

@@ -0,0 +1,125 @@
/**
* Base state and helpers for states. Just does some sanity checks,
* implement a proper state for in-depth checks.
*/
/**
* public
*
* Checks the UI state for a mob.
*
* required user mob The mob who opened/is using the UI.
* required state datum/ui_state The state to check.
*
* return UI_state The state of the UI.
*/
/datum/proc/tgui_status(mob/user, datum/tgui_state/state)
var/src_object = tgui_host(user)
. = STATUS_CLOSE
if(!state)
return
if(isobserver(user))
// // If they turn on ghost AI control, admins can always interact.
// if(user.client.advanced_admin_interaction)
// . = max(., STATUS_INTERACTIVE)
// Regular ghosts can always at least view if in range.
if(user.client)
var/clientviewlist = getviewsize(user.client.view)
if(get_dist(src_object, user) < max(clientviewlist[1], clientviewlist[2]))
. = max(., STATUS_UPDATE)
// Check if the state allows interaction
var/result = state.can_use_topic(src_object, user)
. = max(., result)
/**
* private
*
* Checks if a user can use src_object's UI, and returns the state.
* Can call a mob proc, which allows overrides for each mob.
*
* required src_object datum The object/datum which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/datum/tgui_state/proc/can_use_topic(src_object, mob/user)
// Don't allow interaction by default.
return STATUS_CLOSE
/**
* public
*
* Standard interaction/sanity checks. Different mob types may have overrides.
*
* return UI_state The state of the UI.
*/
/mob/proc/shared_tgui_interaction(src_object)
// Close UIs if mindless.
if(!client)
return STATUS_CLOSE
// Disable UIs if unconcious.
else if(stat)
return STATUS_DISABLED
// Update UIs if incapicitated but concious.
else if(incapacitated())
return STATUS_UPDATE
return STATUS_INTERACTIVE
/mob/living/silicon/ai/shared_tgui_interaction(src_object)
// Disable UIs if the AI is unpowered.
if(lacks_power())
return STATUS_DISABLED
return ..()
/mob/living/silicon/robot/shared_tgui_interaction(src_object)
// Disable UIs if the Borg is unpowered or locked.
if(!cell || cell.charge <= 0 || lockcharge)
return STATUS_DISABLED
return ..()
/**
* public
*
* Check the distance for a living mob.
* Really only used for checks outside the context of a mob.
* Otherwise, use shared_living_ui_distance().
*
* required src_object The object which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/atom/proc/contents_tgui_distance(src_object, mob/living/user)
// Just call this mob's check.
return user.shared_living_tgui_distance(src_object)
/**
* public
*
* Distance versus interaction check.
*
* required src_object atom/movable The object which owns the UI.
*
* return UI_state The state of the UI.
*/
/mob/living/proc/shared_living_tgui_distance(atom/movable/src_object, viewcheck = TRUE)
// If the object is obscured, close it.
if(viewcheck && !(src_object in view(src)))
return STATUS_CLOSE
var/dist = get_dist(src_object, src)
if(dist <= 1) // Open and interact if 1-0 tiles away.
return STATUS_INTERACTIVE
else if(dist <= 2) // View only if 2-3 tiles away.
return STATUS_UPDATE
else if(dist <= 5) // Disable if 5 tiles away.
return STATUS_DISABLED
return STATUS_CLOSE // Otherwise, we got nothing.
/mob/living/carbon/human/shared_living_tgui_distance(atom/movable/src_object)
if((TK in mutations) && (get_dist(src, src_object) <= 2))
return STATUS_INTERACTIVE
return ..()

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