diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm
index 6559f28f26..6bd32c762c 100644
--- a/code/ATMOSPHERICS/atmospherics.dm
+++ b/code/ATMOSPHERICS/atmospherics.dm
@@ -48,6 +48,9 @@ Pipelines + Other Objects -> Pipe network
pipe_color = null
init_dir()
+/obj/machinery/atmospherics/examine_icon()
+ return icon(icon=initial(icon),icon_state=initial(icon_state))
+
// This is used to set up what directions pipes will connect to. Should be called inside New() and whenever a dir changes.
/obj/machinery/atmospherics/proc/init_dir()
return
diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm
index b4c1e30fba..2c53c47583 100644
--- a/code/ATMOSPHERICS/components/unary/cold_sink.dm
+++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm
@@ -21,15 +21,9 @@
var/set_temperature = T20C // Thermostat
var/cooling = 0
-/obj/machinery/atmospherics/unary/freezer/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- RefreshParts()
+/obj/machinery/atmospherics/unary/freezer/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/atmospherics/unary/freezer/atmos_init()
if(node)
diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm
index 3537082ada..c91ef281f3 100644
--- a/code/ATMOSPHERICS/components/unary/heat_source.dm
+++ b/code/ATMOSPHERICS/components/unary/heat_source.dm
@@ -21,15 +21,9 @@
var/set_temperature = T20C //thermostat
var/heating = 0 //mainly for icon updates
-/obj/machinery/atmospherics/unary/heater/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/stack/cable_coil(src, 5)
-
- RefreshParts()
+/obj/machinery/atmospherics/unary/heater/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/atmospherics/unary/heater/atmos_init()
if(node)
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 079715550e..4db75508b3 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -378,3 +378,8 @@ var/global/list/##LIST_NAME = list();\
// Used by radios to indicate that they have sent a message via something other than subspace
#define RADIO_CONNECTION_FAIL 0
#define RADIO_CONNECTION_NON_SUBSPACE 1
+
+#define JOB_CARBON 0x1
+#define JOB_SILICON_ROBOT 0x2
+#define JOB_SILICON_AI 0x4
+#define JOB_SILICON 0x6 // 2|4, probably don't set jobs to this, but good for checking
diff --git a/code/__defines/preferences.dm b/code/__defines/preferences.dm
index 0bb289d2e1..880d9318d8 100644
--- a/code/__defines/preferences.dm
+++ b/code/__defines/preferences.dm
@@ -1,6 +1,15 @@
+// Modes for examine text output
#define EXAMINE_MODE_DEFAULT 0
#define EXAMINE_MODE_INCLUDE_USAGE 1
#define EXAMINE_MODE_SWITCH_TO_PANEL 2
// Should be one higher than the above
-#define EXAMINE_MODE_MAX 3
\ No newline at end of file
+#define EXAMINE_MODE_MAX 3
+
+// Modes for parsing multilingual speech
+#define MULTILINGUAL_DEFAULT 0
+#define MULTILINGUAL_SPACE 1
+#define MULTILINGUAL_DOUBLE_DELIMITER 2
+#define MULTILINGUAL_OFF 3
+
+#define MULTILINGUAL_MODE_MAX 4
\ No newline at end of file
diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index 03724307c6..5a1806805b 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -54,7 +54,7 @@
#define LANGUAGE_AKHANI "Akhani"
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_ZADDAT "Vedahq"
-#define LANGUAGE_PROMETHEAN "Promethean"
+#define LANGUAGE_PROMETHEAN "Promethean Biolinguistics"
#define LANGUAGE_BLOB "Blob"
#define LANGUAGE_GIBBERISH "Babel"
diff --git a/code/__defines/tgs.config.dm b/code/__defines/tgs.config.dm
new file mode 100644
index 0000000000..1ae6593419
--- /dev/null
+++ b/code/__defines/tgs.config.dm
@@ -0,0 +1,12 @@
+#define TGS_EXTERNAL_CONFIGURATION
+#define TGS_V3_API
+#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name)
+#define TGS_READ_GLOBAL(Name) GLOB.##Name
+#define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
+#define TGS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]")
+#define TGS_INFO_LOG(message) log_to_dd("TGS Info: [##message]")
+#define TGS_WARNING_LOG(message) log_to_dd("TGS Warn: [##message]")
+#define TGS_ERROR_LOG(message) log_to_dd("TGS Error: [##message]")
+#define TGS_NOTIFY_ADMINS(event) message_admins(##event)
+#define TGS_CLIENT_COUNT GLOB.clients.len
+#define TGS_PROTECT_DATUM(Path) GENERAL_PROTECT_DATUM(##Path)
diff --git a/code/__defines/tgs.dm b/code/__defines/tgs.dm
new file mode 100644
index 0000000000..4e152ad3cf
--- /dev/null
+++ b/code/__defines/tgs.dm
@@ -0,0 +1,273 @@
+//tgstation-server DMAPI
+
+#define TGS_DMAPI_VERSION "5.0.0"
+
+//All functions and datums outside this document are subject to change with any version and should not be relied on
+
+//CONFIGURATION
+
+//create this define if you want to do configuration outside of this file
+#ifndef TGS_EXTERNAL_CONFIGURATION
+
+//Comment this out once you've filled in the below
+#error TGS API unconfigured
+
+//Uncomment this if you wish to allow the game to interact with TGS 3
+//This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()()
+//#define TGS_V3_API
+
+//Required interfaces (fill in with your codebase equivalent):
+
+//create a global variable named `Name` and set it to `Value`
+#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value)
+
+//Read the value in the global variable `Name`
+#define TGS_READ_GLOBAL(Name)
+
+//Set the value in the global variable `Name` to `Value`
+#define TGS_WRITE_GLOBAL(Name, Value)
+
+//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game use of DD -> TGS capabilities
+#define TGS_PROTECT_DATUM(Path)
+
+//Display an announcement `message` from the server to all players
+#define TGS_WORLD_ANNOUNCE(message)
+
+//Notify current in-game administrators of a string `event`
+#define TGS_NOTIFY_ADMINS(event)
+
+//Write an info `message` to a server log
+#define TGS_INFO_LOG(message)
+
+//Write an warning `message` to a server log
+#define TGS_WARNING_LOG(message)
+
+//Write an error `message` to a server log
+#define TGS_ERROR_LOG(message)
+
+//Get the number of connected /clients
+#define TGS_CLIENT_COUNT
+
+#endif
+
+//EVENT CODES
+
+#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //Before a reboot mode change, extras parameters are the current and new reboot mode enums
+#define TGS_EVENT_PORT_SWAP -2 //Before a port change is about to happen, extra parameters is new port
+#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra prameter is the new name
+
+//See the descriptions for the parameters of these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
+#define TGS_EVENT_REPO_RESET_ORIGIN 0
+#define TGS_EVENT_REPO_CHECKOUT 1
+#define TGS_EVENT_REPO_FETCH 2
+#define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3
+#define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4
+#define TGS_EVENT_BYOND_INSTALL_START 5
+#define TGS_EVENT_BYOND_INSTALL_FAIL 6
+#define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7
+#define TGS_EVENT_COMPILE_START 8
+#define TGS_EVENT_COMPILE_CANCELLED 9
+#define TGS_EVENT_COMPILE_FAILURE 10
+#define TGS_EVENT_COMPILE_COMPLETE 11 // Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the TGS_EVENT_DEPLOYMENT_COMPLETE instead
+#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
+#define TGS_EVENT_DEPLOYMENT_COMPLETE 13
+
+//OTHER ENUMS
+
+#define TGS_REBOOT_MODE_NORMAL 0
+#define TGS_REBOOT_MODE_SHUTDOWN 1
+#define TGS_REBOOT_MODE_RESTART 2
+
+#define TGS_SECURITY_TRUSTED 0
+#define TGS_SECURITY_SAFE 1
+#define TGS_SECURITY_ULTRASAFE 2
+
+//REQUIRED HOOKS
+
+//Call this somewhere in /world/New() that is always run
+//IMPORTANT: This function may sleep! Other TGS functions will not succeed until it completes
+//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels
+//minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated
+/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
+ return
+
+//Call this when your initializations are complete and your game is ready to play before any player interactions happen
+//This may use world.sleep_offline to make this happen so ensure no changes are made to it while this call is running
+//Most importantly, before this point, note that any static files or directories may be in use by another server. Your code should account for this
+//This function should not be called before ..() in /world/New()
+/world/proc/TgsInitializationComplete()
+ return
+
+//Put this at the start of /world/Topic()
+#define TGS_TOPIC var/tgs_topic_return = TgsTopic(args[1]); if(tgs_topic_return) return tgs_topic_return
+
+//Call this at the beginning of world/Reboot(reason)
+/world/proc/TgsReboot()
+ return
+
+//DATUM DEFINITIONS
+//unless otherwise specified all datums defined here should be considered read-only, warranty void if written
+
+//represents git revision information about the current world build
+/datum/tgs_revision_information
+ var/commit //full sha of compiled commit
+ var/origin_commit //full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch
+
+//represents a version of tgstation-server
+/datum/tgs_version
+ var/suite //The suite/major version, can be >=3
+
+ //this group of variables can be null to represent a wild card
+ var/minor //The minor version
+ var/patch //The patch version
+ var/deprecated_patch //The legacy version
+
+ var/raw_parameter //The unparsed parameter
+ var/deprefixed_parameter //The version only bit of raw_parameter
+
+//if the tgs_version is a wildcard version
+/datum/tgs_version/proc/Wildcard()
+ return
+
+//if the tgs_version equals some other_version
+/datum/tgs_version/proc/Equals(datum/tgs_version/other_version)
+ return
+
+//represents a merge of a GitHub pull request
+/datum/tgs_revision_information/test_merge
+ var/number //pull request number
+ var/title //pull request title
+ var/body //pull request body
+ var/author //pull request github author
+ var/url //link to pull request html
+ var/pull_request_commit //commit of the pull request when it was merged
+ var/time_merged //timestamp of when the merge commit for the pull request was created
+ var/comment //optional comment left by the one who initiated the test merge
+
+//represents a connected chat channel
+/datum/tgs_chat_channel
+ var/id //internal channel representation
+ var/friendly_name //user friendly channel name
+ var/connection_name //the name of the configured chat connection
+ var/is_admin_channel //if the server operator has marked this channel for game admins only
+ var/is_private_channel //if this is a private chat channel
+ var/custom_tag //user defined string associated with channel
+
+//represents a chat user
+/datum/tgs_chat_user
+ var/id //Internal user representation, requires channel to be unique
+ var/friendly_name //The user's public name
+ var/mention //The text to use to ping this user in a message
+ var/datum/tgs_chat_channel/channel //The /datum/tgs_chat_channel this user was from
+
+//user definable callback for handling events
+//extra parameters may be specified depending on the event
+/datum/tgs_event_handler/proc/HandleEvent(event_code, ...)
+ set waitfor = FALSE
+ return
+
+//user definable chat command
+/datum/tgs_chat_command
+ var/name = "" //the string to trigger this command on a chat bot. e.g. TGS3_BOT: do_this_command
+ var/help_text = "" //help text for this command
+ var/admin_only = FALSE //set to TRUE if this command should only be usable by registered chat admins
+
+//override to implement command
+//sender: The tgs_chat_user who send to command
+//params: The trimmed string following the command name
+//The return value will be stringified and sent to the appropriate chat
+/datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params)
+ CRASH("[type] has no implementation for Run()")
+
+//FUNCTIONS
+
+//Returns the respective supported /datum/tgs_version of the API
+/world/proc/TgsMaximumAPIVersion()
+ return
+
+/world/proc/TgsMinimumAPIVersion()
+ return
+
+//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
+//No function below this succeeds if it returns FALSE or if TgsNew() has yet to be called
+/world/proc/TgsAvailable()
+ return
+
+//Gets the current /datum/tgs_version of the server tools running the server
+/world/proc/TgsVersion()
+ return
+
+//Gets the current /datum/tgs_version of the DMAPI being used
+/world/proc/TgsApiVersion()
+ return
+
+//Gets the name of the TGS instance running the game
+/world/proc/TgsInstanceName()
+ return
+
+//Get the current `/datum/tgs_revision_information`
+/world/proc/TgsRevision()
+ return
+
+//Get the current BYOND security level
+/world/proc/TgsSecurityLevel()
+ return
+
+//Gets a list of active `/datum/tgs_revision_information/test_merge`s
+/world/proc/TgsTestMerges()
+ return
+
+//Forces a hard reboot of BYOND by ending the process
+//unlike del(world) clients will try to reconnect
+//If the service has not requested a shutdown, the next server will take over
+/world/proc/TgsEndProcess()
+ return
+
+//Gets a list of connected tgs_chat_channel
+/world/proc/TgsChatChannelInfo()
+ return
+
+//Sends a message to connected game chats
+//message: The message to send
+//channels: optional channels to limit the broadcast to
+/world/proc/TgsChatBroadcast(message, list/channels)
+ return
+
+//Send a message to non-admin connected chats
+//message: The message to send
+//admin_only: If TRUE, message will instead be sent to only admin connected chats
+/world/proc/TgsTargetedChatBroadcast(message, admin_only)
+ return
+
+//Send a private message to a specific user
+//message: The message to send
+//user: The /datum/tgs_chat_user to send to
+/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
+ return
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm
index 5abedfe9ac..a199c88622 100644
--- a/code/_helpers/icons.dm
+++ b/code/_helpers/icons.dm
@@ -107,7 +107,7 @@ AngleToHue(hue)
Converts an angle to a hue in the valid range.
RotateHue(hsv, angle)
Takes an HSV or HSVA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360.
- (Rotating red by 60° produces yellow.) The result is another HSV or HSVA color with the same saturation and value
+ (Rotating red by 60deg produces yellow.) The result is another HSV or HSVA color with the same saturation and value
as the original, but a different hue.
GrayScale(rgb)
Takes an RGB or RGBA color and converts it to grayscale. Returns an RGB or RGBA string.
@@ -679,7 +679,7 @@ proc/ColorTone(rgb, tone)
var/curstate = A.icon_state || defstate
if(!((noIcon = (!curicon))))
- var/curstates = icon_states(curicon)
+ var/curstates = cached_icon_states(curicon)
if(!(curstate in curstates))
if("" in curstates)
curstate = ""
@@ -689,19 +689,16 @@ proc/ColorTone(rgb, tone)
var/curdir
var/base_icon_dir //We'll use this to get the icon state to display if not null BUT NOT pass it to overlays as the dir we have
- //These should use the parent's direction (most likely)
- if(!A.dir || A.dir == SOUTH)
- curdir = defdir
- else
- curdir = A.dir
+ // Use the requested dir or the atom's current dir
+ curdir = defdir || A.dir
- //Try to remove/optimize this section ASAP, CPU hog.
+ //Try to remove/optimize this section ASAP, CPU hog. //Slightly mitigated by implementing caching using cached_icon_states
//Determines if there's directionals.
if(!noIcon && curdir != SOUTH)
var/exist = FALSE
var/static/list/checkdirs = list(NORTH, EAST, WEST)
for(var/i in checkdirs) //Not using GLOB for a reason.
- if(length(icon_states(icon(curicon, curstate, i))))
+ if(length(cached_icon_states(icon(curicon, curstate, i))))
exist = TRUE
break
if(!exist)
@@ -739,8 +736,8 @@ proc/ColorTone(rgb, tone)
continue
var/current_layer = current.layer
if(current_layer < 0)
- if(current_layer <= -1000)
- return flat
+ //if(current_layer <= -1000)
+ //return flat
current_layer = process_set + A.layer + current_layer / 1000
for(var/p in 1 to layers.len)
@@ -768,7 +765,7 @@ proc/ColorTone(rgb, tone)
curblend = BLEND_OVERLAY
add = icon(I.icon, I.icon_state, base_icon_dir)
else // 'I' is an appearance object.
- add = getFlatIcon(image(I), curdir, curicon, curstate, curblend, FALSE, no_anim)
+ add = getFlatIcon(image(I), I.dir||curdir, curicon, curstate, curblend, FALSE, no_anim)
if(!add)
continue
// Find the new dimensions of the flat icon to fit the added overlay
@@ -899,6 +896,37 @@ proc/ColorTone(rgb, tone)
composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY)
return composite
+GLOBAL_LIST_EMPTY(icon_state_lists)
+/proc/cached_icon_states(var/icon/I)
+ if(!I)
+ return list()
+ var/key = I
+ var/returnlist = GLOB.icon_state_lists[key]
+ if(!returnlist)
+ returnlist = icon_states(I)
+ if(isfile(I)) // It's something that will stick around
+ GLOB.icon_state_lists[key] = returnlist
+ return returnlist
+
+/proc/expire_states_cache(var/key)
+ if(GLOB.icon_state_lists[key])
+ GLOB.icon_state_lists -= key
+ return TRUE
+ return FALSE
+
+GLOBAL_LIST_EMPTY(cached_examine_icons)
+/proc/set_cached_examine_icon(var/atom/A, var/icon/I, var/expiry = 12000)
+ GLOB.cached_examine_icons[weakref(A)] = I
+ if(expiry)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/uncache_examine_icon, weakref(A)), expiry, TIMER_UNIQUE)
+
+/proc/get_cached_examine_icon(var/atom/A)
+ var/weakref/WR = weakref(A)
+ return GLOB.cached_examine_icons[WR]
+
+/proc/uncache_examine_icon(var/weakref/WR)
+ GLOB.cached_examine_icons -= WR
+
proc/adjust_brightness(var/color, var/value)
if (!color) return "#FFFFFF"
if (!value) return color
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index 73ae811193..d4400da8df 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -94,7 +94,7 @@ proc/age2agedescription(age)
else return "unknown"
/proc/RoundHealth(health)
- var/list/icon_states = icon_states(ingame_hud_med)
+ var/list/icon_states = cached_icon_states(ingame_hud_med)
for(var/icon_state in icon_states)
if(health >= text2num(icon_state))
return icon_state
diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm
index 761bd6cae8..6e63dabb45 100644
--- a/code/_helpers/time.dm
+++ b/code/_helpers/time.dm
@@ -18,6 +18,7 @@
#define DS2TICKS(DS) ((DS)/world.tick_lag) // Convert deciseconds to ticks
#define TICKS2DS(T) ((T) TICKS) // Convert ticks to deciseconds
+#define DS2NEARESTTICK(DS) TICKS2DS(-round(-(DS2TICKS(DS))))
/proc/get_game_time()
var/global/time_offset = 0
@@ -35,25 +36,25 @@
return wtime + (time_offset + wusage) * world.tick_lag
-var/roundstart_hour
+GLOBAL_VAR_INIT(roundstart_hour, pick(2,7,12,17))
var/station_date = ""
var/next_station_date_change = 1 DAY
-#define duration2stationtime(time) time2text(station_time_in_ticks + time, "hh:mm")
-#define worldtime2stationtime(time) time2text(roundstart_hour HOURS + time, "hh:mm")
-#define round_duration_in_ticks (round_start_time ? world.time - round_start_time : 0)
-#define station_time_in_ticks (roundstart_hour HOURS + round_duration_in_ticks)
+#define duration2stationtime(time) time2text(station_time_in_ds + time, "hh:mm")
+#define worldtime2stationtime(time) time2text(GLOB.roundstart_hour HOURS + time, "hh:mm")
+#define round_duration_in_ds (GLOB.round_start_time ? world.time - GLOB.round_start_time : 0)
+#define station_time_in_ds (GLOB.roundstart_hour HOURS + round_duration_in_ds)
/proc/stationtime2text()
- return time2text(station_time_in_ticks, "hh:mm")
+ return time2text(station_time_in_ds + GLOB.timezoneOffset, "hh:mm")
/proc/stationdate2text()
var/update_time = FALSE
- if(station_time_in_ticks > next_station_date_change)
+ if(station_time_in_ds > next_station_date_change)
next_station_date_change += 1 DAY
update_time = TRUE
if(!station_date || update_time)
- var/extra_days = round(station_time_in_ticks / (1 DAY)) DAYS
+ var/extra_days = round(station_time_in_ds / (1 DAY)) DAYS
var/timeofday = world.timeofday + extra_days
station_date = num2text((text2num(time2text(timeofday, "YYYY"))+300)) + "-" + time2text(timeofday, "MM-DD") //VOREStation Edit
return station_date
@@ -64,6 +65,13 @@ var/next_station_date_change = 1 DAY
var/time_portion = time2text(world.timeofday, "hh:mm:ss")
return "[date_portion]T[time_portion]"
+/proc/get_timezone_offset()
+ var/midnight_gmt_here = text2num(time2text(0,"hh")) * 36000
+ if(midnight_gmt_here > 12 HOURS)
+ return 24 HOURS - midnight_gmt_here
+ else
+ return midnight_gmt_here
+
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
if(!wtime)
wtime = world.time
@@ -83,19 +91,19 @@ proc/isDay(var/month, var/day)
var/next_duration_update = 0
var/last_round_duration = 0
-var/round_start_time = 0
+GLOBAL_VAR_INIT(round_start_time, 0)
/hook/roundstart/proc/start_timer()
- round_start_time = world.time
+ GLOB.round_start_time = world.time
return 1
/proc/roundduration2text()
- if(!round_start_time)
+ if(!GLOB.round_start_time)
return "00:00"
if(last_round_duration && world.time < next_duration_update)
return last_round_duration
- var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever
+ var/mills = round_duration_in_ds // 1/10 of a second, not real milliseconds but whatever
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
@@ -107,10 +115,6 @@ var/round_start_time = 0
next_duration_update = world.time + 1 MINUTES
return last_round_duration
-/hook/startup/proc/set_roundstart_hour()
- roundstart_hour = pick(2,7,12,17)
- return 1
-
/var/midnight_rollovers = 0
/var/rollovercheck_last_timeofday = 0
/proc/update_midnight_rollover()
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 799cc5d113..b431ac1298 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -31,6 +31,14 @@
if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
build_click(src, client.buildmode, params, A)
return
+
+ if(multicam_on)
+ var/turf/T = get_turf(A)
+ if(T)
+ for(var/obj/screen/movable/pic_in_pic/ai/P in T.vis_locs)
+ if(P.ai == src)
+ P.Click(params)
+ break
if(stat)
return
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 23269f5bab..89e0baa087 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -257,6 +257,9 @@
if(Adjacent(user))
user.start_pulling(src)
+/turf/CtrlClick(var/mob/user)
+ user.stop_pulling()
+
/*
Alt click
Unused except for AI
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index f2df817366..fa14c1ca48 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -75,6 +75,8 @@
#define ui_ai_pda_log "SOUTH:6,WEST+11:16"
#define ui_ai_take_picture "SOUTH:6,WEST+12:16"
#define ui_ai_view_images "SOUTH:6,WEST+13:16"
+#define ui_ai_multicam "SOUTH+1:6,WEST+12:16"
+#define ui_ai_add_multicam "SOUTH+1:6,WEST+13:16"
//Gun buttons
#define ui_gun1 "EAST-2:26,SOUTH+2:7"
diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm
index 37d9616ea5..afe8df0c62 100644
--- a/code/_onclick/hud/ai.dm
+++ b/code/_onclick/hud/ai.dm
@@ -1,3 +1,25 @@
+/obj/screen/ai/multicam
+ name = "Multicamera Mode"
+ icon = 'icons/mob/screen_ai.dmi'
+ icon_state = "multicam"
+
+/obj/screen/ai/multicam/Click()
+ if(..())
+ return
+ var/mob/living/silicon/ai/AI = usr
+ AI.toggle_multicam()
+
+/obj/screen/ai/add_multicam
+ name = "New Camera"
+ icon = 'icons/mob/screen_ai.dmi'
+ icon_state = "new_cam"
+
+/obj/screen/ai/add_multicam/Click()
+ if(..())
+ return
+ var/mob/living/silicon/ai/AI = usr
+ AI.drop_new_multicam()
+
/datum/hud/proc/ai_hud()
adding = list()
other = list()
@@ -130,6 +152,16 @@
using.layer = SCREEN_LAYER
adding += using
+//Multicamera mode
+ using = new /obj/screen/ai/multicam()
+ using.screen_loc = ui_ai_multicam
+ adding += using
+
+//Add multicamera camera
+ using = new /obj/screen/ai/add_multicam()
+ using.screen_loc = ui_ai_add_multicam
+ adding += using
+
mymob.client.screen = list()
mymob.client.screen += adding + other
mymob.client.screen += mymob.client.void
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 1258e4ce94..adbee61eb8 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -28,6 +28,7 @@
inv_box.icon = ui_style
inv_box.color = ui_color
inv_box.alpha = ui_alpha
+ inv_box.hud = src
var/list/slot_data = hud_data.gear[gear_slot]
inv_box.name = gear_slot
@@ -192,6 +193,7 @@
using.screen_loc = ui_swaphand1
using.color = ui_color
using.alpha = ui_alpha
+ using.hud = src
src.adding += using
using = new /obj/screen/inventory()
@@ -201,6 +203,7 @@
using.screen_loc = ui_swaphand2
using.color = ui_color
using.alpha = ui_alpha
+ using.hud = src
src.adding += using
if(hud_data.has_resist)
diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm
index 3602a52481..40e5977c83 100644
--- a/code/_onclick/hud/movable_screen_objects.dm
+++ b/code/_onclick/hud/movable_screen_objects.dm
@@ -11,6 +11,8 @@
/obj/screen/movable
var/snap2grid = FALSE
var/moved = FALSE
+ var/x_off = -16
+ var/y_off = -16
//Snap Screen Object
//Tied to the grid, snaps to the nearest turf
@@ -40,8 +42,8 @@
screen_loc = "[screen_loc_X[1]],[screen_loc_Y[1]]"
else //Normalise Pixel Values (So the object drops at the center of the mouse, not 16 pixels off)
- var/pix_X = text2num(screen_loc_X[2]) - 16
- var/pix_Y = text2num(screen_loc_Y[2]) - 16
+ var/pix_X = text2num(screen_loc_X[2]) + x_off
+ var/pix_Y = text2num(screen_loc_Y[2]) + y_off
screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]"
/obj/screen/movable/proc/encode_screen_X(X)
diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/picture_in_picture.dm
new file mode 100644
index 0000000000..14b6a862c2
--- /dev/null
+++ b/code/_onclick/hud/picture_in_picture.dm
@@ -0,0 +1,175 @@
+/obj/screen/movable/pic_in_pic
+ name = "Picture-in-picture"
+ screen_loc = "CENTER"
+ plane = PLANE_WORLD
+ icon = null
+ var/atom/center
+ var/width = 0
+ var/height = 0
+ var/list/shown_to = list()
+ var/list/viewing_turfs = list()
+ var/obj/screen/component_button/button_x
+ var/obj/screen/component_button/button_expand
+ var/obj/screen/component_button/button_shrink
+
+ var/list/background_mas = list()
+ var/const/max_dimensions = 10
+
+/obj/screen/movable/pic_in_pic/Initialize()
+ . = ..()
+ make_backgrounds()
+
+/obj/screen/movable/pic_in_pic/Destroy()
+ for(var/C in shown_to)
+ unshow_to(C)
+ QDEL_NULL(button_x)
+ QDEL_NULL(button_shrink)
+ QDEL_NULL(button_expand)
+ return ..()
+
+/obj/screen/movable/pic_in_pic/component_click(obj/screen/component_button/component, params)
+ if(component == button_x)
+ qdel(src)
+ else if(component == button_expand)
+ set_view_size(width+1, height+1)
+ else if(component == button_shrink)
+ set_view_size(width-1, height-1)
+
+/obj/screen/movable/pic_in_pic/proc/make_backgrounds()
+ var/mutable_appearance/base = new /mutable_appearance()
+ base.icon = 'icons/misc/pic_in_pic.dmi'
+ base.layer = DISPOSAL_LAYER
+ base.plane = PLATING_PLANE
+ base.appearance_flags = PIXEL_SCALE
+
+ for(var/direction in cardinal)
+ var/mutable_appearance/dir = new /mutable_appearance(base)
+ dir.dir = direction
+ dir.icon_state = "background_[direction]"
+ background_mas += dir
+
+/obj/screen/movable/pic_in_pic/proc/add_buttons()
+ var/static/mutable_appearance/move_tab
+ if(!move_tab)
+ move_tab = new /mutable_appearance()
+ //all these properties are always the same, and since adding something to the overlay
+ //list makes a copy, there is no reason to make a new one each call
+ move_tab.icon = 'icons/misc/pic_in_pic.dmi'
+ move_tab.icon_state = "move"
+ move_tab.plane = PLANE_PLAYER_HUD
+ var/matrix/M = matrix()
+ M.Translate(0, (height + 0.25) * world.icon_size)
+ move_tab.transform = M
+ overlays += move_tab
+
+ if(!button_x)
+ button_x = new /obj/screen/component_button(null, src)
+ var/mutable_appearance/MA = new /mutable_appearance()
+ MA.name = "close"
+ MA.icon = 'icons/misc/pic_in_pic.dmi'
+ MA.icon_state = "x"
+ MA.plane = PLANE_PLAYER_HUD
+ button_x.appearance = MA
+ M = matrix()
+ M.Translate((max(4, width) - 0.75) * world.icon_size, (height + 0.25) * world.icon_size)
+ button_x.transform = M
+ vis_contents += button_x
+
+ if(!button_expand)
+ button_expand = new /obj/screen/component_button(null, src)
+ var/mutable_appearance/MA = new /mutable_appearance()
+ MA.name = "expand"
+ MA.icon = 'icons/misc/pic_in_pic.dmi'
+ MA.icon_state = "expand"
+ MA.plane = PLANE_PLAYER_HUD
+ button_expand.appearance = MA
+ M = matrix()
+ M.Translate(world.icon_size, (height + 0.25) * world.icon_size)
+ button_expand.transform = M
+ vis_contents += button_expand
+
+ if(!button_shrink)
+ button_shrink = new /obj/screen/component_button(null, src)
+ var/mutable_appearance/MA = new /mutable_appearance()
+ MA.name = "shrink"
+ MA.icon = 'icons/misc/pic_in_pic.dmi'
+ MA.icon_state = "shrink"
+ MA.plane = PLANE_PLAYER_HUD
+ button_shrink.appearance = MA
+ M = matrix()
+ M.Translate(2 * world.icon_size, (height + 0.25) * world.icon_size)
+ button_shrink.transform = M
+ vis_contents += button_shrink
+
+/obj/screen/movable/pic_in_pic/proc/add_background()
+ if((width > 0) && (height > 0))
+ for(var/mutable_appearance/dir in background_mas)
+ var/matrix/M = matrix()
+ var/x_scale = 1
+ var/y_scale = 1
+
+ var/x_off = 0
+ var/y_off = 0
+
+ if(dir.dir & (NORTH|SOUTH))
+ x_scale = width
+ x_off = (width-1)/2 * world.icon_size
+ if(dir.dir & NORTH)
+ y_off = ((height-1) * world.icon_size) + 3
+ else
+ y_off = -3
+
+ if(dir.dir & (EAST|WEST))
+ y_scale = height
+ y_off = (height-1)/2 * world.icon_size
+ if(dir.dir & EAST)
+ x_off = ((width-1) * world.icon_size) + 3
+ else
+ x_off = -3
+
+ M.Scale(x_scale, y_scale)
+ M.Translate(x_off, y_off)
+ dir.transform = M
+ overlays += dir
+
+/obj/screen/movable/pic_in_pic/proc/set_view_size(width, height, do_refresh = TRUE)
+ width = CLAMP(width, 0, max_dimensions)
+ height = CLAMP(height, 0, max_dimensions)
+ src.width = width
+ src.height = height
+
+ y_off = -height * world.icon_size - 16
+
+ overlays.Cut()
+ add_background()
+ add_buttons()
+ if(do_refresh)
+ refresh_view()
+
+/obj/screen/movable/pic_in_pic/proc/set_view_center(atom/target, do_refresh = TRUE)
+ center = target
+ if(do_refresh)
+ refresh_view()
+
+/obj/screen/movable/pic_in_pic/proc/refresh_view()
+ vis_contents -= viewing_turfs
+ if(!width || !height)
+ return
+ var/turf/T = get_turf(center)
+ if(!T)
+ return
+ var/turf/lowerleft = locate(max(1, T.x - round(width/2)), max(1, T.y - round(height/2)), T.z)
+ var/turf/upperright = locate(min(world.maxx, lowerleft.x + width - 1), min(world.maxy, lowerleft.y + height - 1), lowerleft.z)
+ viewing_turfs = block(lowerleft, upperright)
+ vis_contents += viewing_turfs
+
+
+/obj/screen/movable/pic_in_pic/proc/show_to(client/C)
+ if(C)
+ shown_to[C] = 1
+ C.screen += src
+
+/obj/screen/movable/pic_in_pic/proc/unshow_to(client/C)
+ if(C)
+ shown_to -= C
+ C.screen -= src
\ No newline at end of file
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index e82d3ea5f6..ab6985bdbd 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -19,6 +19,9 @@
/obj/screen/Destroy()
master = null
return ..()
+
+/obj/screen/proc/component_click(obj/screen/component_button/component, params)
+ return
/obj/screen/text
icon = null
@@ -31,7 +34,36 @@
/obj/screen/inventory
var/slot_id //The indentifier for the slot. It has nothing to do with ID cards.
+ var/list/object_overlays = list() // Required for inventory/screen overlays.
+/obj/screen/inventory/MouseEntered()
+ ..()
+ add_overlays()
+
+/obj/screen/inventory/MouseExited()
+ ..()
+ cut_overlay(object_overlays)
+ object_overlays.Cut()
+
+/obj/screen/inventory/proc/add_overlays()
+ var/mob/user = hud.mymob
+
+ if(hud && user && slot_id)
+ var/obj/item/holding = user.get_active_hand()
+
+ if(!holding || user.get_equipped_item(slot_id))
+ return
+
+ var/image/item_overlay = image(holding)
+ item_overlay.alpha = 92
+
+ if(!holding.mob_can_equip(user, slot_id, disable_warning = TRUE))
+ item_overlay.color = "#ff0000"
+ else
+ item_overlay.color = "#00ff00"
+
+ object_overlays += item_overlay
+ add_overlay(object_overlays)
/obj/screen/close
name = "close"
@@ -102,78 +134,116 @@
icon_state = "zone_sel"
screen_loc = ui_zonesel
var/selecting = BP_TORSO
+ var/static/list/hover_overlays_cache = list()
+ var/hovering_choice
+ var/mutable_appearance/selecting_appearance
/obj/screen/zone_sel/Click(location, control,params)
+ if(isobserver(usr))
+ return
+
var/list/PL = params2list(params)
var/icon_x = text2num(PL["icon-x"])
var/icon_y = text2num(PL["icon-y"])
- var/old_selecting = selecting //We're only going to update_icon() if there's been a change
+ var/choice = get_zone_at(icon_x, icon_y)
+ if(!choice)
+ return 1
+ return set_selected_zone(choice, usr)
+
+/obj/screen/zone_sel/MouseEntered(location, control, params)
+ MouseMove(location, control, params)
+
+/obj/screen/zone_sel/MouseMove(location, control, params)
+ if(isobserver(usr))
+ return
+
+ var/list/PL = params2list(params)
+ var/icon_x = text2num(PL["icon-x"])
+ var/icon_y = text2num(PL["icon-y"])
+ var/choice = get_zone_at(icon_x, icon_y)
+
+ if(hovering_choice == choice)
+ return
+ vis_contents -= hover_overlays_cache[hovering_choice]
+ hovering_choice = choice
+
+ var/obj/effect/overlay/zone_sel/overlay_object = hover_overlays_cache[choice]
+ if(!overlay_object)
+ overlay_object = new
+ overlay_object.icon_state = "[choice]"
+ hover_overlays_cache[choice] = overlay_object
+ vis_contents += overlay_object
+
+
+/obj/effect/overlay/zone_sel
+ icon = 'icons/mob/zone_sel.dmi'
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ alpha = 128
+ anchored = TRUE
+ layer = LAYER_HUD_ABOVE
+ plane = PLANE_PLAYER_HUD_ABOVE
+
+/obj/screen/zone_sel/MouseExited(location, control, params)
+ if(!isobserver(usr) && hovering_choice)
+ vis_contents -= hover_overlays_cache[hovering_choice]
+ hovering_choice = null
+
+/obj/screen/zone_sel/proc/get_zone_at(icon_x, icon_y)
switch(icon_y)
if(1 to 3) //Feet
switch(icon_x)
if(10 to 15)
- selecting = BP_R_FOOT
+ return BP_R_FOOT
if(17 to 22)
- selecting = BP_L_FOOT
- else
- return 1
+ return BP_L_FOOT
if(4 to 9) //Legs
switch(icon_x)
if(10 to 15)
- selecting = BP_R_LEG
+ return BP_R_LEG
if(17 to 22)
- selecting = BP_L_LEG
- else
- return 1
+ return BP_L_LEG
if(10 to 13) //Hands and groin
switch(icon_x)
if(8 to 11)
- selecting = BP_R_HAND
+ return BP_R_HAND
if(12 to 20)
- selecting = BP_GROIN
+ return BP_GROIN
if(21 to 24)
- selecting = BP_L_HAND
- else
- return 1
+ return BP_L_HAND
if(14 to 22) //Chest and arms to shoulders
switch(icon_x)
if(8 to 11)
- selecting = BP_R_ARM
+ return BP_R_ARM
if(12 to 20)
- selecting = BP_TORSO
+ return BP_TORSO
if(21 to 24)
- selecting = BP_L_ARM
- else
- return 1
+ return BP_L_ARM
if(23 to 30) //Head, but we need to check for eye or mouth
if(icon_x in 12 to 20)
- selecting = BP_HEAD
switch(icon_y)
if(23 to 24)
if(icon_x in 15 to 17)
- selecting = O_MOUTH
+ return O_MOUTH
if(26) //Eyeline, eyes are on 15 and 17
if(icon_x in 14 to 18)
- selecting = O_EYES
+ return O_EYES
if(25 to 27)
if(icon_x in 15 to 17)
- selecting = O_EYES
+ return O_EYES
+ return BP_HEAD
- if(old_selecting != selecting)
- update_icon()
- return 1
-
-/obj/screen/zone_sel/proc/set_selected_zone(bodypart)
- var/old_selecting = selecting
- selecting = bodypart
- if(old_selecting != selecting)
+/obj/screen/zone_sel/proc/set_selected_zone(choice, mob/user)
+ if(isobserver(user))
+ return
+ if(choice != selecting)
+ selecting = choice
update_icon()
/obj/screen/zone_sel/update_icon()
- overlays.Cut()
- overlays += image('icons/mob/zone_sel.dmi', "[selecting]")
-
+ cut_overlay(selecting_appearance)
+ selecting_appearance = mutable_appearance('icons/mob/zone_sel.dmi', "[selecting]")
+ add_overlay(selecting_appearance)
/obj/screen/Click(location, control, params)
if(!usr) return 1
@@ -535,3 +605,15 @@
var/mob/living/carbon/C = hud.mymob
if(C.handcuffed)
overlays |= handcuff_overlay
+
+// PIP stuff
+/obj/screen/component_button
+ var/obj/screen/parent
+
+/obj/screen/component_button/Initialize(mapload, obj/screen/new_parent)
+ . = ..()
+ parent = new_parent
+
+/obj/screen/component_button/Click(params)
+ if(parent)
+ parent.component_click(src, params)
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index 88309b5074..485df1de41 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -50,8 +50,8 @@
/obj/machinery/teleport/hub/attack_ghost(mob/user as mob)
var/atom/l = loc
var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z))
- if(com.locked)
- user.loc = get_turf(com.locked)
+ if(com?.teleport_control.locked)
+ user.loc = get_turf(com.teleport_control.locked)
/obj/effect/portal/attack_ghost(mob/user as mob)
if(target)
diff --git a/code/controllers/autotransfer.dm b/code/controllers/autotransfer.dm
index e64f8de229..8008ef3df9 100644
--- a/code/controllers/autotransfer.dm
+++ b/code/controllers/autotransfer.dm
@@ -17,14 +17,14 @@ datum/controller/transfer_controller/Destroy()
datum/controller/transfer_controller/process()
currenttick = currenttick + 1
//VOREStation Edit START
- if (round_duration_in_ticks >= shift_last_vote - 2 MINUTES)
- shift_last_vote = 999999999999 //Setting to a stupidly high number since it'll be not used again.
- to_world("Warning: This upcoming round-extend vote will be your ONLY extend vote. Wrap up your scenes in the next 4 fuckin hours if the round is extended.") //YAWN EDIT NIGGA VOREStation Edit
- if (round_duration_in_ticks >= shift_hard_end - 1 MINUTE)
+ if (round_duration_in_ds >= shift_last_vote - 2 MINUTES)
+ shift_last_vote = 99999999 //Setting to a stupidly high number since it'll be not used again.
+ to_world("Warning: You have one hour left in the shift. Wrap up your scenes in the next 60 minutes before the transfer is called.") //VOREStation Edit
+ if (round_duration_in_ds >= shift_hard_end - 1 MINUTE)
init_shift_change(null, 1)
shift_hard_end = timerbuffer + config.vote_autotransfer_interval //If shuttle somehow gets recalled, let's force it to call again next time a vote would occur.
timerbuffer = timerbuffer + config.vote_autotransfer_interval //Just to make sure a vote doesn't occur immediately afterwords.
- else if (round_duration_in_ticks >= timerbuffer - 1 MINUTE)
+ else if (round_duration_in_ds >= timerbuffer - 1 MINUTE)
SSvote.autotransfer()
//VOREStation Edit END
timerbuffer = timerbuffer + config.vote_autotransfer_interval
diff --git a/code/controllers/configuration_vr.dm b/code/controllers/configuration_vr.dm
index ad839a5730..a91c04e517 100644
--- a/code/controllers/configuration_vr.dm
+++ b/code/controllers/configuration_vr.dm
@@ -11,6 +11,7 @@
var/static/pto_cap = 100 //Hours
var/static/require_flavor = FALSE
var/static/ipqualityscore_apikey //API key for ipqualityscore.com
+ var/static/use_playtime_restriction_for_jobs = FALSE
/hook/startup/proc/read_vs_config()
var/list/Lines = file2list("config/config.txt")
@@ -61,4 +62,6 @@
config.require_flavor = TRUE
if ("ipqualityscore_apikey")
config.ipqualityscore_apikey = value
+ if ("use_playtime_restriction_for_jobs")
+ config.use_playtime_restriction_for_jobs = TRUE
return 1
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 2212291b9e..811e8497f6 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -156,12 +156,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// Please don't stuff random bullshit here,
// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize()
-/datum/controller/master/Initialize(delay, init_sss)
+/datum/controller/master/Initialize(delay, init_sss, tgs_prime)
set waitfor = 0
if(delay)
sleep(delay)
+ if(tgs_prime)
+ world.TgsInitializationComplete()
+
if(init_sss)
init_subtypes(/datum/controller/subsystem, subsystems)
diff --git a/code/controllers/subsystems/game_master.dm b/code/controllers/subsystems/game_master.dm
index d5326bfba6..ce7e8176c3 100644
--- a/code/controllers/subsystems/game_master.dm
+++ b/code/controllers/subsystems/game_master.dm
@@ -109,7 +109,7 @@ SUBSYSTEM_DEF(game_master)
return FALSE
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
- var/mills = round_duration_in_ticks
+ var/mills = round_duration_in_ds
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
diff --git a/code/controllers/subsystems/nightshift.dm b/code/controllers/subsystems/nightshift.dm
index 9e89a05cee..3f0d9bfda8 100644
--- a/code/controllers/subsystems/nightshift.dm
+++ b/code/controllers/subsystems/nightshift.dm
@@ -20,7 +20,7 @@ SUBSYSTEM_DEF(nightshift)
return ..()
/datum/controller/subsystem/nightshift/fire(resumed = FALSE)
- if(round_duration_in_ticks < nightshift_first_check)
+ if(round_duration_in_ds < nightshift_first_check)
return
check_nightshift()
diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm
index 41811a2a6a..ca0feb37f6 100644
--- a/code/controllers/subsystems/persist_vr.dm
+++ b/code/controllers/subsystems/persist_vr.dm
@@ -47,23 +47,33 @@ SUBSYSTEM_DEF(persist)
// Update client whatever
var/client/C = M.client
- var/wait_in_hours = (wait / (1 HOUR)) * J.timeoff_factor
+ var/wait_in_hours = wait / (1 HOUR)
+ var/pto_factored = wait_in_hours * J.timeoff_factor
LAZYINITLIST(C.department_hours)
+ LAZYINITLIST(C.play_hours)
var/dept_hours = C.department_hours
- if(isnum(C.department_hours[department_earning]))
- dept_hours[department_earning] += wait_in_hours
+ var/play_hours = C.play_hours
+ if(isnum(dept_hours[department_earning]))
+ dept_hours[department_earning] += pto_factored
else
- dept_hours[department_earning] = wait_in_hours
+ dept_hours[department_earning] = pto_factored
- //Cap it
+ // If they're earning PTO they must be in a useful job so are earning playtime in that department
+ if(J.timeoff_factor > 0)
+ if(isnum(play_hours[department_earning]))
+ play_hours[department_earning] += wait_in_hours
+ else
+ play_hours[department_earning] = wait_in_hours
+
+ // Cap it
dept_hours[department_earning] = min(config.pto_cap, dept_hours[department_earning])
-
// Okay we figured it out, lets update database!
var/sql_ckey = sql_sanitize_text(C.ckey)
var/sql_dpt = sql_sanitize_text(department_earning)
var/sql_bal = text2num("[C.department_hours[department_earning]]")
- var/DBQuery/query = dbcon.NewQuery("INSERT INTO vr_player_hours (ckey, department, hours) VALUES ('[sql_ckey]', '[sql_dpt]', [sql_bal]) ON DUPLICATE KEY UPDATE hours = VALUES(hours)")
+ var/sql_total = text2num("[C.play_hours[department_earning]]")
+ var/DBQuery/query = dbcon.NewQuery("INSERT INTO vr_player_hours (ckey, department, hours, total_hours) VALUES ('[sql_ckey]', '[sql_dpt]', [sql_bal], [sql_total]) ON DUPLICATE KEY UPDATE hours = VALUES(hours), total_hours = VALUES(total_hours)")
query.Execute()
if (MC_TICK_CHECK)
diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm
index 397f32078c..f213c6bf30 100644
--- a/code/controllers/subsystems/ticker.dm
+++ b/code/controllers/subsystems/ticker.dm
@@ -394,21 +394,26 @@ var/global/datum/controller/subsystem/ticker/ticker
/datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/new_player/player in player_list)
- if(player && player.ready && player.mind)
- if(player.mind.assigned_role=="AI")
+ if(player && player.ready && player.mind?.assigned_role)
+ var/datum/job/J = SSjob.get_job(player.mind.assigned_role)
+
+ // Snowflakey AI treatment
+ if(J.mob_type & JOB_SILICON_AI)
player.close_spawn_windows()
- player.AIize()
- else if(!player.mind.assigned_role)
+ player.AIize(move = TRUE)
continue
- else
- //VOREStation Edit Start
- var/mob/living/carbon/human/new_char = player.create_character()
- if(new_char)
- qdel(player)
- if(istype(new_char) && !(new_char.mind.assigned_role=="Cyborg"))
- data_core.manifest_inject(new_char)
- //VOREStation Edit End
+
+ // Ask their new_player mob to spawn them
+ if(!player.spawn_checks_vr(player.mind.assigned_role)) continue //VOREStation Add
+ var/mob/living/carbon/human/new_char = player.create_character()
+
+ // Created their playable character, delete their /mob/new_player
+ if(new_char)
+ qdel(player)
+ // If they're a carbon, they can get manifested
+ if(J.mob_type & JOB_CARBON)
+ data_core.manifest_inject(new_char)
/datum/controller/subsystem/ticker/proc/collect_minds()
for(var/mob/living/player in player_list)
diff --git a/code/datums/orbit.dm b/code/datums/orbit.dm
index 5d457ff4ac..0176d7f23d 100644
--- a/code/datums/orbit.dm
+++ b/code/datums/orbit.dm
@@ -4,10 +4,12 @@
var/lock = TRUE
var/turf/lastloc
var/lastprocess
+ var/matrix/init_transform
-/datum/orbit/New(_orbiter, _orbiting, _lock)
+/datum/orbit/New(var/atom/movable/_orbiter, var/atom/_orbiting, _lock)
orbiter = _orbiter
orbiting = _orbiting
+ init_transform = _orbiter.transform
SSorbit.processing += src
if (!orbiting.orbiters)
orbiting.orbiters = list()
@@ -24,6 +26,7 @@
SSorbit.processing -= src
if (orbiter)
orbiter.orbiting = null
+ orbiter.transform = init_transform
orbiter = null
if (orbiting)
if (orbiting.orbiters)
@@ -84,7 +87,6 @@
new/datum/orbit(src, A, lockinorbit)
if (!orbiting) //something failed, and our orbit datum deleted itself
return
- var/matrix/initial_transform = matrix(transform)
//Head first!
if (pre_rotation)
@@ -101,9 +103,6 @@
SpinAnimation(rotation_speed, -1, clockwise, rotation_segments)
- //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
- transform = initial_transform
-
/atom/movable/proc/stop_orbit()
SpinAnimation(0,0)
qdel(orbiting)
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index 962c91a621..e00a4a99df 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -4,6 +4,7 @@
var/list/restricted_jobs = list() // Jobs that cannot be this antagonist (depending on config)
var/list/protected_jobs = list() // As above.
var/list/roundstart_restricted = list() //Jobs that can be this antag, but not at roundstart
+ var/avoid_silicons = FALSE // If we won't hand this antag role to silicons (AI, borg, etc)
// Strings.
var/welcome_text = "Cry havoc and let slip the dogs of war!"
diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm
index c8f2928ced..10f7a75b15 100644
--- a/code/game/antagonist/antagonist_helpers.dm
+++ b/code/game/antagonist/antagonist_helpers.dm
@@ -10,6 +10,10 @@
return FALSE
if(config.protect_roles_from_antagonist && (player.assigned_role in protected_jobs))
return FALSE
+ if(avoid_silicons)
+ var/datum/job/J = SSjob.get_job(player.assigned_role)
+ if(J.mob_type & JOB_SILICON)
+ return FALSE
return TRUE
/datum/antagonist/proc/antags_are_dead()
diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm
index 860e73a052..694c4a3634 100644
--- a/code/game/antagonist/station/changeling.dm
+++ b/code/game/antagonist/station/changeling.dm
@@ -5,7 +5,7 @@
role_text_plural = "Changelings"
bantype = "changeling"
feedback_tag = "changeling_objective"
- restricted_jobs = list("AI", "Cyborg")
+ avoid_silicons = TRUE
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Colony Director")
welcome_text = "Use say \"#g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them."
antag_sound = 'sound/effects/antag_notice/ling_alert.ogg'
diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm
index dc98622ba7..06aab654b4 100644
--- a/code/game/antagonist/station/cultist.dm
+++ b/code/game/antagonist/station/cultist.dm
@@ -11,7 +11,8 @@ var/datum/antagonist/cultist/cult
role_text = "Cultist"
role_text_plural = "Cultists"
bantype = "cultist"
- restricted_jobs = list("Chaplain","AI", "Cyborg")
+ restricted_jobs = list("Chaplain")
+ avoid_silicons = TRUE
protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Colony Director")
roundstart_restricted = list("Internal Affairs Agent", "Head of Security", "Colony Director")
role_type = BE_CULTIST
diff --git a/code/game/antagonist/station/loyalist.dm b/code/game/antagonist/station/loyalist.dm
index 9b2333b491..ec27584426 100644
--- a/code/game/antagonist/station/loyalist.dm
+++ b/code/game/antagonist/station/loyalist.dm
@@ -29,7 +29,7 @@ var/datum/antagonist/loyalists/loyalists
faction_welcome = "Preserve NanoTrasen's interests against the traitorous recidivists amongst the crew. Protect the heads of staff with your life."
faction_indicator = "loyal"
faction_invisible = 1
- restricted_jobs = list("AI", "Cyborg")
+ avoid_silicons = TRUE
/datum/antagonist/loyalists/New()
..()
diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm
index ed3c804506..cdd4efb8f3 100644
--- a/code/game/antagonist/station/renegade.dm
+++ b/code/game/antagonist/station/renegade.dm
@@ -6,7 +6,7 @@ var/datum/antagonist/renegade/renegades
role_text = "Renegade"
role_text_plural = "Renegades"
bantype = "renegade"
- restricted_jobs = list("AI", "Cyborg")
+ avoid_silicons = TRUE
welcome_text = "Something's going to go wrong today, you can just feel it. You're paranoid, you've got a gun, and you're going to survive."
antag_sound = 'sound/effects/antag_notice/general_goodie_alert.ogg'
antag_text = "You are a minor antagonist! Within the rules, \
diff --git a/code/game/antagonist/station/revolutionary.dm b/code/game/antagonist/station/revolutionary.dm
index 17c519b7a0..1db40f396a 100644
--- a/code/game/antagonist/station/revolutionary.dm
+++ b/code/game/antagonist/station/revolutionary.dm
@@ -29,7 +29,7 @@ var/datum/antagonist/revolutionary/revs
faction_indicator = "rev"
faction_invisible = 1
- restricted_jobs = list("AI", "Cyborg")
+ avoid_silicons = TRUE
protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Colony Director", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
roundstart_restricted = list("Internal Affairs Agent", "Colony Director", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
diff --git a/code/game/antagonist/station/stowaway.dm b/code/game/antagonist/station/stowaway.dm
index dc3814b3b1..574fda0bca 100644
--- a/code/game/antagonist/station/stowaway.dm
+++ b/code/game/antagonist/station/stowaway.dm
@@ -6,7 +6,7 @@ var/datum/antagonist/stowaway/stowaways
role_text = "Stowaway"
role_text_plural = "Stowaways"
bantype = "renegade"
- restricted_jobs = list("AI")
+ avoid_silicons = TRUE // This was previously allowing cyborgs to be stowaways, but given that they would just connect to the AI, it didn't make much sense
welcome_text = "People are known to run from many things, or to many things, for many different reasons. You happen to be one of those people."
antag_text = "You are a minor antagonist! Within the server rules, do whatever it is \
that you came to the station to do. Espionage, thievery, or just running from the law are all examples. \
diff --git a/code/game/antagonist/station/thug.dm b/code/game/antagonist/station/thug.dm
index 61d92e1646..f26d6441a8 100644
--- a/code/game/antagonist/station/thug.dm
+++ b/code/game/antagonist/station/thug.dm
@@ -6,7 +6,7 @@ var/datum/antagonist/thug/thugs
role_text = "Thug"
role_text_plural = "Thugs"
bantype = "renegade"
- restricted_jobs = list("AI", "Cyborg")
+ avoid_silicons = TRUE
welcome_text = "Sometimes, people just need to get messed up. Luckily, that's what you're here to do."
antag_text = "You are a minor antagonist! Within the server rules, do whatever it is \
that you came to the station to do, be it violence, theft, or just extreme self-defense. \
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5f8ccb3391..123daae654 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -37,8 +37,8 @@
// During dynamic mapload (reader.dm) this assigns the var overrides from the .dmm file
// Native BYOND maploading sets those vars before invoking New(), by doing this FIRST we come as close to that behavior as we can.
- if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
- _preloader.load(src)
+ if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
+ GLOB._preloader.load(src)
// Pass our arguments to InitAtom so they can be passed to initialize(), but replace 1st with if-we're-during-mapload.
var/do_initialize = SSatoms.initialized
@@ -184,14 +184,18 @@
var/list/output = list("[bicon(src)] That's [f_name] [suffix]", desc)
- if(user.client?.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
+ if(user.client?.prefs.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
output += description_info
- if(user.client?.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
+ if(user.client?.prefs.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
user.client.statpanel = "Examine" // Switch to stat panel
return output
+// Don't make these call bicon or anything, these are what bicon uses. They need to return an icon.
+/atom/proc/examine_icon()
+ return icon(icon=src.icon, icon_state=src.icon_state, dir=SOUTH, frame=1, moving=0)
+
// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set.
// see code/modules/mob/mob_movement.dm for more.
/atom/proc/relaymove()
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index c79a0e94be..b9b8f6db8a 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -56,16 +56,9 @@
var/obj/item/weapon/reagent_containers/glass/beaker = null
var/opened = 0
-/obj/machinery/dna_scannernew/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- RefreshParts()
+/obj/machinery/dna_scannernew/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/dna_scannernew/relaymove(mob/user as mob)
if (user.stat)
diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm
index 578c1a0d8c..9fcb4bd0ea 100644
--- a/code/game/gamemodes/game_mode_latespawn.dm
+++ b/code/game/gamemodes/game_mode_latespawn.dm
@@ -34,7 +34,7 @@
if(emergency_shuttle.shuttle && (emergency_shuttle.shuttle.moving_status == SHUTTLE_WARMUP || emergency_shuttle.shuttle.moving_status == SHUTTLE_INTRANSIT))
return // Don't do anything if the shuttle's coming.
- var/mills = round_duration_in_ticks
+ var/mills = round_duration_in_ds
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
diff --git a/code/game/jobs/job/captain_vr.dm b/code/game/jobs/job/captain_vr.dm
index f08a1b4079..746d92cf86 100644
--- a/code/game/jobs/job/captain_vr.dm
+++ b/code/game/jobs/job/captain_vr.dm
@@ -1,12 +1,14 @@
/datum/job/captain
disallow_jobhop = TRUE
pto_type = PTO_CIVILIAN
+ //dept_time_required = 60 //Pending something more complicated
/datum/job/hop
disallow_jobhop = TRUE
pto_type = PTO_CIVILIAN
departments = list(DEPARTMENT_COMMAND, DEPARTMENT_CIVILIAN)
departments_managed = list(DEPARTMENT_CIVILIAN, DEPARTMENT_CARGO, DEPARTMENT_PLANET)
+ dept_time_required = 60
alt_titles = list("Crew Resources Officer" = /datum/alt_title/cro,
"Deputy Director" = /datum/alt_title/deputy_director)
diff --git a/code/game/jobs/job/civilian_vr.dm b/code/game/jobs/job/civilian_vr.dm
index 2844108187..433935e55b 100644
--- a/code/game/jobs/job/civilian_vr.dm
+++ b/code/game/jobs/job/civilian_vr.dm
@@ -12,6 +12,7 @@
/datum/job/qm
pto_type = PTO_CARGO
+ dept_time_required = 20
/datum/job/cargo_tech
total_positions = 3
diff --git a/code/game/jobs/job/engineering_vr.dm b/code/game/jobs/job/engineering_vr.dm
index 10337d9881..0ed001bd28 100644
--- a/code/game/jobs/job/engineering_vr.dm
+++ b/code/game/jobs/job/engineering_vr.dm
@@ -1,6 +1,7 @@
/datum/job/chief_engineer
disallow_jobhop = TRUE
pto_type = PTO_ENGINEERING
+ dept_time_required = 60
/datum/job/engineer
pto_type = PTO_ENGINEERING
diff --git a/code/game/jobs/job/exploration_vr.dm b/code/game/jobs/job/exploration_vr.dm
index 987041de61..d555c531a2 100644
--- a/code/game/jobs/job/exploration_vr.dm
+++ b/code/game/jobs/job/exploration_vr.dm
@@ -44,6 +44,7 @@ var/const/SAR =(1<<14)
economic_modifier = 8
minimal_player_age = 7
pto_type = PTO_EXPLORATION
+ dept_time_required = 20
access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot, access_explorer, access_gateway)
minimal_access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot, access_explorer, access_gateway)
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index 082753d0fc..a1ca756462 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -31,6 +31,7 @@
var/outfit_type // What outfit datum does this job use in its default title?
var/offmap_spawn = FALSE // Do we require weird and special spawning and datacore handling?
+ var/mob_type = JOB_CARBON // Bitflags representing mob type this job spawns
// Description of the job's role and minimum responsibilities.
var/job_description = "This Job doesn't have a description! Please report it!"
diff --git a/code/game/jobs/job/job_vr.dm b/code/game/jobs/job/job_vr.dm
index ce982aaab9..3ffd0d05f9 100644
--- a/code/game/jobs/job/job_vr.dm
+++ b/code/game/jobs/job/job_vr.dm
@@ -14,6 +14,20 @@
//Disallow joining as this job midround from off-duty position via going on-duty
var/disallow_jobhop = FALSE
+ //Time required in the department as other jobs before playing this one (in hours)
+ var/dept_time_required = 0
+
// Check client-specific availability rules.
/datum/job/proc/player_has_enough_pto(client/C)
return timeoff_factor >= 0 || (C && LAZYACCESS(C.department_hours, pto_type) > 0)
+
+/datum/job/proc/player_has_enough_playtime(client/C)
+ return (available_in_playhours(C) == 0)
+
+/datum/job/proc/available_in_playhours(client/C)
+ if(C && config.use_playtime_restriction_for_jobs)
+ if(isnum(C.play_hours[pto_type])) // Has played that department before
+ return max(0, dept_time_required - C.play_hours[pto_type])
+ else // List doesn't have that entry, maybe never played, maybe invalid PTO type (you should fix that...)
+ return dept_time_required // Could be 0, too, which is fine! They can play that
+ return 0
\ No newline at end of file
diff --git a/code/game/jobs/job/medical_vr.dm b/code/game/jobs/job/medical_vr.dm
index 306fe9acaa..1a29d1ec9d 100644
--- a/code/game/jobs/job/medical_vr.dm
+++ b/code/game/jobs/job/medical_vr.dm
@@ -1,6 +1,7 @@
/datum/job/cmo
disallow_jobhop = TRUE
pto_type = PTO_MEDICAL
+ dept_time_required = 60
/datum/job/doctor
spawn_positions = 5
diff --git a/code/game/jobs/job/science_vr.dm b/code/game/jobs/job/science_vr.dm
index d1bd15c364..637b41f3cb 100644
--- a/code/game/jobs/job/science_vr.dm
+++ b/code/game/jobs/job/science_vr.dm
@@ -1,6 +1,7 @@
/datum/job/rd
disallow_jobhop = TRUE
pto_type = PTO_SCIENCE
+ dept_time_required = 60
access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
access_tox_storage, access_teleporter, access_sec_doors,
diff --git a/code/game/jobs/job/security_vr.dm b/code/game/jobs/job/security_vr.dm
index 9e55d807b0..24b4a33325 100644
--- a/code/game/jobs/job/security_vr.dm
+++ b/code/game/jobs/job/security_vr.dm
@@ -1,6 +1,7 @@
/datum/job/hos
disallow_jobhop = TRUE
pto_type = PTO_SECURITY
+ dept_time_required = 60
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
@@ -13,6 +14,7 @@
/datum/job/warden
pto_type = PTO_SECURITY
+ dept_time_required = 20
/datum/job/detective
pto_type = PTO_SECURITY
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index 6f89adcd07..1619569c9d 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -18,6 +18,7 @@
economic_modifier = 0
has_headset = FALSE
assignable = FALSE
+ mob_type = JOB_SILICON_AI
outfit_type = /decl/hierarchy/outfit/job/silicon/ai
job_description = "The AI oversees the operation of the station and its crew, but has no real authority over them. \
The AI is required to follow its Laws, and Lawbound Synthetics that are linked to it are expected to follow \
@@ -54,6 +55,7 @@
economic_modifier = 0
has_headset = FALSE
assignable = FALSE
+ mob_type = JOB_SILICON_ROBOT
outfit_type = /decl/hierarchy/outfit/job/silicon/cyborg
job_description = "A Cyborg is a mobile station synthetic, piloted by a cybernetically preserved brain. It is considered a person, but is still required \
to follow its Laws."
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 34e75f4320..2470fdc114 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -60,8 +60,12 @@ var/global/datum/controller/occupations/job_master
return 0
if(!job.player_old_enough(player.client))
return 0
- if(!is_job_whitelisted(player, rank)) //VOREStation Code
+ //VOREStation Add
+ if(!job.player_has_enough_playtime(player.client))
return 0
+ if(!is_job_whitelisted(player, rank))
+ return 0
+ //VOREStation Add End
var/position_limit = job.total_positions
if(!latejoin)
@@ -97,6 +101,9 @@ var/global/datum/controller/occupations/job_master
Debug("FOC character not old enough, Player: [player]")
continue
//VOREStation Code Start
+ if(!job.player_has_enough_playtime(player.client))
+ Debug("FOC character not enough playtime, Player: [player]")
+ continue
if(!is_job_whitelisted(player, job.title))
Debug("FOC is_job_whitelisted failed, Player: [player]")
continue
@@ -133,6 +140,9 @@ var/global/datum/controller/occupations/job_master
continue
//VOREStation Code Start
+ if(!job.player_has_enough_playtime(player.client))
+ Debug("GRJ player not enough playtime, Player: [player]")
+ continue
if(!is_job_whitelisted(player, job.title))
Debug("GRJ player not whitelisted for this job, Player: [player], Job: [job.title]")
continue
@@ -283,6 +293,12 @@ var/global/datum/controller/occupations/job_master
Debug("DO player not old enough, Player: [player], Job:[job.title]")
continue
+ //VOREStation Add
+ if(!job.player_has_enough_playtime(player.client))
+ Debug("DO player not enough playtime, Player: [player]")
+ continue
+ //VOREStation Add End
+
// If the player wants that job on this level, then try give it to him.
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
@@ -373,54 +389,64 @@ var/global/datum/controller/occupations/job_master
//Equip custom gear loadout.
var/list/custom_equip_slots = list() //If more than one item takes the same slot, all after the first one spawn in storage.
var/list/custom_equip_leftovers = list()
- if(H.client.prefs.gear && H.client.prefs.gear.len && job.title != "Cyborg" && job.title != "AI")
+ if(H.client.prefs.gear && H.client.prefs.gear.len && !(job.mob_type & JOB_SILICON))
for(var/thing in H.client.prefs.gear)
var/datum/gear/G = gear_datums[thing]
- if(G)
- var/permitted
- if(G.allowed_roles)
- for(var/job_name in G.allowed_roles)
- if(job.title == job_name)
- permitted = 1
+ if(!G) //Not a real gear datum (maybe removed, as this is loaded from their savefile)
+ continue
+
+ var/permitted
+ // Check if it is restricted to certain roles
+ if(G.allowed_roles)
+ for(var/job_name in G.allowed_roles)
+ if(job.title == job_name)
+ permitted = 1
+ else
+ permitted = 1
+
+ // Check if they're whitelisted for this gear (in alien whitelist? seriously?)
+ if(G.whitelisted && !is_alien_whitelisted(H, GLOB.all_species[G.whitelisted]))
+ permitted = 0
+
+ // If they aren't, tell them
+ if(!permitted)
+ to_chat(H, "Your current species, job or whitelist status does not permit you to spawn with [thing]!")
+ continue
+
+ // Implants get special treatment
+ if(G.slot == "implant")
+ var/obj/item/weapon/implant/I = G.spawn_item(H)
+ I.invisibility = 100
+ I.implant_loadout(H)
+ continue
+
+ // Try desperately (and sorta poorly) to equip the item
+ if(G.slot && !(G.slot in custom_equip_slots))
+ var/metadata = H.client.prefs.gear[G.display_name]
+ if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head)
+ custom_equip_leftovers += thing
+ else if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot))
+ to_chat(H, "Equipping you with \the [thing]!")
+ custom_equip_slots.Add(G.slot)
else
- permitted = 1
+ custom_equip_leftovers.Add(thing)
+ else
+ spawn_in_storage += thing
- if(G.whitelisted && !is_alien_whitelisted(H, GLOB.all_species[G.whitelisted]))
-
- //if(G.whitelisted && (G.whitelisted != H.species.name || !is_alien_whitelisted(H, G.whitelisted)))
- permitted = 0
-
- if(!permitted)
- to_chat(H, "Your current species, job or whitelist status does not permit you to spawn with [thing]!")
- continue
-
- if(G.slot == "implant")
- var/obj/item/weapon/implant/I = G.spawn_item(H)
- I.invisibility = 100
- I.implant_loadout(H)
- continue
-
- if(G.slot && !(G.slot in custom_equip_slots))
- // This is a miserable way to fix the loadout overwrite bug, but the alternative requires
- // adding an arg to a bunch of different procs. Will look into it after this merge. ~ Z
- var/metadata = H.client.prefs.gear[G.display_name]
- if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head)
- custom_equip_leftovers += thing
- else if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot))
- to_chat(H, "Equipping you with \the [thing]!")
- custom_equip_slots.Add(G.slot)
- else
- custom_equip_leftovers.Add(thing)
- else
- spawn_in_storage += thing
- //Equip job items.
+ // Set up their account
job.setup_account(H)
+
+ // Equip job items.
job.equip(H, H.mind ? H.mind.role_alt_title : "")
+
+ // Stick their fingerprints on literally everything
job.apply_fingerprints(H)
- if(job.title != "Cyborg" && job.title != "AI")
+
+ // Only non-silicons get post-job-equip equipment
+ if(!(job.mob_type & JOB_SILICON))
H.equip_post_job()
- //If some custom items could not be equipped before, try again now.
+ // If some custom items could not be equipped before, try again now.
for(var/thing in custom_equip_leftovers)
var/datum/gear/G = gear_datums[thing]
if(G.slot in custom_equip_slots)
@@ -456,14 +482,16 @@ var/global/datum/controller/occupations/job_master
H.mind.assigned_role = rank
alt_title = H.mind.role_alt_title
- switch(rank)
- if("Cyborg")
- return H.Robotize()
- if("AI")
- return H
- if("Colony Director")
- var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP) ? null : sound('sound/misc/boatswain.ogg', volume=20)
- captain_announcement.Announce("All hands, [alt_title ? alt_title : "Colony Director"] [H.real_name] on deck!", new_sound = announce_sound, zlevel = H.z)
+ // If we're a silicon, we may be done at this point
+ if(job.mob_type & JOB_SILICON_ROBOT)
+ return H.Robotize()
+ if(job.mob_type & JOB_SILICON_AI)
+ return H
+
+ // TWEET PEEP
+ if(rank == "Colony Director")
+ var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP) ? null : sound('sound/misc/boatswain.ogg', volume=20)
+ captain_announcement.Announce("All hands, [alt_title ? alt_title : "Colony Director"] [H.real_name] on deck!", new_sound = announce_sound, zlevel = H.z)
//Deferred item spawning.
if(spawn_in_storage && spawn_in_storage.len)
@@ -573,7 +601,7 @@ var/global/datum/controller/occupations/job_master
if(!J) continue
J.total_positions = text2num(value)
J.spawn_positions = text2num(value)
- if(name == "AI" || name == "Cyborg")//I dont like this here but it will do for now
+ if(J.mob_type & JOB_SILICON)
J.total_positions = 0
return 1
@@ -598,6 +626,11 @@ var/global/datum/controller/occupations/job_master
if(!job.player_old_enough(player.client))
level6++
continue
+ //VOREStation Add
+ if(!job.player_has_enough_playtime(player.client))
+ level6++
+ continue
+ //VOREStation Add End
if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
level1++
else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 70fd190afe..c19873fd3d 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -180,21 +180,10 @@
idle_power_usage = 15
active_power_usage = 200 //builtin health analyzer, dialysis machine, injectors.
-/obj/machinery/sleeper/New()
- ..()
+/obj/machinery/sleeper/Initialize()
+ . = ..()
beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- component_parts += new /obj/item/weapon/reagent_containers/syringe(src)
- component_parts += new /obj/item/weapon/reagent_containers/syringe(src)
- component_parts += new /obj/item/weapon/reagent_containers/syringe(src)
- component_parts += new /obj/item/stack/material/glass/reinforced(src, 2)
-
- RefreshParts()
+ default_apply_parts()
/obj/machinery/sleeper/Destroy()
if(console)
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index f5034bcf71..482988caf2 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -15,14 +15,9 @@
light_color = "#00FF00"
var/obj/machinery/body_scanconsole/console
-/obj/machinery/bodyscanner/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/stack/material/glass/reinforced(src, 2)
- RefreshParts()
+/obj/machinery/bodyscanner/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/bodyscanner/Destroy()
if(console)
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index facb9e4402..bb1629c109 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -29,15 +29,10 @@
var/filtertext
-/obj/machinery/autolathe/New()
- ..()
+/obj/machinery/autolathe/Initialize()
+ . = ..()
wires = new(src)
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
+ default_apply_parts()
RefreshParts()
/obj/machinery/autolathe/Destroy()
diff --git a/code/game/machinery/biogenerator.dm b/code/game/machinery/biogenerator.dm
index 6f62b2e056..220d9fd013 100644
--- a/code/game/machinery/biogenerator.dm
+++ b/code/game/machinery/biogenerator.dm
@@ -15,17 +15,14 @@
var/build_eff = 1
var/eat_eff = 1
-/obj/machinery/biogenerator/New()
- ..()
+/obj/machinery/biogenerator/Initialize()
+ . = ..()
var/datum/reagents/R = new/datum/reagents(1000)
reagents = R
R.my_atom = src
beaker = new /obj/item/weapon/reagent_containers/glass/bottle(src)
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/biogenerator/on_reagent_change() //When the reagents change, change the icon as well.
update_icon()
diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm
index d40a89c202..b5a25b24a0 100644
--- a/code/game/machinery/bioprinter.dm
+++ b/code/game/machinery/bioprinter.dm
@@ -77,14 +77,10 @@
add_overlay("bioprinter_working")
//VOREStation Edit End
-/obj/machinery/organ_printer/New()
- ..()
-
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- RefreshParts()
-
+/obj/machinery/organ_printer/Initialize()
+ . = ..()
+ default_apply_parts()
+
/obj/machinery/organ_printer/examine(var/mob/user)
. = ..()
var/biomass = get_biomass_volume()
@@ -274,7 +270,7 @@
icon_state = "bioprinter"
circuit = /obj/item/weapon/circuitboard/bioprinter
-/obj/machinery/organ_printer/flesh/full/New()
+/obj/machinery/organ_printer/flesh/full/Initialize()
. = ..()
container = new /obj/item/weapon/reagent_containers/glass/bottle/biomass(src)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 15f9d65bc3..3dbe68fd29 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -29,6 +29,7 @@
var/short_range = 2
var/light_disabled = 0
+ var/in_use_lights = 0 // TO BE IMPLEMENTED - LIES.
var/alarm_on = 0
var/busy = 0
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index 917fed33eb..2b768fb3e6 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -13,13 +13,9 @@
var/chargelevel = -1
circuit = /obj/item/weapon/circuitboard/cell_charger
-/obj/machinery/cell_charger/New()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/stack/cable_coil(src, 5)
- RefreshParts()
- ..()
- return
+/obj/machinery/cell_charger/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/cell_charger/update_icon()
icon_state = "ccharger[charging ? 1 : 0]"
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index ebd740e5e5..e5fec765ca 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -46,17 +46,9 @@
var/list/containers = list() // Beakers for our liquid biomass
var/container_limit = 3 // How many beakers can the machine hold?
-/obj/machinery/clonepod/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
-
- RefreshParts()
+/obj/machinery/clonepod/Initialize()
+ . = ..()
+ default_apply_parts()
update_icon()
/obj/machinery/clonepod/attack_ai(mob/user as mob)
diff --git a/code/game/machinery/computer/shutoff_monitor.dm b/code/game/machinery/computer/shutoff_monitor.dm
index e2413c5e21..89cd4127db 100644
--- a/code/game/machinery/computer/shutoff_monitor.dm
+++ b/code/game/machinery/computer/shutoff_monitor.dm
@@ -2,7 +2,7 @@
name = "automated shutoff valve monitor"
desc = "Console used to remotely monitor shutoff valves on the station."
icon_keyboard = "power_key"
- icon_screen = "power:0"
+ icon_screen = "power_monitor"
light_color = "#a97faa"
circuit = /obj/item/weapon/circuitboard/shutoff_monitor
var/datum/nano_module/shutoff_monitor/monitor
diff --git a/code/game/machinery/computer/timeclock_vr.dm b/code/game/machinery/computer/timeclock_vr.dm
index 42e78683ec..85924d79f6 100644
--- a/code/game/machinery/computer/timeclock_vr.dm
+++ b/code/game/machinery/computer/timeclock_vr.dm
@@ -154,6 +154,7 @@
&& !job.whitelist_only \
&& !jobban_isbanned(user,job.title) \
&& job.player_old_enough(user.client) \
+ && job.player_has_enough_playtime(user.client) \
&& job.pto_type == department \
&& !job.disallow_jobhop \
&& job.timeoff_factor > 0
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm
index 41e3297c2b..4393417e26 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock_electronics.dm
@@ -64,7 +64,7 @@
if (usr.stat || usr.restrained() || (!ishuman(usr) && !istype(usr,/mob/living/silicon)))
return
if (href_list["close"])
- usr << browse(null, "window=airlock")
+ usr << browse(null, "window=airlock_electronics")
return
if (href_list["login"])
diff --git a/code/game/machinery/exonet_node.dm b/code/game/machinery/exonet_node.dm
index 1813d2dc71..b9b95e103c 100644
--- a/code/game/machinery/exonet_node.dm
+++ b/code/game/machinery/exonet_node.dm
@@ -21,21 +21,9 @@
// Proc: New()
// Parameters: None
// Description: Adds components to the machine for deconstruction.
-/obj/machinery/exonet_node/map/New()
- ..()
-
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/ansible(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/crystal(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/treatment(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/treatment(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- RefreshParts()
-
+/obj/machinery/exonet_node/map/Initialize()
+ . = ..()
+ default_apply_parts()
desc = "This machine is one of many, many nodes inside [using_map.starsys_name]'s section of the Exonet, connecting the [using_map.station_short] to the rest of the system, at least \
electronically."
@@ -187,7 +175,7 @@
// Description: This writes to the logs list, so that people can see what people are doing on the Exonet ingame. Note that this is not an admin logging function.
// Communicators are already logged seperately.
/obj/machinery/exonet_node/proc/write_log(var/origin_address, var/target_address, var/data_type, var/content)
- //var/timestamp = time2text(station_time_in_ticks, "hh:mm:ss")
+ //var/timestamp = time2text(station_time_in_ds, "hh:mm:ss")
var/timestamp = "[stationdate2text()] [stationtime2text()]"
var/msg = "[timestamp] | FROM [origin_address] TO [target_address] | TYPE: [data_type] | CONTENT: [content]"
logs.Add(msg)
diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm
index a0ef0503fd..42f7b681b7 100644
--- a/code/game/machinery/jukebox.dm
+++ b/code/game/machinery/jukebox.dm
@@ -54,8 +54,8 @@
new/datum/track("Russkiy rep Diskoteka", 'sound/music/russianrapdisco.ogg')
)
-/obj/machinery/media/jukebox/New()
- ..()
+/obj/machinery/media/jukebox/Initialize()
+ . = ..()
default_apply_parts()
wires = new/datum/wires/jukebox(src)
update_icon()
@@ -63,7 +63,7 @@
/obj/machinery/media/jukebox/Destroy()
qdel(wires)
wires = null
- ..()
+ return ..()
// On initialization, copy our tracks from the global list
/obj/machinery/media/jukebox/Initialize()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 3871908ff2..b126376ecc 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -121,13 +121,17 @@ Class Procs:
if(ispath(circuit))
circuit = new circuit(src)
-/obj/machinery/Initialize()
+/obj/machinery/Initialize(var/mapload)
. = ..()
global.machines += src
+ if(ispath(circuit))
+ circuit = new circuit(src)
if(!speed_process)
START_MACHINE_PROCESSING(src)
else
START_PROCESSING(SSfastprocess, src)
+ if(!mapload)
+ power_change()
/obj/machinery/Destroy()
if(!speed_process)
@@ -452,6 +456,7 @@ Class Procs:
return 1
/datum/proc/apply_visual(mob/M)
+ M.sight = 0 //Just reset their mesons and stuff so they can't use them, by default.
return
/datum/proc/remove_visual(mob/M)
diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm
index 7c184c27de..25805c694e 100644
--- a/code/game/machinery/mass_driver.dm
+++ b/code/game/machinery/mass_driver.dm
@@ -17,16 +17,8 @@
var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess.
/obj/machinery/mass_driver/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/spring(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/stack/cable_coil(src, 5)
- RefreshParts()
+ . = ..()
+ default_apply_parts()
/obj/machinery/mass_driver/attackby(var/obj/item/I, mob/user)
if(default_deconstruction_screwdriver(user, I))
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 883a963fa2..9fd9f74999 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -79,7 +79,7 @@
newMsg.body = msg
newMsg.time_stamp = "[stationtime2text()]"
newMsg.is_admin_message = adminMessage
- newMsg.post_time = round_duration_in_ticks // Should be almost universally unique
+ newMsg.post_time = round_duration_in_ds // Should be almost universally unique
if(message_type)
newMsg.message_type = message_type
if(photo)
diff --git a/code/game/machinery/pda_multicaster.dm b/code/game/machinery/pda_multicaster.dm
index 29de5307cf..29416e828e 100644
--- a/code/game/machinery/pda_multicaster.dm
+++ b/code/game/machinery/pda_multicaster.dm
@@ -23,17 +23,9 @@
"cargo" = new /obj/item/device/pda/multicaster/cargo(src),
"civilian" = new /obj/item/device/pda/multicaster/civilian(src))
-/obj/machinery/pda_multicaster/prebuilt/New()
- ..()
-
- component_parts = list()
- component_parts += new /obj/item/weapon/circuitboard/telecomms/pda_multicaster(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/ansible(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/treatment(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- RefreshParts()
+/obj/machinery/pda_multicaster/prebuilt/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/pda_multicaster/Destroy()
for(var/atom/movable/AM in contents)
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 06acd97d0b..2b8b8aa637 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -17,13 +17,9 @@
var/portable = 1
circuit = /obj/item/weapon/circuitboard/recharger
-/obj/machinery/recharger/New()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/stack/cable_coil(src, 5)
- RefreshParts()
- ..()
- return
+/obj/machinery/recharger/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/recharger/examine(mob/user)
. = ..()
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index 75cc5b55cc..c683a56c0e 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -22,17 +22,9 @@
var/weld_power_use = 2300 // power used per point of brute damage repaired. 2.3 kW ~ about the same power usage of a handheld arc welder
var/wire_power_use = 500 // power used per point of burn damage repaired.
-/obj/machinery/recharge_station/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/cell/high(src)
- component_parts += new /obj/item/stack/cable_coil(src, 5)
- RefreshParts()
-
+/obj/machinery/recharge_station/Initialize()
+ . = ..()
+ default_apply_parts()
update_icon()
/obj/machinery/recharge_station/proc/has_cell_power()
diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm
index 165df28298..46acbb4fdc 100644
--- a/code/game/machinery/telecomms/broadcaster.dm
+++ b/code/game/machinery/telecomms/broadcaster.dm
@@ -32,13 +32,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
/obj/machinery/telecomms/processor/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/crystal(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser/high(src)
- component_parts += new /obj/item/stack/cable_coil(src, 1)
+ default_apply_parts()
/obj/machinery/telecomms/broadcaster/proc/link_radio(var/obj/item/device/radio/R)
if(!istype(R))
diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm
index 1d765375be..e89b9aa726 100644
--- a/code/game/machinery/telecomms/telecomunications.dm
+++ b/code/game/machinery/telecomms/telecomunications.dm
@@ -266,13 +266,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/receiver/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/ansible(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/telecomms/receiver/proc/link_radio(var/obj/item/device/radio/R)
if(!istype(R))
@@ -355,13 +349,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/hub/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
if(is_freq_listening(signal))
@@ -401,13 +389,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/relay/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/telecomms/relay/forceMove(var/newloc)
. = ..(newloc)
@@ -464,12 +446,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/bus/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/stack/cable_coil(src, 1)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/telecomms/bus/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
@@ -525,17 +502,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/processor/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/treatment(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/treatment(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/amplifier(src)
- component_parts += new /obj/item/weapon/stock_parts/subspace/analyzer(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/telecomms/processor/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
@@ -596,12 +563,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/server/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/subspace/sub_filter(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/stack/cable_coil(src, 1)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index c27de5c31c..1cf1e901fb 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -1,3 +1,6 @@
+//////
+////// Teleporter computer
+//////
/obj/machinery/computer/teleporter
name = "teleporter control console"
desc = "Used to control a linked teleportation Hub and Station."
@@ -5,23 +8,23 @@
icon_screen = "teleport"
circuit = /obj/item/weapon/circuitboard/teleporter
dir = 4
- var/obj/item/locked = null
var/id = null
var/one_time_use = 0 //Used for one-time-use teleport cards (such as clown planet coordinates.)
//Setting this to 1 will set locked to null after a player enters the portal and will not allow hand-teles to open portals to that location.
+ var/datum/nano_module/program/teleport_control/teleport_control
/obj/machinery/computer/teleporter/New()
id = "[rand(1000, 9999)]"
..()
underlays.Cut()
underlays += image('icons/obj/stationobjs_vr.dmi', icon_state = "telecomp-wires") //VOREStation Edit: different direction for wires to account for dirs
- return
+ teleport_control = new(src)
/obj/machinery/computer/teleporter/Initialize()
. = ..()
- var/obj/machinery/teleport/station/station
- var/obj/machinery/teleport/hub/hub
-
+ var/obj/machinery/teleport/station/station = null
+ var/obj/machinery/teleport/hub/hub = null
+
// Search surrounding turfs for the station, and then search the station's surrounding turfs for the hub.
for(var/direction in cardinal)
station = locate(/obj/machinery/teleport/station, get_step(src, direction))
@@ -34,9 +37,15 @@
if(istype(station))
station.com = hub
+ teleport_control.hub = hub
if(istype(hub))
hub.com = src
+ teleport_control.station = station
+
+/obj/machinery/computer/teleporter/Destroy()
+ qdel_null(teleport_control)
+ return ..()
/obj/machinery/computer/teleporter/attackby(I as obj, mob/living/user as mob)
if(istype(I, /obj/item/weapon/card/data/))
@@ -74,7 +83,7 @@
else
for(var/mob/O in hearers(src, null))
O.show_message("Locked In", 2)
- locked = L
+ teleport_control.locked = L
one_time_use = 1
add_fingerprint(usr)
@@ -86,57 +95,109 @@
/obj/machinery/teleport/station/attack_ai()
attack_hand()
-/obj/machinery/computer/teleporter/attack_hand(user as mob)
- if(..()) return
+/obj/machinery/computer/teleporter/attack_ai(mob/user)
+ ui_interact(user)
- /* Ghosts can't use this one because it's a direct selection */
- if(istype(user, /mob/observer/dead)) return
+/obj/machinery/computer/teleporter/attack_hand(mob/user)
+ add_fingerprint(user)
+ if(stat & (BROKEN|NOPOWER))
+ return
+ ui_interact(user)
- var/list/L = list()
- var/list/areaindex = list()
+/obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ teleport_control.ui_interact(user, ui_key, ui, force_open)
- for(var/obj/item/device/radio/beacon/R in all_beacons)
- var/turf/T = get_turf(R)
- if(!T)
- continue
- if(!(T.z in using_map.player_levels))
- continue
- var/tmpname = T.loc.name
- if(areaindex[tmpname])
- tmpname = "[tmpname] ([++areaindex[tmpname]])"
- else
- areaindex[tmpname] = 1
- L[tmpname] = R
+/obj/machinery/computer/teleporter/interact(mob/user)
+ teleport_control.ui_interact(user)
- for (var/obj/item/weapon/implant/tracking/I in all_tracking_implants)
- if(!I.implanted || !ismob(I.loc))
- continue
- else
- var/mob/M = I.loc
- if(M.stat == 2)
- if(M.timeofdeath + 6000 < world.time)
- continue
- var/turf/T = get_turf(M)
- if(T) continue
- if(T.z == 2) continue
- var/tmpname = M.real_name
+//////
+////// Nano-module for teleporter
+//////
+/datum/nano_module/program/teleport_control
+ name = "Teleporter Control"
+ var/locked_name = "Not Locked"
+ var/obj/item/locked = null
+ var/obj/machinery/teleport/station/station = null
+ var/obj/machinery/teleport/hub/hub = null
+
+/datum/nano_module/program/teleport_control/Topic(href, href_list)
+ if(..()) return 1
+
+ if(href_list["select_target"])
+ var/list/L = list()
+ var/list/areaindex = list()
+
+ for(var/obj/item/device/radio/beacon/R in all_beacons)
+ var/turf/T = get_turf(R)
+ if(!T)
+ continue
+ if(!(T.z in using_map.player_levels))
+ continue
+ var/tmpname = T.loc.name
if(areaindex[tmpname])
tmpname = "[tmpname] ([++areaindex[tmpname]])"
else
areaindex[tmpname] = 1
- L[tmpname] = I
+ L[tmpname] = R
- var/desc = input("Please select a location to lock in.", "Locking Computer") in L|null
- if(!desc)
- return
- if(get_dist(src, usr) > 1 && !issilicon(usr))
- return
+ for (var/obj/item/weapon/implant/tracking/I in all_tracking_implants)
+ if(!I.implanted || !ismob(I.loc))
+ continue
+ else
+ var/mob/M = I.loc
+ if(M.stat == 2)
+ if(M.timeofdeath + 6000 < world.time)
+ continue
+ var/turf/T = get_turf(M)
+ if(T) continue
+ if(T.z == 2) continue
+ var/tmpname = M.real_name
+ if(areaindex[tmpname])
+ tmpname = "[tmpname] ([++areaindex[tmpname]])"
+ else
+ areaindex[tmpname] = 1
+ L[tmpname] = I
- locked = L[desc]
- for(var/mob/O in hearers(src, null))
- O.show_message("Locked In", 2)
- add_fingerprint(usr)
- return
+ var/desc = input("Please select a location to lock in.", "Locking Menu") in L|null
+ if(!desc)
+ return 0
+ if(get_dist(host, usr) > 1 && !issilicon(usr))
+ return 0
+
+ locked = L[desc]
+ locked_name = desc
+ return 1
+
+ if(href_list["test_fire"])
+ station?.testfire()
+ return 1
+
+ if(href_list["toggle_on"])
+ if(!station)
+ return 0
+
+ if(station.engaged)
+ station.disengage()
+ else
+ station.engage()
+
+ return 1
+
+/datum/nano_module/program/teleport_control/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["locked_name"] = locked_name ? locked_name : "No Target"
+ data["station_connected"] = station ? 1 : 0
+ data["hub_connected"] = hub ? 1 : 0
+ data["calibrated"] = hub ? hub.accurate : 0
+ data["teleporter_on"] = station ? station.engaged : 0
+
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "teleport_control.tmpl", "Teleport Control Console", 400, 500, state = state)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
/obj/machinery/computer/teleporter/verb/set_id(t as text)
set category = "Object"
@@ -158,6 +219,9 @@
if(!T || istype(T, /area)) return null
return T
+//////
+////// Root of all the machinery
+//////
/obj/machinery/teleport
name = "teleport"
icon = 'icons/obj/stationobjs.dmi'
@@ -165,6 +229,9 @@
anchored = 1.0
var/lockeddown = 0
+//////
+////// The part you step into
+//////
/obj/machinery/teleport/hub
name = "teleporter hub"
desc = "It's the hub of a teleporting machine."
@@ -178,22 +245,15 @@
circuit = /obj/item/weapon/circuitboard/teleporter_hub
var/obj/machinery/computer/teleporter/com
-/obj/machinery/teleport/hub/New()
- ..()
- underlays.Cut()
+/obj/machinery/teleport/hub/Initialize()
+ . = ..()
underlays += image('icons/obj/stationobjs.dmi', icon_state = "tele-wires")
+ default_apply_parts()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/stack/cable_coil(src, 10)
- RefreshParts()
+/obj/machinery/teleport/hub/Destroy()
+ com?.teleport_control.hub = null
+ com = null
+ return ..()
/obj/machinery/teleport/hub/Bumped(M as mob|obj)
spawn()
@@ -205,7 +265,7 @@
/obj/machinery/teleport/hub/proc/teleport(atom/movable/M as mob|obj)
if(!com)
return
- if(!com.locked)
+ if(!com.teleport_control.locked)
for(var/mob/O in hearers(src, null))
O.show_message("Failure: Cannot authenticate locked on coordinates. Please reinstate coordinate matrix.")
return
@@ -221,11 +281,11 @@
if(prob(5) && !accurate) //oh dear a problem, put em in deep space
do_teleport(M, locate(rand((2*TRANSITIONEDGE), world.maxx - (2*TRANSITIONEDGE)), rand((2*TRANSITIONEDGE), world.maxy - (2*TRANSITIONEDGE)), 3), 2)
else
- do_teleport(M, com.locked) //dead-on precision
+ do_teleport(M, com.teleport_control.locked) //dead-on precision
if(com.one_time_use) //Make one-time-use cards only usable one time!
com.one_time_use = 0
- com.locked = null
+ com.teleport_control.locked = null
else
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(5, 1, src)
@@ -235,92 +295,10 @@
for(var/mob/B in hearers(src, null))
B.show_message("Test fire completed.")
return
-/*
-/proc/do_teleport(atom/movable/M as mob|obj, atom/destination, precision)
- if(istype(M, /obj/effect))
- qdel(M)
- return
- if(istype(M, /obj/item/weapon/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite
- for(var/mob/O in viewers(M, null))
- O.show_message(text("The [] bounces off of the portal!", M.name), 1)
- return
- if(istype(M, /mob/living))
- var/mob/living/MM = M
- if(MM.check_contents_for(/obj/item/weapon/disk/nuclear))
- to_chat(MM, "Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through.")
- return
- var/disky = 0
- for (var/atom/O in M.contents) //I'm pretty sure this accounts for the maximum amount of container in container stacking. --NeoFite
- if(istype(O, /obj/item/weapon/storage) || istype(O, /obj/item/weapon/gift))
- for (var/obj/OO in O.contents)
- if(istype(OO, /obj/item/weapon/storage) || istype(OO, /obj/item/weapon/gift))
- for (var/obj/OOO in OO.contents)
- if(istype(OOO, /obj/item/weapon/disk/nuclear))
- disky = 1
- if(istype(OO, /obj/item/weapon/disk/nuclear))
- disky = 1
- if(istype(O, /obj/item/weapon/disk/nuclear))
- disky = 1
- if(istype(O, /mob/living))
- var/mob/living/MM = O
- if(MM.check_contents_for(/obj/item/weapon/disk/nuclear))
- disky = 1
- if(disky)
- for(var/mob/P in viewers(M, null))
- P.show_message(text("The [] bounces off of the portal!", M.name), 1)
- return
-
-//Bags of Holding cause bluespace teleportation to go funky. --NeoFite
- if(istype(M, /mob/living))
- var/mob/living/MM = M
- if(MM.check_contents_for(/obj/item/weapon/storage/backpack/holding))
- to_chat(MM, "The Bluespace interface on your Bag of Holding interferes with the teleport!")
- precision = rand(1,100)
- if(istype(M, /obj/item/weapon/storage/backpack/holding))
- precision = rand(1,100)
- for (var/atom/O in M.contents) //I'm pretty sure this accounts for the maximum amount of container in container stacking. --NeoFite
- if(istype(O, /obj/item/weapon/storage) || istype(O, /obj/item/weapon/gift))
- for (var/obj/OO in O.contents)
- if(istype(OO, /obj/item/weapon/storage) || istype(OO, /obj/item/weapon/gift))
- for (var/obj/OOO in OO.contents)
- if(istype(OOO, /obj/item/weapon/storage/backpack/holding))
- precision = rand(1,100)
- if(istype(OO, /obj/item/weapon/storage/backpack/holding))
- precision = rand(1,100)
- if(istype(O, /obj/item/weapon/storage/backpack/holding))
- precision = rand(1,100)
- if(istype(O, /mob/living))
- var/mob/living/MM = O
- if(MM.check_contents_for(/obj/item/weapon/storage/backpack/holding))
- precision = rand(1,100)
-
- var/turf/destturf = get_turf(destination)
-
- var/tx = destturf.x + rand(precision * -1, precision)
- var/ty = destturf.y + rand(precision * -1, precision)
-
- var/tmploc
-
- if(ismob(destination.loc)) //If this is an implant.
- tmploc = locate(tx, ty, destturf.z)
- else
- tmploc = locate(tx, ty, destination.z)
-
- if(tx == destturf.x && ty == destturf.y && (istype(destination.loc, /obj/structure/closet) || istype(destination.loc, /obj/structure/closet/secure_closet)))
- tmploc = destination.loc
-
- if(tmploc==null)
- return
-
- M.loc = tmploc
- sleep(2)
-
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, M)
- s.start()
- return
-*/
+//////
+////// The middle part
+//////
/obj/machinery/teleport/station
name = "station"
desc = "It's the station thingy of a teleport thingy." //seriously, wtf.
@@ -335,29 +313,15 @@
circuit = /obj/item/weapon/circuitboard/teleporter_station
var/obj/machinery/teleport/hub/com
-/obj/machinery/teleport/station/New()
- ..()
- overlays.Cut()
- overlays += image('icons/obj/stationobjs.dmi', icon_state = "controller-wires")
+/obj/machinery/teleport/station/Initialize()
+ . = ..()
+ add_overlay("controller-wires")
+ default_apply_parts()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/stack/cable_coil(src, 10)
- RefreshParts()
-
-/obj/machinery/teleport/station/attackby(var/obj/item/weapon/W)
- attack_hand()
-
-/obj/machinery/teleport/station/attack_ai()
- attack_hand()
-
-/obj/machinery/teleport/station/attack_hand()
- if(engaged)
- disengage()
- else
- engage()
+/obj/machinery/teleport/station/Destroy()
+ com?.com?.teleport_control.station = null
+ com = null
+ return ..()
/obj/machinery/teleport/station/proc/engage()
if(stat & (BROKEN|NOPOWER))
@@ -389,27 +353,17 @@
engaged = 0
return
-/obj/machinery/teleport/station/verb/testfire()
- set name = "Test Fire Teleporter"
- set category = "Object"
- set src in oview(1)
-
- if(stat & (BROKEN|NOPOWER) || !istype(usr,/mob/living))
+/obj/machinery/teleport/station/proc/testfire()
+ if(!com || active)
return
- if(com && !active)
- active = 1
- for(var/mob/O in hearers(src, null))
- O.show_message("Test firing!", 2)
- com.teleport()
- use_power(5000)
- flick(src, "controller-c") //VOREStation Add
+ active = TRUE
+ visible_message("Test firing!")
+ com.teleport()
+ use_power(5000)
+ flick(src, "controller-c") //VOREStation Add
- spawn(30)
- active=0
-
- add_fingerprint(usr)
- return
+ VARSET_IN(src, active, FALSE, 3 SECONDS)
/obj/machinery/teleport/station/power_change()
..()
diff --git a/code/game/machinery/virtual_reality/vr_console.dm b/code/game/machinery/virtual_reality/vr_console.dm
index 8a417a98bc..75236c3cd2 100644
--- a/code/game/machinery/virtual_reality/vr_console.dm
+++ b/code/game/machinery/virtual_reality/vr_console.dm
@@ -23,13 +23,9 @@
active_power_usage = 200
light_color = "#FF0000"
-/obj/machinery/vr_sleeper/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/stack/material/glass/reinforced(src, 2)
-
- RefreshParts()
+/obj/machinery/vr_sleeper/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/vr_sleeper/Initialize()
. = ..()
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index 2a6b90cdc6..edb8e56155 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -29,14 +29,10 @@
/obj/item/clothing/head/helmet/space
)
-/obj/machinery/washing_machine/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- RefreshParts()
-
+/obj/machinery/washing_machine/Initialize()
+ . = ..()
+ default_apply_parts()
+
/obj/machinery/washing_machine/verb/start()
set name = "Start Washing"
set category = "Object"
diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm
index 5584590f92..c2288709e5 100644
--- a/code/game/mecha/mech_bay.dm
+++ b/code/game/mecha/mech_bay.dm
@@ -12,15 +12,9 @@
var/charge = 45
var/repair = 0
-/obj/machinery/mech_recharger/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- RefreshParts()
+/obj/machinery/mech_recharger/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/mech_recharger/Crossed(var/obj/mecha/M)
. = ..()
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index a881cdb720..734c5bfa4c 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -26,22 +26,11 @@
var/category = null
var/sync_message = ""
-/obj/machinery/mecha_part_fabricator/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- RefreshParts()
-
- files = new /datum/research(src) //Setup the research data holder.
- return
-
/obj/machinery/mecha_part_fabricator/Initialize()
- update_categories()
. = ..()
+ default_apply_parts()
+ files = new /datum/research(src) //Setup the research data holder.
+ update_categories()
/obj/machinery/mecha_part_fabricator/process()
..()
diff --git a/code/game/mecha/mech_prosthetics.dm b/code/game/mecha/mech_prosthetics.dm
index 5e93378a0c..bb2c5f87ce 100644
--- a/code/game/mecha/mech_prosthetics.dm
+++ b/code/game/mecha/mech_prosthetics.dm
@@ -29,18 +29,11 @@
var/species = "Human"
var/sync_message = ""
-/obj/machinery/pros_fabricator/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- RefreshParts()
-
+/obj/machinery/pros_fabricator/Initialize()
+ . = ..()
+ default_apply_parts()
+
files = new /datum/research(src) //Setup the research data holder.
- return
/obj/machinery/pros_fabricator/Initialize()
. = ..()
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index ba863c8c31..a5516c4c33 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -95,9 +95,9 @@
var/list/cargo = list()
var/cargo_capacity = 3
- var/static/image/radial_image_eject = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_eject"),
- var/static/image/radial_image_airtoggle = image(icon= 'icons/mob/radial.dmi', icon_state = "radial_airtank"),
- var/static/image/radial_image_lighttoggle = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_light"),
+ var/static/image/radial_image_eject = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_eject")
+ var/static/image/radial_image_airtoggle = image(icon= 'icons/mob/radial.dmi', icon_state = "radial_airtank")
+ var/static/image/radial_image_lighttoggle = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_light")
var/static/image/radial_image_statpanel = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_examine2")
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index fb82e6515a..f2a15be551 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -49,6 +49,9 @@
if(triggered)
return
+ if(istype(M, /obj/mecha))
+ explode(M)
+
if(istype(M, /mob/living/))
if(!M.hovering)
explode(M)
@@ -79,7 +82,7 @@
triggered = 1
s.set_up(3, 1, src)
s.start()
- if(M)
+ if(istype(M))
M.radiation += 50
randmutb(M)
domutcheck(M,null)
@@ -96,7 +99,7 @@
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread()
s.set_up(3, 1, src)
s.start()
- if(M)
+ if(istype(M))
M.Stun(30)
visible_message("\The [src.name] flashes violently before disintegrating!")
spawn(0)
@@ -136,7 +139,10 @@
triggered = 1
s.set_up(3, 1, src)
s.start()
- if(M)
+ if(istype(M, /obj/mecha))
+ var/obj/mecha/E = M
+ M = E.occupant
+ if(istype(M))
qdel(M.client)
spawn(0)
qdel(s)
@@ -195,7 +201,7 @@
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread()
s.set_up(3, 1, src)
s.start()
- if(M)
+ if(istype(M))
M.adjust_fire_stacks(5)
M.fire_act()
visible_message("\The [src.name] bursts into flames!")
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 795355a6e3..deddf50ca5 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -7,7 +7,7 @@
layer = ABOVE_TURF_LAYER
anchored = 1
w_class = ITEMSIZE_LARGE
- canhear_range = 2
+ canhear_range = 7 //VOREStation Edit
flags = NOBLOODY
var/circuit = /obj/item/weapon/circuitboard/intercom
var/number = 0
@@ -195,7 +195,19 @@
icon_state = "intercom_open"
else
icon_state = initial(icon_state)
+//VOREStation Add Start
+/obj/item/device/radio/intercom/AICtrlClick(var/mob/user)
+ ToggleBroadcast()
+ to_chat(user, "\The [src]'s microphone is now [broadcasting ? "enabled" : "disabled"].")
+/obj/item/device/radio/intercom/AIAltClick(var/mob/user)
+ if(frequency == AI_FREQ)
+ set_frequency(initial(frequency))
+ to_chat(user, "\The [src]'s frequency is now set to Default.")
+ else
+ set_frequency(AI_FREQ)
+ to_chat(user, "\The [src]'s frequency is now set to AI Private.")
+//VOREStation Add End
/obj/item/device/radio/intercom/locked
var/locked_frequency
diff --git a/code/game/objects/items/weapons/RCD_vr.dm b/code/game/objects/items/weapons/RCD_vr.dm
index 5cfc822efa..f4089e9b9c 100644
--- a/code/game/objects/items/weapons/RCD_vr.dm
+++ b/code/game/objects/items/weapons/RCD_vr.dm
@@ -9,9 +9,9 @@
var/ammostate
var/list/effects = list()
- var/static/image/radial_image_airlock = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock"),
- var/static/image/radial_image_decon = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"),
- var/static/image/radial_image_grillewind = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"),
+ var/static/image/radial_image_airlock = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock")
+ var/static/image/radial_image_decon = image(icon= 'icons/mob/radial.dmi', icon_state = "delete")
+ var/static/image/radial_image_grillewind = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow")
var/static/image/radial_image_floorwall = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor")
// Ammo for the (non-electric) RCDs.
diff --git a/code/game/objects/items/weapons/storage/internal.dm b/code/game/objects/items/weapons/storage/internal.dm
index 498f6aa5d3..00d6f79402 100644
--- a/code/game/objects/items/weapons/storage/internal.dm
+++ b/code/game/objects/items/weapons/storage/internal.dm
@@ -1,90 +1,90 @@
-//A storage item intended to be used by other items to provide storage functionality.
-//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow.
-/obj/item/weapon/storage/internal
- preserve_item = 1
- var/obj/item/master_item
-
-/obj/item/weapon/storage/internal/New(obj/item/MI)
- master_item = MI
- loc = master_item
- //name = master_item.name //VOREStation Removal
- verbs -= /obj/item/verb/verb_pickup //make sure this is never picked up.
- ..()
-
-/obj/item/weapon/storage/internal/Destroy()
- master_item = null
- . = ..()
-
-/obj/item/weapon/storage/internal/attack_hand()
- return //make sure this is never picked up
-
-/obj/item/weapon/storage/internal/mob_can_equip()
- return 0 //make sure this is never picked up
-
-//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items.
-//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open()
-//However they are helpful for allowing the master item to pretend it is a storage item itself.
-//If you are using these you will probably want to override attackby() as well.
-//See /obj/item/clothing/suit/storage for an example.
-
-//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour.
-//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of
-//doing it without the ability to call another proc's parent, really.
-/obj/item/weapon/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj)
- if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist
-
- if (istype(user.loc,/obj/mecha)) // stops inventory actions in a mech
- return 0
-
- if(over_object == user && Adjacent(user)) // this must come before the screen objects only block
- src.open(user)
- return 0
-
- if (!( istype(over_object, /obj/screen) ))
- return 1
-
- //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away.
- //there's got to be a better way of doing this...
- if (!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user))
- return 0
-
- if (!( user.restrained() ) && !( user.stat ))
- switch(over_object.name)
- if("r_hand")
- user.unEquip(master_item)
- user.put_in_r_hand(master_item)
- if("l_hand")
- user.unEquip(master_item)
- user.put_in_l_hand(master_item)
- master_item.add_fingerprint(user)
- return 0
- return 0
-
-//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour.
-//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise.
-//It's strange, but no other way of doing it without the ability to call another proc's parent, really.
-/obj/item/weapon/storage/internal/proc/handle_attack_hand(mob/user as mob)
-
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket.
- H.put_in_hands(master_item)
- H.l_store = null
- return 0
- if(H.r_store == master_item && !H.get_active_hand())
- H.put_in_hands(master_item)
- H.r_store = null
- return 0
-
- src.add_fingerprint(user)
- if (master_item.loc == user)
- src.open(user)
- return 0
-
- for(var/mob/M in range(1, master_item.loc))
- if (M.s_active == src)
- src.close(M)
- return 1
-
-/obj/item/weapon/storage/internal/Adjacent(var/atom/neighbor)
- return master_item.Adjacent(neighbor)
+//A storage item intended to be used by other items to provide storage functionality.
+//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow.
+/obj/item/weapon/storage/internal
+ preserve_item = 1
+ var/obj/item/master_item
+
+/obj/item/weapon/storage/internal/New(obj/item/MI)
+ master_item = MI
+ loc = master_item
+ //name = master_item.name //VOREStation Removal
+ verbs -= /obj/item/verb/verb_pickup //make sure this is never picked up.
+ ..()
+
+/obj/item/weapon/storage/internal/Destroy()
+ master_item = null
+ . = ..()
+
+/obj/item/weapon/storage/internal/attack_hand()
+ return //make sure this is never picked up
+
+/obj/item/weapon/storage/internal/mob_can_equip(M as mob, slot, disable_warning = 0)
+ return 0 //make sure this is never picked up
+
+//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items.
+//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open()
+//However they are helpful for allowing the master item to pretend it is a storage item itself.
+//If you are using these you will probably want to override attackby() as well.
+//See /obj/item/clothing/suit/storage for an example.
+
+//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour.
+//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of
+//doing it without the ability to call another proc's parent, really.
+/obj/item/weapon/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj)
+ if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist
+
+ if (istype(user.loc,/obj/mecha)) // stops inventory actions in a mech
+ return 0
+
+ if(over_object == user && Adjacent(user)) // this must come before the screen objects only block
+ src.open(user)
+ return 0
+
+ if (!( istype(over_object, /obj/screen) ))
+ return 1
+
+ //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away.
+ //there's got to be a better way of doing this...
+ if (!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user))
+ return 0
+
+ if (!( user.restrained() ) && !( user.stat ))
+ switch(over_object.name)
+ if("r_hand")
+ user.unEquip(master_item)
+ user.put_in_r_hand(master_item)
+ if("l_hand")
+ user.unEquip(master_item)
+ user.put_in_l_hand(master_item)
+ master_item.add_fingerprint(user)
+ return 0
+ return 0
+
+//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour.
+//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise.
+//It's strange, but no other way of doing it without the ability to call another proc's parent, really.
+/obj/item/weapon/storage/internal/proc/handle_attack_hand(mob/user as mob)
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket.
+ H.put_in_hands(master_item)
+ H.l_store = null
+ return 0
+ if(H.r_store == master_item && !H.get_active_hand())
+ H.put_in_hands(master_item)
+ H.r_store = null
+ return 0
+
+ src.add_fingerprint(user)
+ if (master_item.loc == user)
+ src.open(user)
+ return 0
+
+ for(var/mob/M in range(1, master_item.loc))
+ if (M.s_active == src)
+ src.close(M)
+ return 1
+
+/obj/item/weapon/storage/internal/Adjacent(var/atom/neighbor)
+ return master_item.Adjacent(neighbor)
diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm
index 95db86460e..a668075068 100644
--- a/code/game/objects/items/weapons/storage/wallets.dm
+++ b/code/game/objects/items/weapons/storage/wallets.dm
@@ -63,7 +63,7 @@
overlays.Cut()
if(front_id)
var/tiny_state = "id-generic"
- if("id-"+front_id.icon_state in icon_states(icon))
+ if("id-"+front_id.icon_state in cached_icon_states(icon))
tiny_state = "id-"+front_id.icon_state
var/image/tiny_image = new/image(icon, icon_state = tiny_state)
tiny_image.appearance_flags = RESET_COLOR
diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm
index fb33d8f30d..7d0947fbbf 100644
--- a/code/game/objects/items/weapons/teleportation.dm
+++ b/code/game/objects/items/weapons/teleportation.dm
@@ -147,11 +147,11 @@ Frequency:
if(com)
break
break
- if (istype(com, /obj/machinery/computer/teleporter) && com.locked && !com.one_time_use)
+ if (istype(com, /obj/machinery/computer/teleporter) && com.teleport_control.locked && !com.one_time_use)
if(R.icon_state == "tele1")
- L["[com.id] (Active)"] = com.locked
+ L["[com.id] (Active)"] = com.teleport_control.locked
else
- L["[com.id] (Inactive)"] = com.locked
+ L["[com.id] (Inactive)"] = com.teleport_control.locked
var/list/turfs = list( )
for(var/turf/T in orange(10))
if(T.x>world.maxx-8 || T.x<8) continue //putting them at the edge is dumb
diff --git a/code/game/objects/structures/barsign.dm b/code/game/objects/structures/barsign.dm
index cd1c448b2f..e54c75eebb 100644
--- a/code/game/objects/structures/barsign.dm
+++ b/code/game/objects/structures/barsign.dm
@@ -6,7 +6,7 @@
var/cult = 0
/obj/structure/sign/double/barsign/proc/get_valid_states(initial=1)
- . = icon_states(icon)
+ . = cached_icon_states(icon)
. -= "on"
. -= "narsiebistro"
. -= "empty"
diff --git a/code/game/objects/structures/cliff.dm b/code/game/objects/structures/cliff.dm
index c4caf4b7ab..66fb945988 100644
--- a/code/game/objects/structures/cliff.dm
+++ b/code/game/objects/structures/cliff.dm
@@ -114,7 +114,7 @@ two tiles on initialization, and which way a cliff is facing may change during m
var/subtraction_icon_state = "[icon_state]-subtract"
var/cache_string = "[icon_state]_[T.icon]_[T.icon_state]"
- if(T && subtraction_icon_state in icon_states(icon))
+ if(T && subtraction_icon_state in cached_icon_states(icon))
cut_overlays()
// If we've made the same icon before, just recycle it.
if(cache_string in GLOB.cliff_icon_cache)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 3df62610c9..2434d33e89 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -47,6 +47,9 @@
else
. += "There is a thick layer of silicate covering it."
+/obj/structure/window/examine_icon()
+ return icon(icon=initial(icon),icon_state=initial(icon_state))
+
/obj/structure/window/take_damage(var/damage = 0, var/sound_effect = 1)
var/initialhealth = health
diff --git a/code/game/turfs/flooring/flooring.dm b/code/game/turfs/flooring/flooring.dm
index 60157c1ee8..aa6f3b0e6f 100644
--- a/code/game/turfs/flooring/flooring.dm
+++ b/code/game/turfs/flooring/flooring.dm
@@ -26,9 +26,10 @@ var/list/flooring_types
var/name = "floor"
var/desc
var/icon
- var/icon_base
+ var/icon_base // initial base icon_state without edges or corners.
- var/has_base_range
+ var/has_base_range // This will pick between a range of 0 - x. Number icon_states accordingly.
+ // Note that this will append a 0 - x number automatically to icon_base, but NOT the dmi. Do icon_base = "grass", but name grass0 inside the dmi. etc etc.
var/has_damage_range
var/has_burn_range
var/damage_temperature
@@ -42,17 +43,69 @@ var/list/flooring_types
var/descriptor = "tiles"
var/flags
var/can_paint
- var/list/footstep_sounds = list() // key=species name, value = list of soundss
+ var/list/footstep_sounds = list() // key=species name, value = list of sounds,
+ // For instance, footstep_sounds = list("key" = list(sound.ogg))
/decl/flooring/grass
name = "grass"
desc = "Do they smoke grass out in space, Bowie? Or do they smoke AstroTurf?"
icon = 'icons/turf/flooring/grass.dmi'
icon_base = "grass"
- has_base_range = 3
+ has_base_range = 1
damage_temperature = T0C+80
flags = TURF_HAS_EDGES | TURF_REMOVE_SHOVEL
build_type = /obj/item/stack/tile/grass
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/grass1.ogg',
+ 'sound/effects/footstep/grass2.ogg',
+ 'sound/effects/footstep/grass3.ogg',
+ 'sound/effects/footstep/grass4.ogg'))
+
+/decl/flooring/grass/sif // Subtype for Sif's grass.
+ name = "growth"
+ desc = "A natural moss that has adapted to the sheer cold climate."
+ icon = 'icons/turf/outdoors.dmi'
+ icon_base = "grass_sif"
+ has_base_range = 1
+
+/decl/flooring/water
+ name = "water"
+ desc = "Water is wet, gosh, who knew!"
+ icon = 'icons/turf/outdoors.dmi'
+ icon_base = "seashallow"
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/water1.ogg',
+ 'sound/effects/footstep/water2.ogg',
+ 'sound/effects/footstep/water3.ogg',
+ 'sound/effects/footstep/water4.ogg'))
+
+/decl/flooring/sand
+ name = "sand"
+ desc = "I don't like sand. It's coarse and rough and irritating and it gets everywhere."
+ icon = 'icons/misc/beach.dmi'
+ icon_base = "sand"
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/HeavySand1.ogg',
+ 'sound/effects/footstep/HeavySand2.ogg',
+ 'sound/effects/footstep/HeavySand3.ogg',
+ 'sound/effects/footstep/HeavySand4.ogg'))
+
+/decl/flooring/sand/desert // Subtype of sand, desert.
+ name = "desert"
+ desc = "I don't like sand. It's coarse and rough and irritating and it gets everywhere."
+ icon = 'icons/turf/desert.dmi'
+ icon_base = "desert"
+
+/decl/flooring/mud
+ name = "mud"
+ desc = "STICKY AND WET!"
+ icon = 'icons/turf/outdoors.dmi'
+ icon_base = "mud_dark"
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/mud1.ogg',
+ 'sound/effects/footstep/mud2.ogg',
+ 'sound/effects/footstep/mud3.ogg',
+ 'sound/effects/footstep/mud4.ogg'))
/decl/flooring/asteroid
name = "coarse sand"
@@ -61,6 +114,26 @@ var/list/flooring_types
icon_base = "asteroid"
flags = TURF_HAS_EDGES | TURF_REMOVE_SHOVEL
build_type = null
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/asteroid1.ogg',
+ 'sound/effects/footstep/asteroid2.ogg',
+ 'sound/effects/footstep/asteroid3.ogg',
+ 'sound/effects/footstep/asteroid4.ogg',
+ 'sound/effects/footstep/asteroid5.ogg'))
+
+/decl/flooring/dirt
+ name = "dirt"
+ desc = "Gritty and unpleasant, just like dirt."
+ icon = 'icons/turf/outdoors.dmi'
+ icon_base = "dirt-dark"
+ flags = TURF_HAS_EDGES | TURF_REMOVE_SHOVEL
+ build_type = null
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/asteroid1.ogg',
+ 'sound/effects/footstep/asteroid2.ogg',
+ 'sound/effects/footstep/asteroid3.ogg',
+ 'sound/effects/footstep/asteroid4.ogg',
+ 'sound/effects/footstep/asteroid5.ogg'))
/decl/flooring/snow
name = "snow"
@@ -216,7 +289,7 @@ var/list/flooring_types
icon_base = "lino"
can_paint = 1
build_type = /obj/item/stack/tile/linoleum
- flags = TURF_REMOVE_SCREWDRIVER
+ flags = TURF_REMOVE_SCREWDRIVER | TURF_CAN_BREAK | TURF_CAN_BURN
/decl/flooring/tiling/red
name = "floor"
@@ -239,7 +312,6 @@ var/list/flooring_types
name = "floor"
icon_base = "asteroidfloor"
has_damage_range = null
- flags = TURF_REMOVE_CROWBAR
build_type = /obj/item/stack/tile/floor/steel
/decl/flooring/tiling/white
@@ -252,7 +324,6 @@ var/list/flooring_types
name = "floor"
icon_base = "white"
has_damage_range = null
- flags = TURF_REMOVE_CROWBAR
build_type = /obj/item/stack/tile/floor/yellow
/decl/flooring/tiling/dark
@@ -260,7 +331,6 @@ var/list/flooring_types
desc = "How ominous."
icon_base = "dark"
has_damage_range = null
- flags = TURF_REMOVE_CROWBAR
build_type = /obj/item/stack/tile/floor/dark
/decl/flooring/tiling/hydro
@@ -308,20 +378,26 @@ var/list/flooring_types
desc = "Heavily reinforced with steel rods."
icon = 'icons/turf/flooring/tiles.dmi'
icon_base = "reinforced"
- flags = TURF_REMOVE_WRENCH | TURF_ACID_IMMUNE
+ flags = TURF_REMOVE_WRENCH | TURF_ACID_IMMUNE | TURF_CAN_BURN | TURF_CAN_BREAK
build_type = /obj/item/stack/rods
build_cost = 2
build_time = 30
apply_thermal_conductivity = 0.025
apply_heat_capacity = 325000
can_paint = 1
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/hull1.ogg',
+ 'sound/effects/footstep/hull2.ogg',
+ 'sound/effects/footstep/hull3.ogg',
+ 'sound/effects/footstep/hull4.ogg',
+ 'sound/effects/footstep/hull5.ogg'))
/decl/flooring/reinforced/circuit
name = "processing strata"
icon = 'icons/turf/flooring/circuit.dmi'
icon_base = "bcircuit"
build_type = null
- flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_CROWBAR
+ flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_CAN_BURN | TURF_REMOVE_CROWBAR
can_paint = 1
/decl/flooring/reinforced/circuit/green
@@ -337,3 +413,13 @@ var/list/flooring_types
has_damage_range = 6
flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK
can_paint = null
+
+/decl/flooring/lava // Defining this in case someone DOES step on lava and survive. Somehow.
+ name = "lava"
+ desc = "Lava. Y'know. Sets you on fire. AAAAAAAAAAA"
+ icon = 'icons/turf/outdoors.dmi'
+ icon_base = "lava"
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/lava1.ogg',
+ 'sound/effects/footstep/lava2.ogg',
+ 'sound/effects/footstep/lava3.ogg'))
\ No newline at end of file
diff --git a/code/game/turfs/flooring/flooring_premade.dm b/code/game/turfs/flooring/flooring_premade.dm
index 5453c2da40..d3ef65ec6a 100644
--- a/code/game/turfs/flooring/flooring_premade.dm
+++ b/code/game/turfs/flooring/flooring_premade.dm
@@ -387,8 +387,7 @@
name = "snow"
icon = 'icons/turf/snow_new.dmi'
icon_state = "snow"
- outdoors = TRUE
- movement_cost = 8
+ initial_flooring = /decl/flooring/snow
var/list/crossed_dirs = list()
footstep_sounds = list("human" = list( //YW edit: Should provide proper snow stepping!
'sound/effects/footstep/snow1.ogg',
diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm
index cf5396aa96..e11ad7e998 100644
--- a/code/game/turfs/simulated/floor_icon.dm
+++ b/code/game/turfs/simulated/floor_icon.dm
@@ -1,4 +1,4 @@
-var/list/flooring_cache = list()
+GLOBAL_LIST_EMPTY(flooring_cache)
var/image/no_ceiling_image = null
@@ -79,10 +79,11 @@ var/image/no_ceiling_image = null
icon = 'icons/turf/flooring/plating.dmi'
icon_state = "dmg[rand(1,4)]"
else if(flooring)
+ var/rand_key = rand(0,2)
if(!isnull(broken) && (flooring.flags & TURF_CAN_BREAK))
- add_overlay(get_flooring_overlay("[flooring.icon_base]-broken-[broken]","broken[broken]")) // VOREStation Edit - Eris overlays
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-broken-[rand_key]","broken[rand_key]"))
if(!isnull(burnt) && (flooring.flags & TURF_CAN_BURN))
- add_overlay(get_flooring_overlay("[flooring.icon_base]-burned-[burnt]","burned[burnt]")) // VOREStation Edit - Eris overlays
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-burned-[rand_key]","burned[rand_key]"))
if(update_neighbors)
for(var/turf/simulated/floor/F in range(src, 1))
@@ -96,8 +97,8 @@ var/image/no_ceiling_image = null
add_overlay(no_ceiling_image)
/turf/simulated/floor/proc/get_flooring_overlay(var/cache_key, var/icon_base, var/icon_dir = 0)
- if(!flooring_cache[cache_key])
+ if(!GLOB.flooring_cache[cache_key])
var/image/I = image(icon = flooring.icon, icon_state = icon_base, dir = icon_dir)
I.layer = layer
- flooring_cache[cache_key] = I
- return flooring_cache[cache_key]
+ GLOB.flooring_cache[cache_key] = I
+ return GLOB.flooring_cache[cache_key]
diff --git a/code/game/turfs/simulated/lava.dm b/code/game/turfs/simulated/lava.dm
index 01ad912b70..902c38c16a 100644
--- a/code/game/turfs/simulated/lava.dm
+++ b/code/game/turfs/simulated/lava.dm
@@ -13,6 +13,7 @@
movement_cost = 2
can_build_into_floor = TRUE
can_dirty = FALSE
+ initial_flooring = /decl/flooring/lava // Defining this in case someone DOES step on lava and survive. Somehow.
/turf/simulated/floor/lava/outdoors
outdoors = TRUE
diff --git a/code/game/turfs/simulated/outdoors/dirt.dm b/code/game/turfs/simulated/outdoors/dirt.dm
index 4d14205072..58e1db4951 100644
--- a/code/game/turfs/simulated/outdoors/dirt.dm
+++ b/code/game/turfs/simulated/outdoors/dirt.dm
@@ -1,6 +1,7 @@
-/turf/simulated/floor/outdoors/dirt
- name = "dirt"
- desc = "Quite dirty!"
- icon_state = "dirt-dark"
- edge_blending_priority = 2
- turf_layers = list(/turf/simulated/floor/outdoors/rocks)
\ No newline at end of file
+/turf/simulated/floor/outdoors/dirt
+ name = "dirt"
+ desc = "Quite dirty!"
+ icon_state = "dirt-dark"
+ edge_blending_priority = 2
+ turf_layers = list(/turf/simulated/floor/outdoors/rocks)
+ initial_flooring = /decl/flooring/asteroid
\ No newline at end of file
diff --git a/code/game/turfs/simulated/outdoors/grass.dm b/code/game/turfs/simulated/outdoors/grass.dm
index 553b4858bb..4909b14c20 100644
--- a/code/game/turfs/simulated/outdoors/grass.dm
+++ b/code/game/turfs/simulated/outdoors/grass.dm
@@ -4,21 +4,22 @@ var/list/grass_types = list(
/turf/simulated/floor/outdoors/grass
name = "grass"
- icon_state = "grass"
+ icon_state = "grass0"
edge_blending_priority = 4
+ initial_flooring = /decl/flooring/grass
turf_layers = list(
/turf/simulated/floor/outdoors/rocks,
/turf/simulated/floor/outdoors/dirt
)
var/grass_chance = 20
-
+/*
var/animal_chance = 1
// Weighted spawn list.
var/list/animal_types = list(
/mob/living/simple_mob/animal/passive/tindalos = 1
)
-
+*/
var/list/grass_types = list(
/obj/structure/flora/ausbushes/sparsegrass,
/obj/structure/flora/ausbushes/fullgrass
@@ -34,12 +35,13 @@ var/list/grass_types = list(
/turf/simulated/floor/outdoors/grass/sif
name = "growth"
- icon_state = "grass_sif"
+ icon_state = "grass_sif0"
+ initial_flooring = /decl/flooring/grass/sif
edge_blending_priority = 4
grass_chance = 5
var/tree_chance = 2
-
- animal_chance = 0 //VOREStation Edit
+/*
+ animal_chance = 0.5
animal_types = list(
/mob/living/simple_mob/animal/sif/diyaab = 10,
@@ -48,7 +50,7 @@ var/list/grass_types = list(
/mob/living/simple_mob/animal/sif/shantak/retaliate = 2,
/obj/random/mob/multiple/sifmobs = 1
)
-
+*/
grass_types = list(
/obj/structure/flora/sif/eyes = 1,
/obj/structure/flora/sif/tendrils = 10
@@ -63,30 +65,26 @@ var/list/grass_types = list(
. = ..()
/turf/simulated/floor/outdoors/grass/Initialize()
- if(prob(50))
- icon_state = "[initial(icon_state)]2"
- //edge_blending_priority++
-
if(grass_chance && prob(grass_chance) && !check_density())
var/grass_type = pickweight(grass_types)
new grass_type(src)
-
+/*
if(animal_chance && prob(animal_chance) && !check_density())
var/animal_type = pickweight(animal_types)
new animal_type(src)
-
+*/
. = ..()
/turf/simulated/floor/outdoors/grass/forest
name = "thick grass"
- icon_state = "grass-dark"
+ icon_state = "grass-dark0"
grass_chance = 80
//tree_chance = 20
edge_blending_priority = 5
/turf/simulated/floor/outdoors/grass/sif/forest
name = "thick growth"
- icon_state = "grass_sif_dark"
+ icon_state = "grass_sif_dark0"
edge_blending_priority = 5
tree_chance = 10
grass_chance = 0
diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm
index 7bef49cd49..bbc71d536b 100644
--- a/code/game/turfs/simulated/outdoors/outdoors.dm
+++ b/code/game/turfs/simulated/outdoors/outdoors.dm
@@ -81,6 +81,7 @@ var/list/turf_edge_cache = list()
name = "mud"
icon_state = "mud_dark"
edge_blending_priority = 3
+ initial_flooring = /decl/flooring/mud
/turf/simulated/floor/outdoors/rocks
name = "rocks"
diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index 5bf41c4a5f..dd49744a8f 100644
--- a/code/game/turfs/simulated/wall_icon.dm
+++ b/code/game/turfs/simulated/wall_icon.dm
@@ -67,7 +67,7 @@
I.color = reinf_material.icon_colour
add_overlay(I)
else
- if("[reinf_material.icon_reinf]0" in icon_states('icons/turf/wall_masks.dmi'))
+ if("[reinf_material.icon_reinf]0" in cached_icon_states('icons/turf/wall_masks.dmi'))
// Directional icon
for(var/i = 1 to 4)
I = image('icons/turf/wall_masks.dmi', "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index add0b3b11d..1fc49d58a9 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -46,6 +46,9 @@
dismantle_wall(null,null,1)
..()
+/turf/simulated/wall/examine_icon()
+ return icon(icon=initial(icon), icon_state=initial(icon_state))
+
/turf/simulated/wall/process()
// Calling parent will kill processing
if(!radiate())
diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm
index 2068bd2e35..0093f84849 100644
--- a/code/game/turfs/simulated/water.dm
+++ b/code/game/turfs/simulated/water.dm
@@ -20,6 +20,8 @@
/turf/simulated/floor/water/Initialize()
. = ..()
+ var/decl/flooring/F = get_flooring_data(/decl/flooring/water)
+ footstep_sounds = F?.footstep_sounds
update_icon()
handle_fish()
diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm
index 056facb60c..c5338b3db9 100644
--- a/code/game/turfs/unsimulated/beach.dm
+++ b/code/game/turfs/unsimulated/beach.dm
@@ -15,6 +15,7 @@
name = "Water"
icon_state = "water"
initialized = FALSE
+ movement_cost = 4 // Water should slow you down, just like simulated turf.
/turf/unsimulated/beach/water/Initialize()
. = ..()
@@ -23,20 +24,17 @@
/turf/simulated/floor/beach
name = "Beach"
icon = 'icons/misc/beach.dmi'
- footstep_sounds = list("human" = list(
- 'sound/effects/footstep/carpet1.ogg',
- 'sound/effects/footstep/carpet2.ogg',
- 'sound/effects/footstep/carpet3.ogg',
- 'sound/effects/footstep/carpet4.ogg',
- 'sound/effects/footstep/carpet5.ogg'))
+ initial_flooring = /decl/flooring/sand
/turf/simulated/floor/beach/sand
name = "Sand"
icon_state = "sand"
+ initial_flooring = /decl/flooring/sand
/turf/simulated/floor/beach/sand/desert
icon = 'icons/turf/desert.dmi'
icon_state = "desert"
+ initial_flooring = /decl/flooring/sand/desert
/turf/simulated/floor/beach/sand/desert/Initialize()
. = ..()
@@ -51,10 +49,24 @@
/turf/simulated/floor/beach/water
name = "Water"
icon_state = "water"
+ movement_cost = 4 // Water should slow you down, just like the original simulated turf.
+ initial_flooring = /decl/flooring/water
/turf/simulated/floor/beach/water/ocean
icon_state = "seadeep"
+ movement_cost = 8 // Deep water should be difficult to wade through.
+ initial_flooring = /decl/flooring/water/beach/deep
/turf/simulated/floor/beach/water/Initialize()
. = ..()
add_overlay(image("icon"='icons/misc/beach.dmi',"icon_state"="water5","layer"=MOB_LAYER+0.1))
+
+/decl/flooring/water/beach/deep // We're custom-defining a 'deep' water turf for the beach.
+ name = "deep water"
+ desc = "Deep Ocean Water"
+ icon = 'icons/misc/beach.dmi'
+ icon_base = "seadeep"
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/bubbles3.ogg', // No I don't get why it's named 3/4/5 either. Whatever.
+ 'sound/effects/footstep/bubbles4.ogg',
+ 'sound/effects/footstep/bubbles5.ogg'))
diff --git a/code/game/world.dm b/code/game/world.dm
index a71a3e6cdb..6e76ab93a1 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -15,6 +15,8 @@
if(byond_version < RECOMMENDED_VERSION)
to_world_log("Your server's byond version does not meet the recommended requirements for this server. Please update BYOND")
+ TgsNew()
+
config.post_load()
if(config && config.server_name != null && config.server_suffix && world.port > 0)
@@ -25,7 +27,7 @@
// if(config && config.log_runtime)
// log = file("data/logs/runtime/[time2text(world.realtime,"YYYY-MM-DD-(hh-mm-ss)")]-runtime.log")
- GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
+ GLOB.timezoneOffset = get_timezone_offset()
callHook("startup")
init_vchat()
@@ -62,7 +64,7 @@
master_controller = new /datum/controller/game_controller()
- Master.Initialize(10, FALSE)
+ Master.Initialize(10, FALSE, TRUE)
spawn(1)
master_controller.setup()
@@ -82,6 +84,7 @@ var/world_topic_spam_protect_ip = "0.0.0.0"
var/world_topic_spam_protect_time = world.timeofday
/world/Topic(T, addr, master, key)
+ TGS_TOPIC
log_topic("\"[T]\", from:[addr], master:[master], key:[key]")
if (T == "ping")
@@ -409,6 +412,7 @@ var/world_topic_spam_protect_time = world.timeofday
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
C << link("byond://[config.server]")
+ TgsReboot()
log_world("World rebooted at [time_stamp()]")
..()
diff --git a/code/hub.dm b/code/hub.dm
index c085c0500d..d3e49cecb4 100644
--- a/code/hub.dm
+++ b/code/hub.dm
@@ -3,6 +3,10 @@
hub = "Exadv1.spacestation13"
hub_password = "kMZy3U5jJHSiBQjr"
name = "Space Station 13"
+ /*YW EDIT we want to be on the hub
+ name = "VOREStation" //VOREStation Edit
+ visibility = 0 //VOREStation Edit
+ */
/* This is for any host that would like their server to appear on the main SS13 hub.
To use it, simply replace the password above, with the password found below, and it should work.
If not, let us know on the main tgstation IRC channel of irc.rizon.net #tgstation13 we can help you there.
diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm
index 6a0d8ba266..7f9e02b769 100644
--- a/code/modules/admin/verbs/buildmode.dm
+++ b/code/modules/admin/verbs/buildmode.dm
@@ -161,6 +161,7 @@
Right Mouse Button on enemy mob = Command selected mobs to attack mob
\
Right Mouse Button on allied mob = Command selected mobs to follow mob
\
Right Mouse Button + shift on any mob = Command selected mobs to follow mob regardless of faction
\
+ Note: The following also reset the mob's home position:
\
Right Mouse Button on tile = Command selected mobs to move to tile (will cancel if enemies are seen)
\
Right Mouse Button + shift on tile = Command selected mobs to reposition to tile (will not be inturrupted by enemies)
\
Right Mouse Button + alt on obj/turfs = Command selected mobs to attack obj/turf
\
@@ -569,6 +570,7 @@
var/told = 0
for(var/mob/living/unit in holder.selected_mobs)
var/datum/ai_holder/AI = unit.ai_holder
+ AI.home_turf = T
if(unit.get_AI_stance() == STANCE_SLEEP)
unit.forceMove(T)
forced++
diff --git a/code/modules/ai/ai_holder.dm b/code/modules/ai/ai_holder.dm
index d4686e1537..3cabb3ffde 100644
--- a/code/modules/ai/ai_holder.dm
+++ b/code/modules/ai/ai_holder.dm
@@ -27,6 +27,16 @@
QDEL_NULL(ai_holder)
return ..()
+/mob/living/Login()
+ if(!stat && ai_holder)
+ ai_holder.manage_processing(AI_NO_PROCESS)
+ return ..()
+
+/mob/living/Logout()
+ if(!stat && !key && ai_holder)
+ ai_holder.manage_processing(AI_PROCESSING)
+ return ..()
+
/datum/ai_holder
var/mob/living/holder = null // The mob this datum is going to control.
var/stance = STANCE_IDLE // Determines if the mob should be doing a specific thing, e.g. attacking, following, standing around, etc.
@@ -145,11 +155,15 @@
// 'Tactical' processes such as moving a step, meleeing an enemy, firing a projectile, and other fairly cheap actions that need to happen quickly.
/datum/ai_holder/proc/handle_tactics()
+ if(holder.key && !autopilot)
+ return
handle_special_tactic()
handle_stance_tactical()
// 'Strategical' processes that are more expensive on the CPU and so don't get run as often as the above proc, such as A* pathfinding or robust targeting.
/datum/ai_holder/proc/handle_strategicals()
+ if(holder.key && !autopilot)
+ return
handle_special_strategical()
handle_stance_strategical()
@@ -160,6 +174,8 @@
// For setting the stance WITHOUT processing it
/datum/ai_holder/proc/set_stance(var/new_stance)
+ if(holder.key && !autopilot)
+ return
if(stance == new_stance)
ai_log("set_stance() : Ignoring change stance to same stance request.", AI_LOG_INFO)
return
@@ -277,11 +293,11 @@
if(STANCE_IDLE)
if(speak_chance) // In the long loop since otherwise it wont shut up.
handle_idle_speaking()
-
+
if(hostile)
ai_log("handle_stance_strategical() : STANCE_IDLE, going to find_target().", AI_LOG_TRACE)
find_target()
-
+
if(should_go_home())
ai_log("handle_stance_tactical() : STANCE_IDLE, going to go home.", AI_LOG_TRACE)
go_home()
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index 5580c7fd98..ed6439d3cd 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -204,12 +204,12 @@ You can set verify to TRUE if you want send() to sleep until the client has the
directions = list(SOUTH)
var/sprites = list()
- for (var/icon_state_name in icon_states(I))
+ 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(icon_states(sprite))) // that direction or state doesn't exist
+ if (!sprite || !length(cached_icon_states(sprite))) // that direction or state doesn't exist
continue
sprites[sprite_name] = sprite
return sprites
diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm
index c90f5ec504..05bb6b17cd 100644
--- a/code/modules/client/client defines.dm
+++ b/code/modules/client/client defines.dm
@@ -27,8 +27,6 @@
var/chatOutputLoadedAt
var/adminhelped = 0
- var/examine_text_mode = 0 // Just examine text, include usage (description_info), switch to examine panel.
-
///////////////
//SOUND STUFF//
@@ -56,6 +54,7 @@
var/account_join_date = "(Requires database)"
var/account_age = "(Requires database)"
var/list/department_hours // VOREStation Edit - Track hours of leave accured for each department.
+ var/list/play_hours // VOREStation Edit - Tracks total playtime hours for each departments.
preload_rsc = PRELOAD_RSC
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 7df78ea617..7425c5b72e 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -325,11 +325,13 @@
// VOREStation Edit Start - Department Hours
if(config.time_off)
- var/DBQuery/query_hours = dbcon.NewQuery("SELECT department, hours FROM vr_player_hours WHERE ckey = '[sql_ckey]'")
+ var/DBQuery/query_hours = dbcon.NewQuery("SELECT department, hours, total_hours FROM vr_player_hours WHERE ckey = '[sql_ckey]'")
query_hours.Execute()
+ LAZYINITLIST(department_hours)
+ LAZYINITLIST(play_hours)
while(query_hours.NextRow())
- LAZYINITLIST(department_hours)
department_hours[query_hours.item[1]] = text2num(query_hours.item[2])
+ play_hours[query_hours.item[1]] = text2num(query_hours.item[3])
// VOREStation Edit End - Department Hours
if(sql_id)
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 7c9d179f27..06f0a0c877 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -901,7 +901,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
dat += "
[current_species.blurb] | "
//vorestation edit end
dat += ""
- if("preview" in icon_states(current_species.icobase))
+ if("preview" in cached_icon_states(current_species.icobase))
usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png")
dat += "
"
dat += "Language: [current_species.species_language] "
diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm b/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm
index da9ad9021d..42c87335f6 100644
--- a/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm
@@ -13,6 +13,27 @@
display_name = "AR glasses, prescription"
path = /obj/item/clothing/glasses/omnihud/prescription
+/datum/gear/eyes/arglasses/sec
+ display_name = "AR-S glasses (Sec)"
+ path = /obj/item/clothing/glasses/omnihud/sec
+ allowed_roles = list("Security Officer","Head of Security","Warden","Detective")
+
+/datum/gear/eyes/arglasses/eng
+ display_name = "AR-E glasses (Eng)"
+ path = /obj/item/clothing/glasses/omnihud/eng
+ allowed_roles = list("Station Engineer","Chief Engineer","Atmospheric Technician")
+
+/datum/gear/eyes/arglasses/med
+ display_name = "AR-M glasses (Medical)"
+ path = /obj/item/clothing/glasses/omnihud/med
+ allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist", "Psychiatrist", "Field Medic")
+
+/datum/gear/eyes/arglasses/all
+ display_name = "AR-B glasses (CD, HoP)"
+ path = /obj/item/clothing/glasses/omnihud/all
+ cost = 2
+ allowed_roles = list("Colony Director","Head of Personnel")
+
/datum/gear/eyes/spiffygogs
display_name = "slick orange goggles"
path = /obj/item/clothing/glasses/fluff/spiffygogs
diff --git a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
index 452b721e6d..088a13c443 100644
--- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
@@ -92,7 +92,7 @@
/datum/gear/fluff/aurora
path = /obj/item/clothing/accessory/solgov/department/security/aurora
display_name = "Aurora's keepsake"
- description = "An old solgov sec insignia given to Aurora"
+ description = "An old solcom sec insignia given to Aurora"
ckeywhitelist = list("storesund97")
character_name = list("Aurora")
@@ -150,27 +150,6 @@
ckeywhitelist = list("bwoincognito")
character_name = list("Tasald Corlethian")
-/datum/gear/fluff/tasald_cartographer_jumpsuit
- path = /obj/item/clothing/under/solgov/utility/sifguard/officer/exploration
- display_name = "Tasald's Cartographer's uniform - jumpsuit"
- slot = slot_w_uniform
- ckeywhitelist = list("bwoincognito")
- character_name = list("Tasald Corlethian")
-
-/datum/gear/fluff/tasald_cartographer_jacket
- path = /obj/item/clothing/suit/storage/service/sifguard/command
- display_name = "Tasald's Cartographer's uniform - jacket"
- slot = slot_wear_suit
- ckeywhitelist = list("bwoincognito")
- character_name = list("Tasald Corlethian")
-
-/datum/gear/fluff/tasald_cartographer_beret
- path = /obj/item/clothing/head/beret/sol/expedition/command
- display_name = "Tasald's Cartographer's uniform - beret"
- slot = slot_head
- ckeywhitelist = list("bwoincognito")
- character_name = list("Tasald Corlethian")
-
/datum/gear/fluff/octavius_box
path = /obj/item/weapon/storage/box/fluff/octavious
display_name = "Octavious' Box"
diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm
index 220af5af8e..d0ff9588d5 100644
--- a/code/modules/client/preference_setup/occupation/occupation.dm
+++ b/code/modules/client/preference_setup/occupation/occupation.dm
@@ -143,6 +143,12 @@
var/available_in_days = job.available_in_days(user.client)
. += "[rank] | \[IN [(available_in_days)] DAYS] | "
continue
+ //VOREStation Add
+ if(!job.player_has_enough_playtime(user.client))
+ var/available_in_hours = job.available_in_playhours(user.client)
+ . += "[rank] \[IN [(available_in_hours)] DEPTHOURS] | "
+ continue
+ //VOREStation Add End
if(job.minimum_character_age && user.client && (user.client.prefs.age < job.minimum_character_age))
. += "[rank] \[MINIMUM CHARACTER AGE: [job.minimum_character_age]] | "
continue
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 14f4b5100e..2c09523d93 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -134,6 +134,10 @@ datum/preferences
var/lastnews // Hash of last seen lobby news content.
+ var/examine_text_mode = 0 // Just examine text, include usage (description_info), switch to examine panel.
+ var/multilingual_mode = 0 // Default behaviour, delimiter-key-space, delimiter-key-delimiter, off
+
+
/datum/preferences/New(client/C)
player_setup = new(src)
set_biological_gender(pick(MALE, FEMALE))
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 652f2ac082..efa91fc860 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -81,6 +81,8 @@
else
player_setup.load_character(S)
S.cd = "/character[default_slot]"
+ player_setup.save_character(S)
+ sanitize_preferences()
player_setup.load_character(S)
return 1
@@ -104,7 +106,9 @@
slot = sanitize_integer(slot, 1, config.character_slots, initial(default_slot))
if(slot != default_slot)
default_slot = slot
+ nif_path = nif_durability = nif_savedata = null //VOREStation Add - Don't copy NIF
S["default_slot"] << slot
+
else
S["default_slot"] << default_slot
diff --git a/code/modules/client/preferences_spawnpoints.dm b/code/modules/client/preferences_spawnpoints.dm
index acf1c771a7..e990ee1793 100644
--- a/code/modules/client/preferences_spawnpoints.dm
+++ b/code/modules/client/preferences_spawnpoints.dm
@@ -13,6 +13,7 @@ var/list/spawntypes = list()
var/list/restrict_job = null
var/list/disallow_job = null
var/announce_channel = "Common"
+ var/allowed_mob_types = JOB_SILICON|JOB_CARBON
proc/check_job_spawning(job)
if(restrict_job && !(job in restrict_job))
@@ -22,9 +23,15 @@ var/list/spawntypes = list()
return 0
var/datum/job/J = SSjob.get_job(job)
- if(J?.offmap_spawn && !(job in restrict_job))
+ if(!J) // Couldn't find, admin shenanigans? Allow it
+ return 1
+
+ if(J.offmap_spawn && !(job in restrict_job))
return 0
+ if(!(J.mob_type & allowed_mob_types))
+ return 0
+
return 1
/datum/spawnpoint/proc/get_spawn_position()
@@ -57,7 +64,7 @@ var/list/spawntypes = list()
/datum/spawnpoint/cryo
display_name = "Cryogenic Storage"
msg = "has completed cryogenic revival"
- disallow_job = list("Cyborg")
+ allowed_mob_types = JOB_CARBON
/datum/spawnpoint/cryo/New()
..()
@@ -66,7 +73,7 @@ var/list/spawntypes = list()
/datum/spawnpoint/cyborg
display_name = "Cyborg Storage"
msg = "has been activated from storage"
- restrict_job = list("Cyborg")
+ allowed_mob_types = JOB_SILICON
/datum/spawnpoint/cyborg/New()
..()
diff --git a/code/modules/client/preferences_toggle_procs.dm b/code/modules/client/preferences_toggle_procs.dm
index b8e0ea3d5c..e33f3645d1 100644
--- a/code/modules/client/preferences_toggle_procs.dm
+++ b/code/modules/client/preferences_toggle_procs.dm
@@ -328,17 +328,34 @@
set category = "Preferences"
set desc = "Control the additional behaviour of examining things"
- examine_text_mode++
- examine_text_mode %= EXAMINE_MODE_MAX // This cycles through them because if you're already specifically being routed to the examine panel, you probably don't need to have the extra text printed to chat
- switch(examine_text_mode) // ... And I only wanted to add one verb
+ prefs.examine_text_mode++
+ prefs.examine_text_mode %= EXAMINE_MODE_MAX // This cycles through them because if you're already specifically being routed to the examine panel, you probably don't need to have the extra text printed to chat
+ switch(prefs.examine_text_mode) // ... And I only wanted to add one verb
if(EXAMINE_MODE_DEFAULT)
- to_chat(src, "Examining things will only output the base examine text, and you will not be redirected to the examine panel automatically.")
+ to_chat(src, "Examining things will only output the base examine text, and you will not be redirected to the examine panel automatically.")
if(EXAMINE_MODE_INCLUDE_USAGE)
- to_chat(src, "Examining things will also print any extra usage information normally included in the examine panel to the chat.")
+ to_chat(src, "Examining things will also print any extra usage information normally included in the examine panel to the chat.")
if(EXAMINE_MODE_SWITCH_TO_PANEL)
- to_chat(src, "Examining things will direct you to the examine panel, where you can view extended information about the thing.")
+ to_chat(src, "Examining things will direct you to the examine panel, where you can view extended information about the thing.")
+
+/client/verb/toggle_multilingual_mode()
+ set name = "Toggle Multilingual Mode"
+ set category = "Preferences"
+ set desc = "Control the behaviour of multilingual speech parsing"
+
+ prefs.multilingual_mode++
+ prefs.multilingual_mode %= MULTILINGUAL_MODE_MAX // Cycles through the various options
+ switch(prefs.multilingual_mode)
+ if(MULTILINGUAL_DEFAULT)
+ to_chat(src, "Multilingual parsing will only check for the delimiter-key combination (,0galcom-2tradeband).")
+ if(MULTILINGUAL_SPACE)
+ to_chat(src, "Multilingual parsing will enforce a space after the delimiter-key combination (,0 galcom -2still galcom). The extra space will be consumed by the pattern-matching.")
+ if(MULTILINGUAL_DOUBLE_DELIMITER)
+ to_chat(src, "Multilingual parsing will enforce the a language delimiter after the delimiter-key combination (,0,galcom -2 still galcom). The extra delimiter will be consumed by the pattern-matching.")
+ if(MULTILINGUAL_OFF)
+ to_chat(src, "Multilingual parsing is now disabled. Entire messages will be in the language specified at the start of the message.")
//Toggles for Staff
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 4b92cdd149..5f61f21582 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -59,7 +59,7 @@
user.recalculate_vis()
//BS12: Species-restricted clothing check.
-/obj/item/clothing/mob_can_equip(M as mob, slot)
+/obj/item/clothing/mob_can_equip(M as mob, slot, disable_warning = 0)
//if we can't equip the item anyway, don't bother with species_restricted (cuts down on spam)
if (!..())
@@ -808,7 +808,7 @@
//autodetect rollability
if(rolled_down < 0)
- if(("[worn_state]_d_s" in icon_states(icon)) || ("[worn_state]_s" in icon_states(rolled_down_icon)) || ("[worn_state]_d_s" in icon_states(icon_override)))
+ if(("[worn_state]_d_s" in cached_icon_states(icon)) || ("[worn_state]_s" in cached_icon_states(rolled_down_icon)) || ("[worn_state]_d_s" in cached_icon_states(icon_override)))
rolled_down = 0
if(rolled_down == -1)
@@ -845,11 +845,11 @@
under_icon = sprite_sheets[H.species.get_bodytype(H)]
else if(item_icons && item_icons[slot_w_uniform_str])
under_icon = item_icons[slot_w_uniform_str]
- else if ("[worn_state]_s" in icon_states(rolled_down_icon))
+ else if ("[worn_state]_s" in cached_icon_states(rolled_down_icon))
under_icon = rolled_down_icon
// The _s is because the icon update procs append it.
- if((under_icon == rolled_down_icon && "[worn_state]_s" in icon_states(under_icon)) || ("[worn_state]_d_s" in icon_states(under_icon)))
+ if((under_icon == rolled_down_icon && "[worn_state]_s" in cached_icon_states(under_icon)) || ("[worn_state]_d_s" in cached_icon_states(under_icon)))
if(rolled_down != 1)
rolled_down = 0
else
@@ -868,13 +868,13 @@
under_icon = sprite_sheets[H.species.get_bodytype(H)]
else if(item_icons && item_icons[slot_w_uniform_str])
under_icon = item_icons[slot_w_uniform_str]
- else if ("[worn_state]_s" in icon_states(rolled_down_sleeves_icon))
+ else if ("[worn_state]_s" in cached_icon_states(rolled_down_sleeves_icon))
under_icon = rolled_down_sleeves_icon
else if(index)
under_icon = new /icon("[INV_W_UNIFORM_DEF_ICON]_[index].dmi")
// The _s is because the icon update procs append it.
- if((under_icon == rolled_down_sleeves_icon && "[worn_state]_s" in icon_states(under_icon)) || ("[worn_state]_r_s" in icon_states(under_icon)))
+ if((under_icon == rolled_down_sleeves_icon && "[worn_state]_s" in cached_icon_states(under_icon)) || ("[worn_state]_r_s" in cached_icon_states(under_icon)))
if(rolled_sleeves != 1)
rolled_sleeves = 0
else
@@ -958,7 +958,7 @@
if(rolled_down)
body_parts_covered = initial(body_parts_covered)
body_parts_covered &= ~(UPPER_TORSO|ARMS)
- if("[worn_state]_s" in icon_states(rolled_down_icon))
+ if("[worn_state]_s" in cached_icon_states(rolled_down_icon))
icon_override = rolled_down_icon
item_state_slots[slot_w_uniform_str] = "[worn_state]"
else
@@ -991,7 +991,7 @@
rolled_sleeves = !rolled_sleeves
if(rolled_sleeves)
body_parts_covered &= ~(ARMS)
- if("[worn_state]_s" in icon_states(rolled_down_sleeves_icon))
+ if("[worn_state]_s" in cached_icon_states(rolled_down_sleeves_icon))
icon_override = rolled_down_sleeves_icon
item_state_slots[slot_w_uniform_str] = "[worn_state]"
else
diff --git a/code/modules/clothing/clothing_vr.dm b/code/modules/clothing/clothing_vr.dm
index 62228ea5a0..0545cb92b7 100644
--- a/code/modules/clothing/clothing_vr.dm
+++ b/code/modules/clothing/clothing_vr.dm
@@ -135,7 +135,7 @@
var/mob/living/carbon/human/H = user
if(isTaurTail(H.tail_style))
var/datum/sprite_accessory/tail/taur/taurtail = H.tail_style
- if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in icon_states(taurtail.suit_sprites)))
+ if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in cached_icon_states(taurtail.suit_sprites)))
icon_override = taurtail.suit_sprites
normalize = FALSE
taurized = TRUE
diff --git a/code/modules/clothing/gloves/arm_guards.dm b/code/modules/clothing/gloves/arm_guards.dm
index 558f855545..791bb0a10b 100644
--- a/code/modules/clothing/gloves/arm_guards.dm
+++ b/code/modules/clothing/gloves/arm_guards.dm
@@ -7,7 +7,7 @@
w_class = ITEMSIZE_NORMAL
drop_sound = 'sound/items/drop/metalshield.ogg'
-/obj/item/clothing/gloves/arm_guard/mob_can_equip(var/mob/living/carbon/human/H, slot)
+/obj/item/clothing/gloves/arm_guard/mob_can_equip(var/mob/living/carbon/human/H, slot, disable_warning = 0)
if(..()) //This will only run if no other problems occured when equiping.
if(H.wear_suit)
if(H.wear_suit.body_parts_covered & ARMS)
diff --git a/code/modules/clothing/gloves/gauntlets.dm b/code/modules/clothing/gloves/gauntlets.dm
index 8807fb93ad..eb5d05c909 100644
--- a/code/modules/clothing/gloves/gauntlets.dm
+++ b/code/modules/clothing/gloves/gauntlets.dm
@@ -14,7 +14,7 @@
punch_force = 5
var/obj/item/clothing/gloves/gloves = null //Undergloves
-/obj/item/clothing/gloves/gauntlets/mob_can_equip(mob/user)
+/obj/item/clothing/gloves/gauntlets/mob_can_equip(mob/user, slot, disable_warning = 0)
var/mob/living/carbon/human/H = user
if(H.gloves)
gloves = H.gloves
diff --git a/code/modules/clothing/head/solgov_vr.dm b/code/modules/clothing/head/solgov_vr.dm
index 3861ecebe1..0a9ddd2c41 100644
--- a/code/modules/clothing/head/solgov_vr.dm
+++ b/code/modules/clothing/head/solgov_vr.dm
@@ -6,8 +6,8 @@
desc = "It's a blue ballcap in Terran Commonwealth Government colors."
/obj/item/clothing/head/soft/sol/expedition
- name = "\improper Explorer corps cap"
- desc = "It's a black ballcap bearing a Terran Commonwealth Explorer Corps crest."
+ name = "\improper NDF cap"
+ desc = "It's a black ballcap bearing a Nanotrasen Defense Force crest."
/obj/item/clothing/head/soft/sol/fleet
name = "fleet cap"
@@ -70,12 +70,12 @@
//Dress
/obj/item/clothing/head/dress/expedition
- name = "explorer's dress cap"
- desc = "A peaked grey dress uniform cap belonging to the Terran Commonwealth Explorer Corps."
+ name = "\improper NDF dress cap"
+ desc = "A peaked grey dress uniform cap belonging to the Nanotrasen Defense Force."
/obj/item/clothing/head/dress/expedition/command
- name = "explorer's command dress cap"
- desc = "A peaked grey dress uniform cap belonging to the Terran Commonwealth Explorer Corps. This one is trimmed in gold."
+ name = "\improper NDF command dress cap"
+ desc = "A peaked grey dress uniform cap belonging to the Nanotrasen Defense Force. This one is trimmed in gold."
/obj/item/clothing/head/dress/fleet
name = "fleet dress wheel cover"
@@ -124,28 +124,28 @@
desc = "A white beret denoting service in the Interstellar Health Service. For medics that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/expedition
- name = "explorer's beret"
- desc = "A black beret belonging to the Terran Commonwealth explorer corps. For personnel that are more inclined towards style than safety."
+ name = "\improper NDF beret"
+ desc = "A black beret belonging to the Nanotrasen Defense Force. For personnel that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/expedition/security
- name = "explorer's security beret"
- desc = "A Terran Commonwealth Explorer Corps beret with a security crest. For personnel that are more inclined towards style than safety."
+ name = "\improper NDF security beret"
+ desc = "A Nanotrasen Defense Force beret with a security crest. For personnel that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/expedition/medical
- name = "explorer's medical beret"
- desc = "A Terran Commonwealth Explorer Corps beret with a medical crest. For personnel that are more inclined towards style than safety."
+ name = "\improper NDF medical beret"
+ desc = "A Nanotrasen Defense Force beret with a medical crest. For personnel that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/expedition/engineering
- name = "explorer's engineering beret"
- desc = "A Terran Commonwealth Explorer Corps beret with an engineering crest. For personnel that are more inclined towards style than safety."
+ name = "\improper NDF engineering beret"
+ desc = "A Nanotrasen Defense Force beret with an engineering crest. For personnel that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/expedition/supply
- name = "explorer's supply beret"
- desc = "A Terran Commonwealth Explorer Corps beret with a supply crest. For personnel that are more inclined towards style than safety."
+ name = "\improper NDF supply beret"
+ desc = "A Nanotrasen Defense Force beret with a supply crest. For personnel that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/expedition/command
- name = "explorer's command beret"
- desc = "A Terran Commonwealth Explorer Corps beret with a command crest. For personnel that are more inclined towards style than safety."
+ name = "\improper NDF command beret"
+ desc = "A Nanotrasen Defense Force beret with a command crest. For personnel that are more inclined towards style than safety."
/obj/item/clothing/head/beret/sol/fleet
name = "fleet beret"
diff --git a/code/modules/clothing/masks/monitor.dm b/code/modules/clothing/masks/monitor.dm
index 230f224d09..be337c9067 100644
--- a/code/modules/clothing/masks/monitor.dm
+++ b/code/modules/clothing/masks/monitor.dm
@@ -33,7 +33,7 @@
canremove = 1
return ..()
-/obj/item/clothing/mask/monitor/mob_can_equip(var/mob/living/carbon/human/user, var/slot)
+/obj/item/clothing/mask/monitor/mob_can_equip(var/mob/living/carbon/human/user, var/slot, disable_warning = FALSE)
if (!..())
return 0
if(istype(user))
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index 57b8a0911a..816c5052fc 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -42,7 +42,7 @@
user.update_inv_shoes() //so our mob-overlays update
user.update_action_buttons()
-/obj/item/clothing/shoes/magboots/mob_can_equip(mob/user, slot)
+/obj/item/clothing/shoes/magboots/mob_can_equip(mob/user, slot, disable_warning = FALSE)
var/mob/living/carbon/human/H = user
if(H.shoes)
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 691f53de5a..3920ddd636 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -520,7 +520,7 @@
|ACCESSORY_SLOT_ARMOR_M)
blood_overlay_type = "armor"
-/obj/item/clothing/suit/armor/pcarrier/mob_can_equip(var/mob/living/carbon/human/H, slot)
+/obj/item/clothing/suit/armor/pcarrier/mob_can_equip(var/mob/living/carbon/human/H, slot, disable_warning = FALSE)
if(..()) //This will only run if no other problems occured when equiping.
if(H.gloves)
if(H.gloves.body_parts_covered & ARMS)
diff --git a/code/modules/clothing/suits/solgov_vr.dm b/code/modules/clothing/suits/solgov_vr.dm
index 21c6851acf..b23cb35bc9 100644
--- a/code/modules/clothing/suits/solgov_vr.dm
+++ b/code/modules/clothing/suits/solgov_vr.dm
@@ -2,40 +2,40 @@
//Service
/obj/item/clothing/suit/storage/service/sifguard
- name = "\improper SolCom jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has silver buttons."
+ name = "\improper NDF jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has silver buttons."
/obj/item/clothing/suit/storage/service/sifguard/medical
- name = "\improper SolCom medical jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has silver buttons and blue trim."
+ name = "\improper NDF medical jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has silver buttons and blue trim."
/obj/item/clothing/suit/storage/service/sifguard/medical/command
- name = "\improper SolCom medical command jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has gold buttons and blue trim."
+ name = "\improper NDF medical command jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has gold buttons and blue trim."
/obj/item/clothing/suit/storage/service/sifguard/engineering
- name = "\improper SolCom engineering jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has silver buttons and orange trim."
+ name = "\improper NDF engineering jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has silver buttons and orange trim."
/obj/item/clothing/suit/storage/service/sifguard/engineering/command
- name = "\improper SolCom engineering command jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has gold buttons and orange trim."
+ name = "\improper NDF engineering command jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has gold buttons and orange trim."
/obj/item/clothing/suit/storage/service/sifguard/supply
- name = "\improper SolCom supply jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has silver buttons and brown trim."
+ name = "\improper NDF supply jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has silver buttons and brown trim."
/obj/item/clothing/suit/storage/service/sifguard/security
- name = "\improper SolCom security jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has silver buttons and red trim."
+ name = "\improper NDF security jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has silver buttons and red trim."
/obj/item/clothing/suit/storage/service/sifguard/security/command
- name = "\improper SolCom security command jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has gold buttons and red trim."
+ name = "\improper NDF security command jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has gold buttons and red trim."
/obj/item/clothing/suit/storage/service/sifguard/command
- name = "\improper SolCom command jacket"
- desc = "A uniform service jacket belonging to the Terran Commonwealth Explorer Corps. It has gold buttons and gold trim."
+ name = "\improper NDF command jacket"
+ desc = "A uniform service jacket belonging to the Nanotrasen Defense Force. It has gold buttons and gold trim."
/obj/item/clothing/suit/storage/service/marine
name = "marine coat"
@@ -76,12 +76,12 @@
//Dress
/obj/item/clothing/suit/dress/expedition
- name = "SolCom dress jacket"
- desc = "A silver and grey dress jacket belonging to the Terran Commonwealth Explorer Corps. Fashionable, for the 24th century at least."
+ name = "\improper NDF dress jacket"
+ desc = "A silver and grey dress jacket belonging to the Nanotrasen Defense Force. Fashionable, for the 24th century at least."
/obj/item/clothing/suit/dress/expedition/command
- name = "explorer's command dress jacket"
- desc = "A gold and grey dress jacket belonging to the Terran Commonwealth Explorer Corps. The height of fashion."
+ name = "\improper NDF command dress jacket"
+ desc = "A gold and grey dress jacket belonging to the Nanotrasen Defense Force. The height of fashion."
/obj/item/clothing/suit/storage/toggle/dress/fleet
name = "fleet dress jacket"
diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm
index a20b4b4686..a9ace268ac 100644
--- a/code/modules/clothing/under/accessories/accessory.dm
+++ b/code/modules/clothing/under/accessories/accessory.dm
@@ -24,7 +24,7 @@
if(!inv_overlay)
var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]"
if(icon_override)
- if("[tmp_icon_state]_tie" in icon_states(icon_override))
+ if("[tmp_icon_state]_tie" in cached_icon_states(icon_override))
tmp_icon_state = "[tmp_icon_state]_tie"
inv_overlay = image(icon = icon_override, icon_state = tmp_icon_state, dir = SOUTH)
else
@@ -48,7 +48,7 @@
tmp_icon_state = on_rolled["rolled"]
if(icon_override)
- if("[tmp_icon_state]_mob" in icon_states(icon_override))
+ if("[tmp_icon_state]_mob" in cached_icon_states(icon_override))
tmp_icon_state = "[tmp_icon_state]_mob"
mob_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]")
else if(wearer && sprite_sheets[wearer.species.get_bodytype(wearer)]) //Teshari can finally into webbing, too!
diff --git a/code/modules/clothing/under/accessories/lockets.dm b/code/modules/clothing/under/accessories/lockets.dm
index ca859addb5..153df0d584 100644
--- a/code/modules/clothing/under/accessories/lockets.dm
+++ b/code/modules/clothing/under/accessories/lockets.dm
@@ -13,7 +13,7 @@
if(!base_icon)
base_icon = icon_state
- if(!("[base_icon]_open" in icon_states(icon)))
+ if(!("[base_icon]_open" in cached_icon_states(icon)))
to_chat(user, "\The [src] doesn't seem to open.")
return
diff --git a/code/modules/clothing/under/accessories/torch_vr.dm b/code/modules/clothing/under/accessories/torch_vr.dm
index caba931c6f..730710fe9b 100644
--- a/code/modules/clothing/under/accessories/torch_vr.dm
+++ b/code/modules/clothing/under/accessories/torch_vr.dm
@@ -192,3 +192,22 @@ armour attachments
/obj/item/clothing/accessory/armor/helmcover/blue/sol
name = "peacekeeper helmet cover"
desc = "A fabric cover for armored helmets. This one is in TCG peacekeeper colors."
+
+/*********
+ranks - ndf
+*********/
+/obj/item/clothing/accessory/solgov/rank/ec/enlisted
+ name = "ranks (E-1 seaman recruit)"
+ desc = "Insignia denoting the rank of Seaman Recruit."
+
+/obj/item/clothing/accessory/solgov/rank/ec/enlisted/e3
+ name = "ranks (E-3 seaman)"
+ desc = "Insignia denoting the rank of Seaman."
+
+/obj/item/clothing/accessory/solgov/rank/ec/enlisted/e5
+ name = "ranks (E-5 petty officer)"
+ desc = "Insignia denoting the rank of Petty Officer."
+
+/obj/item/clothing/accessory/solgov/rank/ec/enlisted/e7
+ name = "ranks (E-7 chief petty officer)"
+ desc = "Insignia denoting the rank of Chief Petty Officer."
diff --git a/code/modules/clothing/under/solgov_vr.dm b/code/modules/clothing/under/solgov_vr.dm
index e663db1344..891439d2d3 100644
--- a/code/modules/clothing/under/solgov_vr.dm
+++ b/code/modules/clothing/under/solgov_vr.dm
@@ -2,8 +2,8 @@
//PT
/obj/item/clothing/under/solgov/pt/sifguard
- name = "\improper SolCom pt uniform"
- desc = "A baggy shirt bearing the seal of the Terran Commonwealth Explorer Corps and some dorky looking blue shorts."
+ name = "\improper NDF pt uniform"
+ desc = "A baggy shirt bearing the seal of the Nanotrasen Defense Force and some dorky looking blue shorts."
/obj/item/clothing/under/solgov/pt/fleet
name = "fleet pt uniform"
@@ -21,12 +21,12 @@
desc = "A comfortable turtleneck and black utility trousers."
/obj/item/clothing/under/solgov/utility/sifguard
- name = "\improper SolCom uniform"
- desc = "The utility uniform of the Terran Commonwealth Explorer Corps, made from biohazard resistant material. This one has silver trim."
+ name = "\improper NDF uniform"
+ desc = "The utility uniform of the Nanotrasen Defense Force, made from biohazard resistant material. This one has silver trim."
/obj/item/clothing/under/solgov/utility/sifguard/officer
- name = "\improper SolCom officer uniform"
- desc = "The utility uniform of the Terran Commonwealth Explorer Corps, made from biohazard resistant material. This one has gold trim."
+ name = "\improper NDF officer uniform"
+ desc = "The utility uniform of the Nanotrasen Defense Force, made from biohazard resistant material. This one has gold trim."
/obj/item/clothing/under/solgov/utility/fleet
@@ -77,12 +77,12 @@
desc = "The service uniform of the TCG Marine Corps. Slimming and stylish."
/obj/item/clothing/under/solgov/mildress/expeditionary
- name = "\improper SolCom dress uniform"
- desc = "The dress uniform of the Terran Commonwealth Explorer Corps in silver trim."
+ name = "\improper NDF dress uniform"
+ desc = "The dress uniform of the Nanotrasen Defense Force in silver trim."
/obj/item/clothing/under/solgov/mildress/expeditionary/command
- name = "\improper SolCom command dress uniform"
- desc = "The dress uniform of the Terran Commonwealth Explorer Corps in gold trim."
+ name = "\improper NDF command dress uniform"
+ desc = "The dress uniform of the Nanotrasen Defense Force in gold trim."
/obj/item/clothing/under/solgov/mildress/marine
name = "marine dress uniform"
diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm
index b87183c385..5e85c0123c 100644
--- a/code/modules/customitems/item_spawning.dm
+++ b/code/modules/customitems/item_spawning.dm
@@ -78,7 +78,7 @@
var/list/new_item_icons = list()
var/list/new_item_state_slots = list()
- var/list/available_states = icon_states(CUSTOM_ITEM_MOB)
+ var/list/available_states = cached_icon_states(CUSTOM_ITEM_MOB)
//If l_hand or r_hand are not present, preserve them using item_icons/item_state_slots
//Then use icon_override to make every other slot use the custom sprites by default.
diff --git a/code/modules/detectivework/microscope/dnascanner.dm b/code/modules/detectivework/microscope/dnascanner.dm
index 94d4acd5cd..0b9782b2c8 100644
--- a/code/modules/detectivework/microscope/dnascanner.dm
+++ b/code/modules/detectivework/microscope/dnascanner.dm
@@ -16,14 +16,9 @@
var/last_process_worldtime = 0
var/report_num = 0
-/obj/machinery/dnaforensics/New()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- RefreshParts()
- ..()
+/obj/machinery/dnaforensics/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/dnaforensics/attackby(var/obj/item/W, mob/user as mob)
diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm
index 02a8ad8acd..ca30941c1c 100644
--- a/code/modules/events/event_container.dm
+++ b/code/modules/events/event_container.dm
@@ -22,7 +22,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT
var/last_world_time = 0
/datum/event_container/process()
- if(!round_start_time)
+ if(!GLOB.round_start_time)
return //don't do events if the round hasn't even started yet
if(!next_event_time)
diff --git a/code/modules/examine/examine.dm b/code/modules/examine/examine.dm
index 6e2df0b1fa..f49c672bca 100644
--- a/code/modules/examine/examine.dm
+++ b/code/modules/examine/examine.dm
@@ -5,7 +5,7 @@
This means that this file can be unchecked, along with the other examine files, and can be removed entirely with no effort.
*/
-#define EXAMINE_PANEL_PADDING " "
+#define EXAMINE_PANEL_PADDING " "
/atom/
var/description_info = null //Helpful blue text.
@@ -56,7 +56,7 @@
description_holders["interactions"] = A.get_description_interaction()
description_holders["name"] = "[A.name]"
- description_holders["icon"] = "\icon[A]"
+ description_holders["icon"] = "\icon[A.examine_icon()]"
description_holders["desc"] = A.desc
/mob/Stat()
diff --git a/code/modules/food/drinkingglass/drinkingglass.dm b/code/modules/food/drinkingglass/drinkingglass.dm
index 928c24954b..c2c5dc4219 100644
--- a/code/modules/food/drinkingglass/drinkingglass.dm
+++ b/code/modules/food/drinkingglass/drinkingglass.dm
@@ -74,9 +74,9 @@
update_icon()
/obj/item/weapon/reagent_containers/food/drinks/glass2/proc/can_add_extra(obj/item/weapon/glass_extra/GE)
- if(!("[base_icon]_[GE.glass_addition]left" in icon_states(icon))) //VOREStation Edit
+ if(!("[base_icon]_[GE.glass_addition]left" in cached_icon_states(icon))) //VOREStation Edit
return 0
- if(!("[base_icon]_[GE.glass_addition]right" in icon_states(icon))) //VOREStation Edit
+ if(!("[base_icon]_[GE.glass_addition]right" in cached_icon_states(icon))) //VOREStation Edit
return 0
return 1
@@ -106,9 +106,9 @@
over_liquid |= "[base_icon][amnt]_fizz"
for(var/S in R.glass_special)
- if("[base_icon]_[S]" in icon_states(icon)) //VOREStation Edit
+ if("[base_icon]_[S]" in cached_icon_states(icon)) //VOREStation Edit
under_liquid |= "[base_icon]_[S]"
- else if("[base_icon][amnt]_[S]" in icon_states(icon)) //VOREStation Edit
+ else if("[base_icon][amnt]_[S]" in cached_icon_states(icon)) //VOREStation Edit
over_liquid |= "[base_icon][amnt]_[S]"
for(var/k in under_liquid)
diff --git a/code/modules/food/kitchen/microwave.dm b/code/modules/food/kitchen/microwave.dm
index b9beeed09b..593a7892fd 100644
--- a/code/modules/food/kitchen/microwave.dm
+++ b/code/modules/food/kitchen/microwave.dm
@@ -31,13 +31,11 @@
********************/
/obj/machinery/microwave/Initialize()
+ . = ..()
reagents = new/datum/reagents(100)
reagents.my_atom = src
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
+ default_apply_parts()
if (!available_recipes)
available_recipes = new
@@ -60,9 +58,7 @@
acceptable_items |= /obj/item/device/soulstone
acceptable_items |= /obj/item/weapon/fuel_assembly/supermatter
- RefreshParts()
soundloop = new(list(src), FALSE)
- return ..()
/obj/machinery/microwave/Destroy()
QDEL_NULL(soundloop)
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 982f44e794..90afa7f416 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -141,7 +141,7 @@
var/image/fruit_base = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-product")
fruit_base.color = "[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"
plant_icon.overlays |= fruit_base
- if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in icon_states('icons/obj/hydroponics_products.dmi'))
+ if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in cached_icon_states('icons/obj/hydroponics_products.dmi'))
var/image/fruit_leaves = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf")
fruit_leaves.color = "[seed.get_trait(TRAIT_PLANT_COLOUR)]"
plant_icon.overlays |= fruit_leaves
diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm
index 1ca42f4c60..28315b361a 100644
--- a/code/modules/hydroponics/seed_controller.dm
+++ b/code/modules/hydroponics/seed_controller.dm
@@ -53,7 +53,7 @@ var/global/datum/controller/plants/plant_controller // Set in New().
/datum/controller/plants/proc/setup()
// Build the icon lists.
- for(var/icostate in icon_states('icons/obj/hydroponics_growing.dmi'))
+ for(var/icostate in cached_icon_states('icons/obj/hydroponics_growing.dmi'))
var/split = findtext(icostate,"-")
if(!split)
// invalid icon_state
@@ -71,7 +71,7 @@ var/global/datum/controller/plants/plant_controller // Set in New().
if(!(base in GLOB.forbidden_plant_growth_sprites))
accessible_plant_sprites[base] = ikey
- for(var/icostate in icon_states('icons/obj/hydroponics_products.dmi'))
+ for(var/icostate in cached_icon_states('icons/obj/hydroponics_products.dmi'))
var/split = findtext(icostate,"-")
var/base = copytext(icostate,1,split)
if(split)
diff --git a/code/modules/integrated_electronics/subtypes/time.dm b/code/modules/integrated_electronics/subtypes/time.dm
index df8e686b1f..9633ef7881 100644
--- a/code/modules/integrated_electronics/subtypes/time.dm
+++ b/code/modules/integrated_electronics/subtypes/time.dm
@@ -86,10 +86,10 @@
power_draw_per_use = 4
/obj/item/integrated_circuit/time/clock/do_work()
- set_pin_data(IC_OUTPUT, 1, time2text(station_time_in_ticks, "hh:mm:ss") )
- set_pin_data(IC_OUTPUT, 2, text2num(time2text(station_time_in_ticks, "hh") ) )
- set_pin_data(IC_OUTPUT, 3, text2num(time2text(station_time_in_ticks, "mm") ) )
- set_pin_data(IC_OUTPUT, 4, text2num(time2text(station_time_in_ticks, "ss") ) )
+ set_pin_data(IC_OUTPUT, 1, time2text(station_time_in_ds, "hh:mm:ss") )
+ set_pin_data(IC_OUTPUT, 2, text2num(time2text(station_time_in_ds, "hh") ) )
+ set_pin_data(IC_OUTPUT, 3, text2num(time2text(station_time_in_ds, "mm") ) )
+ set_pin_data(IC_OUTPUT, 4, text2num(time2text(station_time_in_ds, "ss") ) )
push_data()
activate_pin(2)
diff --git a/code/modules/maps/tg/reader.dm b/code/modules/maps/tg/reader.dm
index 71adb65bad..b7bf3561f5 100644
--- a/code/modules/maps/tg/reader.dm
+++ b/code/modules/maps/tg/reader.dm
@@ -2,15 +2,9 @@
//SS13 Optimized Map loader
//////////////////////////////////////////////////////////////
-/*
//global datum that will preload variables on atoms instanciation
GLOBAL_VAR_INIT(use_preloader, FALSE)
GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
-*/
-
-//global datum that will preload variables on atoms instanciation
-var/global/dmm_suite/preloader/_preloader = new()
-var/global/use_preloader = FALSE
/dmm_suite
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
@@ -36,6 +30,12 @@ var/global/use_preloader = FALSE
*
*/
/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num, orientation as num)
+
+ dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
+ trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g")
+ trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g")
+ modelCache = list()
+
//How I wish for RAII
if(!measureOnly)
Master.StartLoadingMap()
@@ -350,7 +350,7 @@ var/global/use_preloader = FALSE
index = members.len
if(members[index] != /area/template_noop)
var/atom/instance
- _preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
+ GLOB._preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
var/atype = members[index]
for(var/area/A in world)
if(A.type == atype)
@@ -361,8 +361,8 @@ var/global/use_preloader = FALSE
if(crds)
instance.contents.Add(crds)
- if(use_preloader && instance)
- _preloader.load(instance)
+ if(GLOB.use_preloader && instance)
+ GLOB._preloader.load(instance)
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
@@ -398,7 +398,7 @@ var/global/use_preloader = FALSE
//Instance an atom at (x,y,z) and gives it the variables in attributes
/dmm_suite/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf, orientation=0)
- _preloader.setup(attributes, path)
+ GLOB._preloader.setup(attributes, path)
if(crds)
if(!no_changeturf && ispath(path, /turf))
@@ -406,8 +406,8 @@ var/global/use_preloader = FALSE
else
. = create_atom(path, crds)//first preloader pass
- if(use_preloader && .)//second preloader pass, for those atoms that don't ..() in New()
- _preloader.load(.)
+ if(GLOB.use_preloader && .)//second preloader pass, for those atoms that don't ..() in New()
+ GLOB._preloader.load(.)
//custom CHECK_TICK here because we don't want things created while we're sleeping to not initialize
if(TICK_CHECK)
@@ -530,7 +530,7 @@ var/global/use_preloader = FALSE
/dmm_suite/preloader/proc/setup(list/the_attributes, path)
if(the_attributes.len)
- use_preloader = TRUE
+ GLOB.use_preloader = TRUE
attributes = the_attributes
target_path = path
@@ -540,7 +540,7 @@ var/global/use_preloader = FALSE
if(islist(value))
value = deepCopyList(value)
what.vars[attribute] = value
- use_preloader = FALSE
+ GLOB.use_preloader = FALSE
/area/template_noop
name = "Area Passthrough"
diff --git a/code/modules/media/mediamanager.dm b/code/modules/media/mediamanager.dm
index 96b9ab36cb..5ff00d5eee 100644
--- a/code/modules/media/mediamanager.dm
+++ b/code/modules/media/mediamanager.dm
@@ -11,7 +11,7 @@
#ifdef DEBUG_MEDIAPLAYER
#define MP_DEBUG(x) to_chat(owner,x)
-#warning Please comment out #define DEBUG_MEDIAPLAYER before committing.
+#warn Please comment out #define DEBUG_MEDIAPLAYER before committing.
#else
#define MP_DEBUG(x)
#endif
diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm
index 3c38927910..f4e51a0c30 100644
--- a/code/modules/mining/drilling/drill.dm
+++ b/code/modules/mining/drilling/drill.dm
@@ -52,16 +52,9 @@
var/need_update_field = 0
var/need_player_check = 0
-/obj/machinery/mining/drill/New()
-
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/cell/high(src)
-
- RefreshParts()
+/obj/machinery/mining/drill/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/mining/drill/process()
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index e1a3e01690..79ef6b1c4c 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -163,6 +163,8 @@ turf/simulated/mineral/floor/light_corner
if(random_icon)
dir = pick(alldirs)
. = INITIALIZE_HINT_LATELOAD
+ var/decl/flooring/F = get_flooring_data(/decl/flooring/sand)
+ footstep_sounds = F?.footstep_sounds
/turf/simulated/mineral/LateInitialize()
if(density && mineral)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index e20d3740c9..349859029f 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -152,6 +152,13 @@
if(new_stat != DEAD)
CRASH("It is best if observers stay dead, thank you.")
+/mob/observer/dead/examine_icon()
+ var/icon/I = get_cached_examine_icon(src)
+ if(!I)
+ I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE)
+ set_cached_examine_icon(src, I, 200 SECONDS)
+ return I
+
/*
Transfer_mind is there to check if mob is being deleted/not going to have a body.
Works together with spawning an observer, noted above.
diff --git a/code/modules/mob/freelook/ai/eye.dm b/code/modules/mob/freelook/ai/eye.dm
index c79417cb86..5b37804da3 100644
--- a/code/modules/mob/freelook/ai/eye.dm
+++ b/code/modules/mob/freelook/ai/eye.dm
@@ -10,17 +10,36 @@
/mob/observer/eye/aiEye/New()
..()
visualnet = cameranet
+
+/mob/observer/eye/aiEye/Destroy()
+ if(owner)
+ var/mob/living/silicon/ai/ai = owner
+ ai.all_eyes -= src
+ owner = null
+ . = ..()
/mob/observer/eye/aiEye/setLoc(var/T, var/cancel_tracking = 1)
- if(..())
+ if(owner)
+ T = get_turf(T)
+ loc = T
+
var/mob/living/silicon/ai/ai = owner
if(cancel_tracking)
ai.ai_cancel_tracking()
- //Holopad
+ if(use_static)
+ ai.camera_visibility(src)
+
+ if(ai.client && !ai.multicam_on)
+ ai.client.eye = src
+
+ if(ai.master_multicam)
+ ai.master_multicam.refresh_view()
+
if(ai.holo)
if(ai.hologram_follow)
ai.holo.move_hologram(ai)
+
return 1
// AI MOVEMENT
@@ -46,6 +65,7 @@
if(!newloc)
newloc = src.loc
eyeobj = new /mob/observer/eye/aiEye(newloc)
+ all_eyes += eyeobj
eyeobj.owner = src
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
if(client)
@@ -66,7 +86,12 @@
/atom/proc/move_camera_by_click()
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
- if(AI.eyeobj && AI.client.eye == AI.eyeobj)
+ if(AI.eyeobj)
+ if(!AI.multicam_on || AI.client.eye != AI.eyeobj)
+ return
+ var/area/A = get_area(AI.eyeobj)
+ if(istype(A, /area/ai_multicam_room))
+ return
var/turf/T = get_turf(src)
if(T)
AI.eyeobj.setLoc(T)
diff --git a/code/modules/mob/freelook/chunk.dm b/code/modules/mob/freelook/chunk.dm
index 41439b4adc..5f59d2e737 100644
--- a/code/modules/mob/freelook/chunk.dm
+++ b/code/modules/mob/freelook/chunk.dm
@@ -25,12 +25,12 @@
// Add an eye to the chunk, then update if changed.
-/datum/chunk/proc/add(mob/observer/eye/eye)
- if(!eye.owner)
- return
+/datum/chunk/proc/add(mob/observer/eye/eye, add_images = TRUE)
+ if(add_images)
+ var/client/client = eye.GetViewerClient()
+ if(client)
+ client.images += obscured
eye.visibleChunks += src
- if(eye.owner.client)
- eye.owner.client.images += obscured
visible++
seenby += eye
if(changed && !updating)
@@ -38,12 +38,12 @@
// Remove an eye from the chunk, then update if changed.
-/datum/chunk/proc/remove(mob/observer/eye/eye)
- if(!eye.owner)
- return
+/datum/chunk/proc/remove(mob/observer/eye/eye, remove_images = TRUE)
+ if(remove_images)
+ var/client/client = eye.GetViewerClient()
+ if(client)
+ client.images -= obscured
eye.visibleChunks -= src
- if(eye.owner.client)
- eye.owner.client.images -= obscured
seenby -= eye
if(visible > 0)
visible--
@@ -92,10 +92,11 @@
obscured -= t.obfuscations[obfuscation.type]
for(var/eye in seenby)
var/mob/observer/eye/m = eye
- if(!m || !m.owner)
+ if(!m)
continue
- if(m.owner.client)
- m.owner.client.images -= t.obfuscations[obfuscation.type]
+ var/client/client = m.GetViewerClient()
+ if(client)
+ client.images -= t.obfuscations[obfuscation.type]
for(var/turf in visRemoved)
var/turf/t = turf
@@ -109,11 +110,12 @@
obscured += t.obfuscations[obfuscation.type]
for(var/eye in seenby)
var/mob/observer/eye/m = eye
- if(!m || !m.owner)
+ if(!m)
seenby -= m
continue
- if(m.owner.client)
- m.owner.client.images += t.obfuscations[obfuscation.type]
+ var/client/client = m.GetViewerClient()
+ if(client)
+ client.images += t.obfuscations[obfuscation.type]
/datum/chunk/proc/acquireVisibleTurfs(var/list/visible)
diff --git a/code/modules/mob/freelook/eye.dm b/code/modules/mob/freelook/eye.dm
index 85cfc736c9..89a15c3000 100644
--- a/code/modules/mob/freelook/eye.dm
+++ b/code/modules/mob/freelook/eye.dm
@@ -23,6 +23,8 @@
var/ghostimage = null
var/datum/visualnet/visualnet
+ var/use_static = TRUE
+ var/static_visibility_range = 16
/mob/observer/eye/Destroy()
if(owner)
@@ -67,8 +69,8 @@
visualnet.updateVisibility(owner, 0)
owner.loc = loc
visualnet.updateVisibility(owner, 0)
-
- visualnet.visibility(src)
+ if(use_static)
+ visualnet.visibility(src, owner.client)
return 1
return 0
@@ -85,6 +87,11 @@
return
return eyeobj.EyeMove(n, direct)
+
+/mob/observer/eye/proc/GetViewerClient()
+ if(owner)
+ return owner.client
+ return null
/mob/observer/eye/EyeMove(n, direct)
var/initial = initial(sprint)
diff --git a/code/modules/mob/freelook/visualnet.dm b/code/modules/mob/freelook/visualnet.dm
index bbcd0c7d66..44cd9278cc 100644
--- a/code/modules/mob/freelook/visualnet.dm
+++ b/code/modules/mob/freelook/visualnet.dm
@@ -2,6 +2,8 @@
//
// The datum containing all the chunks.
+#define CHUNK_SIZE 16
+
/datum/visualnet
// The chunks of the map, mapping the areas that an object can see.
var/list/chunks = list()
@@ -36,29 +38,63 @@
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
-/datum/visualnet/proc/visibility(mob/observer/eye/eye)
- // 0xf = 15
- var/x1 = max(0, eye.x - 16) & ~0xf
- var/y1 = max(0, eye.y - 16) & ~0xf
- var/x2 = min(world.maxx, eye.x + 16) & ~0xf
- var/y2 = min(world.maxy, eye.y + 16) & ~0xf
+/datum/visualnet/proc/visibility(list/moved_eyes, client/C, list/other_eyes)
+ if(!islist(moved_eyes))
+ moved_eyes = moved_eyes ? list(moved_eyes) : list()
+ if(islist(other_eyes))
+ other_eyes = (other_eyes - moved_eyes)
+ else
+ other_eyes = list()
- var/list/visibleChunks = list()
+ var/list/chunks_pre_seen = list()
+ var/list/chunks_post_seen = list()
- for(var/x = x1; x <= x2; x += 16)
- for(var/y = y1; y <= y2; y += 16)
- visibleChunks += getChunk(x, y, eye.z)
+ for(var/V in moved_eyes)
+ var/mob/observer/eye/eye = V
+ if(C)
+ chunks_pre_seen |= eye.visibleChunks
+ // 0xf = 15
+ var/static_range = eye.static_visibility_range
+ var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
+ var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
+ var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
+ var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
- var/list/remove = eye.visibleChunks - visibleChunks
- var/list/add = visibleChunks - eye.visibleChunks
+ var/list/visibleChunks = list()
- for(var/chunk in remove)
- var/datum/chunk/c = chunk
- c.remove(eye)
+ for(var/x = x1; x <= x2; x += CHUNK_SIZE)
+ for(var/y = y1; y <= y2; y += CHUNK_SIZE)
+ visibleChunks |= getChunk(x, y, eye.z)
- for(var/chunk in add)
- var/datum/chunk/c = chunk
- c.add(eye)
+ var/list/remove = eye.visibleChunks - visibleChunks
+ var/list/add = visibleChunks - eye.visibleChunks
+
+ for(var/chunk in remove)
+ var/datum/chunk/c = chunk
+ c.remove(eye, FALSE)
+
+ for(var/chunk in add)
+ var/datum/chunk/c = chunk
+ c.add(eye, FALSE)
+
+ if(C)
+ chunks_post_seen |= eye.visibleChunks
+
+ if(C)
+ for(var/V in other_eyes)
+ var/mob/observer/eye/eye = V
+ chunks_post_seen |= eye.visibleChunks
+
+ var/list/remove = chunks_pre_seen - chunks_post_seen
+ var/list/add = chunks_post_seen - chunks_pre_seen
+
+ for(var/chunk in remove)
+ var/datum/chunk/c = chunk
+ C.images -= c.obscured
+
+ for(var/chunk in add)
+ var/datum/chunk/c = chunk
+ C.images += c.obscured
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index f7ee2d9520..9687bde18f 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1596,6 +1596,13 @@
else
layer = HIDING_LAYER
+/mob/living/carbon/human/examine_icon()
+ var/icon/I = get_cached_examine_icon(src)
+ if(!I)
+ I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE)
+ set_cached_examine_icon(src, I, 50 SECONDS)
+ return I
+
/mob/living/carbon/human/proc/get_display_species()
//Shows species in tooltip
if(src.custom_species) //VOREStation Add
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index a0892c9fc9..cd2d368d6d 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -2,40 +2,38 @@
/mob/living/carbon/human/movement_delay(oldloc, direct)
- var/tally = 0
+ . = 0
+
+ if (istype(loc, /turf/space))
+ return ..() - 1
if(species.slowdown)
- tally = species.slowdown
-
- if (istype(loc, /turf/space)) return -1 // It's hard to be slowed down in space by... anything
-
- if(embedded_flag)
- handle_embedded_objects() //Moving with objects stuck in you can cause bad times.
+ . += species.slowdown
if(force_max_speed)
- return HUMAN_LOWEST_SLOWDOWN
+ return ..() + HUMAN_LOWEST_SLOWDOWN
for(var/datum/modifier/M in modifiers)
if(!isnull(M.haste) && M.haste == TRUE)
- return HUMAN_LOWEST_SLOWDOWN // Returning -1 will actually result in a slowdown for Teshari.
+ return ..() + HUMAN_LOWEST_SLOWDOWN // Returning -1 will actually result in a slowdown for Teshari.
if(!isnull(M.slowdown))
- tally += M.slowdown
+ . += M.slowdown
var/health_deficiency = (getMaxHealth() - health)
- if(health_deficiency >= 40) tally += (health_deficiency / 25)
+ if(health_deficiency >= 40) . += (health_deficiency / 25)
if(can_feel_pain())
- if(halloss >= 10) tally += (halloss / 10) //halloss shouldn't slow you down if you can't even feel it
+ if(halloss >= 10) . += (halloss / 10) //halloss shouldn't slow you down if you can't even feel it
var/hungry = (500 - nutrition) / 5 //VOREStation Edit - Fixed 500 here instead of our huge MAX_NUTRITION
- if (hungry >= 70) tally += hungry/50
+ if (hungry >= 70) . += hungry/50
//VOREstation start
if (feral >= 10) //crazy feral animals give less and less of a shit about pain and hunger as they get crazier
- tally = max(species.slowdown, species.slowdown+((tally-species.slowdown)/(feral/10))) // As feral scales to damage, this amounts to an effective +1 slowdown cap
- if(shock_stage >= 10) tally -= 1.5 //this gets a +3 later, feral critters take reduced penalty
+ . = max(species.slowdown, species.slowdown+((.-species.slowdown)/(feral/10))) // As feral scales to damage, this amounts to an effective +1 slowdown cap
+ if(shock_stage >= 10) . -= 1.5 //this gets a +3 later, feral critters take reduced penalty
if(reagents.has_reagent("numbenzyme"))
- tally += 1.5 //A tad bit of slowdown.
+ . += 1.5 //A tad bit of slowdown.
if(riding_datum) //Bit of slowdown for taur rides if rider is bigger or fatter than mount.
var/datum/riding/R = riding_datum
var/mob/living/L = R.ridden
@@ -43,48 +41,48 @@
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.size_multiplier > L.size_multiplier)
- tally += 1
+ . += 1
if(H.weight > L.weight)
- tally += 1
+ . += 1
//VOREstation end
if(istype(buckled, /obj/structure/bed/chair/wheelchair))
for(var/organ_name in list(BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
- tally += 4
+ . += 4
else if(E.splinted && E.splinted.loc != E)
- tally += 0.5
+ . += 0.5
else if(E.status & ORGAN_BROKEN)
- tally += 1.5
+ . += 1.5
else
for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
- tally += 4
+ . += 4
else if(E.splinted && E.splinted.loc != E)
- tally += 0.5
+ . += 0.5
else if(E.status & ORGAN_BROKEN)
- tally += 1.5
+ . += 1.5
- if(shock_stage >= 10) tally += 3
+ if(shock_stage >= 10) . += 3
- if(aiming && aiming.aiming_at) tally += 5 // Iron sights make you slower, it's a well-known fact.
+ if(aiming && aiming.aiming_at) . += 5 // Iron sights make you slower, it's a well-known fact.
if(FAT in src.mutations)
- tally += 1.5
+ . += 1.5
if (bodytemperature < species.cold_level_1)
- tally += (species.cold_level_1 - bodytemperature) / 10 * 1.75
+ . += (species.cold_level_1 - bodytemperature) / 10 * 1.75
- tally += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow
+ . += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow
if(mRun in mutations)
- tally = 0
+ . = 0
// Turf related slowdown
var/turf/T = get_turf(src)
- tally += calculate_turf_slowdown(T, direct)
+ . += calculate_turf_slowdown(T, direct)
// Item related slowdown.
var/item_tally = calculate_item_encumbrance()
@@ -101,19 +99,25 @@
item_tally *= species.item_slowdown_mod
- tally += item_tally
+ . += item_tally
if(CE_SLOWDOWN in chem_effects)
- if (tally >= 0 )
- tally = (tally + tally/4) //Add a quarter of penalties on top.
- tally += chem_effects[CE_SLOWDOWN]
+ if (. >= 0 )
+ . *= 1.25 //Add a quarter of penalties on top.
+ . += chem_effects[CE_SLOWDOWN]
if(CE_SPEEDBOOST in chem_effects)
- if (tally >= 0) // cut any penalties in half
- tally = tally/2
- tally -= chem_effects[CE_SPEEDBOOST] // give 'em a buff on top.
+ if (. >= 0) // cut any penalties in half
+ . *= 0.5
+ . -= chem_effects[CE_SPEEDBOOST] // give 'em a buff on top.
- return max(HUMAN_LOWEST_SLOWDOWN, tally+config.human_delay) // Minimum return should be the same as force_max_speed
+ . = max(HUMAN_LOWEST_SLOWDOWN, . + config.human_delay) // Minimum return should be the same as force_max_speed
+ . += ..()
+
+/mob/living/carbon/human/Moved()
+ . = ..()
+ if(embedded_flag)
+ handle_embedded_objects() //Moving with objects stuck in you can cause bad times.
// This calculates the amount of slowdown to receive from items worn. This does NOT include species modifiers.
// It is in a seperate place to avoid an infinite loop situation with dragging mobs dragging each other.
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index e4162219fe..ed41c4c69b 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -322,7 +322,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3]))
//Handle husk overlay.
- if(husk && ("overlay_husk" in icon_states(species.icobase)))
+ if(husk && ("overlay_husk" in cached_icon_states(species.icobase)))
var/icon/mask = new(base_icon)
var/icon/husk_over = new(species.icobase,"overlay_husk")
mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 8fc975073e..d74f43bced 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -224,7 +224,15 @@ default behaviour is:
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
- step(AM, t)
+ var/turf/T = AM.loc
+ var/turf/T2 = get_step(AM,t)
+ if(!T2) // Map edge
+ now_pushing = 0
+ return
+ var/move_time = movement_delay(loc, t)
+ move_time = DS2NEARESTTICK(move_time)
+ if(AM.Move(T2, t, move_time))
+ Move(T, t, move_time)
if(ishuman(AM) && AM:grabbed_by)
for(var/obj/item/weapon/grab/G in AM:grabbed_by)
step(G:assailant, get_dir(G:assailant, AM))
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index fa59ebf5c8..61f0be1a95 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -85,6 +85,14 @@ var/list/ai_verbs_default = list(
var/datum/ai_icon/selected_sprite // The selected icon set
var/custom_sprite = 0 // Whether the selected icon is custom
var/carded
+
+ // Multicam Vars
+ var/multicam_allowed = TRUE
+ var/multicam_on = FALSE
+ var/obj/screen/movable/pic_in_pic/ai/master_multicam
+ var/list/multicam_screens = list()
+ var/list/all_eyes = list()
+ var/max_multicams = 6
can_be_antagged = TRUE
@@ -478,12 +486,27 @@ var/list/ai_verbs_default = list(
return
+/mob/living/silicon/ai/proc/camera_visibility(mob/observer/eye/aiEye/moved_eye)
+ cameranet.visibility(moved_eye, client, all_eyes)
+
+/mob/living/silicon/ai/forceMove(atom/destination)
+ . = ..()
+ if(.)
+ end_multicam()
+
/mob/living/silicon/ai/reset_view(atom/A)
if(camera)
camera.set_light(0)
if(istype(A,/obj/machinery/camera))
camera = A
- ..()
+ if(A != GLOB.ai_camera_room_landmark)
+ end_multicam()
+ . = ..()
+ if(.)
+ if(!A && isturf(loc) && eyeobj)
+ end_multicam()
+ client.eye = eyeobj
+ client.perspective = MOB_PERSPECTIVE
if(istype(A,/obj/machinery/camera))
if(camera_light_on) A.set_light(AI_CAMERA_LUMINOSITY)
else A.set_light(0)
diff --git a/code/modules/mob/living/silicon/ai/ai_vr.dm b/code/modules/mob/living/silicon/ai/ai_vr.dm
index 0fe723cad3..2f22d0e788 100644
--- a/code/modules/mob/living/silicon/ai/ai_vr.dm
+++ b/code/modules/mob/living/silicon/ai/ai_vr.dm
@@ -7,7 +7,7 @@
add_language(LANGUAGE_DAEMON, 1)
add_language(LANGUAGE_ENOCHIAN, 1)
-/mob/AIize(move = 1)
+/mob/AIize(var/move = TRUE)
. = ..()
add_language(LANGUAGE_BIRDSONG, 1)
add_language(LANGUAGE_SAGARU, 1)
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index b1398d3170..e155b8e005 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -94,6 +94,7 @@
spawn(20)
to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.")
+ end_multicam()
sleep(50)
if (loc.power_equip)
if (!istype(T, /turf/space))
diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm
index fa06162c31..57856a861f 100644
--- a/code/modules/mob/living/silicon/ai/login.dm
+++ b/code/modules/mob/living/silicon/ai/login.dm
@@ -1,4 +1,4 @@
-/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up ¬_¬ ~Carn
+/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up �_� ~Carn
..()
for(var/obj/effect/rune/rune in rune_list)
client.images += rune.blood_image
@@ -6,5 +6,7 @@
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 1
O.emotion = "Neutral"
+ if(multicam_on)
+ end_multicam()
src.view_core()
return
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm
new file mode 100644
index 0000000000..018454608c
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/multicam.dm
@@ -0,0 +1,327 @@
+//Picture in picture
+
+/obj/screen/movable/pic_in_pic/ai
+ var/mob/living/silicon/ai/ai
+ var/list/highlighted_mas = list()
+ var/highlighted = FALSE
+ var/mob/observer/eye/aiEye/pic_in_pic/aiEye
+
+/obj/screen/movable/pic_in_pic/ai/Initialize()
+ . = ..()
+ aiEye = new /mob/observer/eye/aiEye/pic_in_pic()
+ aiEye.screen = src
+
+/obj/screen/movable/pic_in_pic/ai/Destroy()
+ . = ..()
+ if(!QDELETED(aiEye))
+ QDEL_NULL(aiEye)
+ else
+ aiEye = null
+ set_ai(null)
+
+/obj/screen/movable/pic_in_pic/ai/Click()
+ ..()
+ if(ai)
+ ai.select_main_multicam_window(src)
+
+/obj/screen/movable/pic_in_pic/ai/make_backgrounds()
+ ..()
+ var/mutable_appearance/base = new /mutable_appearance()
+ base.icon = 'icons/misc/pic_in_pic.dmi'
+ base.layer = DISPOSAL_LAYER
+ base.plane = PLATING_PLANE
+ base.appearance_flags = PIXEL_SCALE
+
+ for(var/direction in cardinal)
+ var/mutable_appearance/dir = new /mutable_appearance(base)
+ dir.dir = direction
+ dir.icon_state = "background_highlight_[direction]"
+ highlighted_mas += dir
+
+/obj/screen/movable/pic_in_pic/ai/add_background()
+ if((width > 0) && (height > 0))
+ if(!highlighted)
+ return ..()
+
+ for(var/mutable_appearance/dir in highlighted_mas)
+ var/matrix/M = matrix()
+ var/x_scale = 1
+ var/y_scale = 1
+
+ var/x_off = 0
+ var/y_off = 0
+
+ if(dir.dir & (NORTH|SOUTH))
+ x_scale = width
+ x_off = (width-1)/2 * world.icon_size
+ if(dir.dir & NORTH)
+ y_off = ((height-1) * world.icon_size) + 3
+ else
+ y_off = -3
+
+ if(dir.dir & (EAST|WEST))
+ y_scale = height
+ y_off = (height-1)/2 * world.icon_size
+ if(dir.dir & EAST)
+ x_off = ((width-1) * world.icon_size) + 3
+ else
+ x_off = -3
+
+ M.Scale(x_scale, y_scale)
+ M.Translate(x_off, y_off)
+ dir.transform = M
+ overlays += dir
+
+/obj/screen/movable/pic_in_pic/ai/set_view_size(width, height, do_refresh = TRUE)
+ if(!aiEye)
+ qdel(src)
+ return
+
+ aiEye.static_visibility_range = (round(max(width, height) / 2) + 1)
+ if(ai)
+ ai.camera_visibility(aiEye)
+ ..()
+
+/obj/screen/movable/pic_in_pic/ai/set_view_center(atom/target, do_refresh = TRUE)
+ ..()
+ if(!aiEye)
+ qdel(src)
+ return
+
+ aiEye.setLoc(get_turf(target))
+
+/obj/screen/movable/pic_in_pic/ai/refresh_view()
+ ..()
+ if(!aiEye)
+ qdel(src)
+ return
+
+ aiEye.setLoc(get_turf(center))
+
+/obj/screen/movable/pic_in_pic/ai/proc/highlight()
+ if(highlighted)
+ return
+ if(!aiEye)
+ qdel(src)
+ return
+ highlighted = TRUE
+ overlays.Cut()
+ add_background()
+ add_buttons()
+
+/obj/screen/movable/pic_in_pic/ai/proc/unhighlight()
+ if(!highlighted)
+ return
+ if(!aiEye)
+ qdel(src)
+ return
+ highlighted = FALSE
+ overlays.Cut()
+ add_background()
+ add_buttons()
+
+/obj/screen/movable/pic_in_pic/ai/proc/set_ai(mob/living/silicon/ai/new_ai)
+ if(!aiEye && !QDELETED(src))
+ if(new_ai)
+ to_chat(new_ai, "You've run into a unfixable bug with AI eye code. \
+In order to create a new multicam, you will have to select a different camera first before trying to add one, or ask an admin to fix you. \
+Whatever you did that made the last camera window disappear-- don't do that again.
")
+ qdel(src)
+ return
+ if(ai)
+ ai.multicam_screens -= src
+ ai.all_eyes -= aiEye
+ if(ai.master_multicam == src)
+ ai.master_multicam = null
+ if(ai.multicam_on)
+ unshow_to(ai.client)
+ ai = new_ai
+ if(new_ai)
+ new_ai.multicam_screens += src
+ ai.all_eyes += aiEye
+ if(new_ai.multicam_on)
+ show_to(new_ai.client)
+
+//Turf, area, and landmark for the viewing room
+
+/turf/unsimulated/ai_visible
+ name = ""
+ icon = 'icons/misc/pic_in_pic.dmi'
+ icon_state = "room_background"
+ flags = NOJAUNT
+ plane = SPACE_PLANE
+ layer = AREA_LAYER + 0.1
+
+/turf/unsimulated/ai_visible/Initialize()
+ . = ..()
+
+/area/ai_multicam_room
+ name = "ai_multicam_room"
+ icon_state = "ai_camera_room"
+ dynamic_lighting = FALSE
+ ambience = list()
+
+GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
+
+/obj/effect/landmark/ai_multicam_room
+ name = "ai camera room"
+ icon_state = "x"
+
+/obj/effect/landmark/ai_multicam_room/Initialize()
+ . = ..()
+ qdel(GLOB.ai_camera_room_landmark)
+ GLOB.ai_camera_room_landmark = src
+
+/obj/effect/landmark/ai_multicam_room/Destroy()
+ if(GLOB.ai_camera_room_landmark == src)
+ GLOB.ai_camera_room_landmark = null
+ return ..()
+
+//Dummy camera eyes
+
+/mob/observer/eye/aiEye/pic_in_pic
+ name = "Secondary AI Eye"
+ var/obj/screen/movable/pic_in_pic/ai/screen
+ var/list/cameras_telegraphed = list()
+ var/telegraph_cameras = TRUE
+ var/telegraph_range = 7
+
+/mob/observer/eye/aiEye/pic_in_pic/GetViewerClient()
+ if(screen && screen.ai)
+ return screen.ai.client
+
+/mob/observer/eye/aiEye/pic_in_pic/setLoc(turf/T)
+ T = get_turf(T)
+ forceMove(T)
+ if(screen && screen.ai)
+ screen.ai.camera_visibility(src)
+ else
+ cameranet.visibility(src)
+ update_camera_telegraphing()
+
+/mob/observer/eye/aiEye/pic_in_pic/proc/update_camera_telegraphing()
+ if(!telegraph_cameras)
+ return
+ var/list/obj/machinery/camera/add = list()
+ var/list/obj/machinery/camera/remove = list()
+ var/list/obj/machinery/camera/visible = list()
+ for(var/VV in visibleChunks)
+ var/datum/chunk/camera/CC = VV
+ for(var/V in CC.cameras)
+ var/obj/machinery/camera/C = V
+ if (!C.can_use() || (get_dist(C, src) > telegraph_range))
+ continue
+ visible |= C
+
+ add = visible - cameras_telegraphed
+ remove = cameras_telegraphed - visible
+
+ for(var/V in remove)
+ var/obj/machinery/camera/C = V
+ if(QDELETED(C))
+ continue
+ cameras_telegraphed -= C
+ C.in_use_lights--
+ C.update_icon()
+ for(var/V in add)
+ var/obj/machinery/camera/C = V
+ if(QDELETED(C))
+ continue
+ cameras_telegraphed |= C
+ C.in_use_lights++
+ C.update_icon()
+
+/mob/observer/eye/aiEye/pic_in_pic/proc/disable_camera_telegraphing()
+ telegraph_cameras = FALSE
+ for(var/V in cameras_telegraphed)
+ var/obj/machinery/camera/C = V
+ if(QDELETED(C))
+ continue
+ C.in_use_lights--
+ C.update_icon()
+ cameras_telegraphed.Cut()
+
+/mob/observer/eye/aiEye/pic_in_pic/Destroy()
+ disable_camera_telegraphing()
+ if(screen && screen.ai)
+ screen.ai.all_eyes -= src
+ if(!QDELETED(screen))
+ QDEL_NULL(screen)
+ else
+ screen = null
+ return ..()
+
+//AI procs
+
+/mob/living/silicon/ai/proc/drop_new_multicam(silent = FALSE)
+ if(!multicam_allowed)
+ if(!silent)
+ to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.")
+ return
+ if(!eyeobj)
+ return
+ if(multicam_screens.len >= max_multicams)
+ if(!silent)
+ to_chat(src, "Cannot place more than [max_multicams] multicamera windows.")
+ return
+ var/obj/screen/movable/pic_in_pic/ai/C = new /obj/screen/movable/pic_in_pic/ai()
+ C.set_view_size(3, 3, FALSE)
+ C.set_view_center(get_turf(eyeobj))
+ C.set_ai(src)
+ if(!silent)
+ to_chat(src, "Added new multicamera window.")
+ return C
+
+/mob/living/silicon/ai/proc/toggle_multicam()
+ if(!multicam_allowed)
+ to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.")
+ return
+ if(multicam_on)
+ end_multicam()
+ else
+ start_multicam()
+
+/mob/living/silicon/ai/proc/start_multicam()
+ if(multicam_on || aiRestorePowerRoutine || !isturf(loc))
+ return
+ if(!GLOB.ai_camera_room_landmark)
+ to_chat(src, "This function is not available at this time.")
+ return
+ multicam_on = TRUE
+ refresh_multicam()
+ to_chat(src, "Multiple-camera viewing mode activated.")
+
+/mob/living/silicon/ai/proc/refresh_multicam()
+ reset_view(GLOB.ai_camera_room_landmark)
+ if(client)
+ for(var/V in multicam_screens)
+ var/obj/screen/movable/pic_in_pic/P = V
+ P.show_to(client)
+
+/mob/living/silicon/ai/proc/end_multicam()
+ if(!multicam_on)
+ return
+ multicam_on = FALSE
+ select_main_multicam_window(null)
+ if(client)
+ for(var/V in multicam_screens)
+ var/obj/screen/movable/pic_in_pic/P = V
+ P.unshow_to(client)
+ reset_view()
+ to_chat(src, "Multiple-camera viewing mode deactivated.")
+
+
+/mob/living/silicon/ai/proc/select_main_multicam_window(obj/screen/movable/pic_in_pic/ai/P)
+ if(master_multicam == P)
+ return
+
+ if(master_multicam)
+ master_multicam.set_view_center(get_turf(eyeobj), FALSE)
+ master_multicam.unhighlight()
+ master_multicam = null
+
+ if(P)
+ P.highlight()
+ eyeobj.setLoc(get_turf(P.center))
+ P.set_view_center(eyeobj)
+ master_multicam = P
diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm
index 7664e57103..b7241721f1 100644
--- a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm
+++ b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm
@@ -22,7 +22,7 @@
var/emagged = 0
/obj/item/weapon/dogborg/jaws/small/attack_self(mob/user)
- var/mob/living/silicon/robot.R = user
+ var/mob/living/silicon/robot/R = user
if(R.emagged || R.emag_items)
emagged = !emagged
if(emagged)
@@ -187,7 +187,7 @@
. += "[src] is dry."
/obj/item/device/dogborg/tongue/attack_self(mob/user)
- var/mob/living/silicon/robot.R = user
+ var/mob/living/silicon/robot/R = user
if(R.emagged || R.emag_items)
emagged = !emagged
if(emagged)
@@ -222,7 +222,7 @@
to_chat(user, "You finish licking off \the [target.name].")
water.use_charge(5)
qdel(target)
- var/mob/living/silicon/robot.R = user
+ var/mob/living/silicon/robot/R = user
R.cell.charge += 50
else if(istype(target,/obj/item))
if(istype(target,/obj/item/trash))
@@ -231,7 +231,7 @@
user.visible_message("[user] finishes eating \the [target.name].", "You finish eating \the [target.name].")
to_chat(user, "You finish off \the [target.name].")
qdel(target)
- var/mob/living/silicon/robot.R = user
+ var/mob/living/silicon/robot/R = user
R.cell.charge += 250
water.use_charge(5)
return
@@ -249,8 +249,8 @@
if(do_after (user, 50))
user.visible_message("[user] finishes gulping down \the [target.name].", "You finish swallowing \the [target.name].")
to_chat(user, "You finish off \the [target.name], and gain some charge!")
- var/mob/living/silicon/robot.R = user
- var/obj/item/weapon/cell.C = target
+ var/mob/living/silicon/robot/R = user
+ var/obj/item/weapon/cell/C = target
R.cell.charge += C.maxcharge / 3
water.use_charge(5)
qdel(target)
@@ -264,7 +264,7 @@
target.clean_blood()
else if(ishuman(target))
if(src.emagged)
- var/mob/living/silicon/robot.R = user
+ var/mob/living/silicon/robot/R = user
var/mob/living/L = target
if(R.cell.charge <= 666)
return
@@ -307,7 +307,7 @@
flags |= NOBLUDGEON
/obj/item/pupscrubber/attack_self(mob/user)
- var/mob/living/silicon/robot.R = user
+ var/mob/living/silicon/robot/R = user
if(!enabled)
R.scrubbing = TRUE
enabled = TRUE
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index b83b7bfee9..77e0f0cbe9 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -15,14 +15,14 @@
//No longer needed, but I'll leave it here incase we plan to re-use it.
/mob/living/silicon/robot/movement_delay()
- var/tally = 0 //Incase I need to add stuff other than "speed" later
-
- tally = speed
+ . = speed
if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
- tally-=2 // VOREStation Edit
+ . -= 2 // VOREStation Edit
- return tally+config.robot_delay
+ . += config.robot_delay
+
+ . += ..()
// NEW: Use power while moving.
/mob/living/silicon/robot/SelfMove(turf/n, direct)
diff --git a/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm b/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm
index 63d412cb17..4416117d6c 100644
--- a/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm
+++ b/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm
@@ -157,7 +157,7 @@
if("corrupted") // Load them up with ion laws.
var/datum/ai_laws/laws = new() // Start with an empty lawset.
- for(1 to rand(1, 3))
+ for(var/i=1 to rand(1, 3))
laws.add_ion_law(generate_ion_law(exclude_crew_names = TRUE))
return laws
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 2e42d6d92c..b98340baef 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -410,7 +410,7 @@
return
/mob/living/silicon/reset_view()
- ..()
+ . = ..()
if(cameraFollow)
cameraFollow = null
diff --git a/code/modules/mob/living/simple_mob/appearance.dm b/code/modules/mob/living/simple_mob/appearance.dm
index 05f758d7c4..14f09e9057 100644
--- a/code/modules/mob/living/simple_mob/appearance.dm
+++ b/code/modules/mob/living/simple_mob/appearance.dm
@@ -65,7 +65,7 @@
if(!eye_layer)
eye_layer = image(icon, "[icon_state]-eyes")
eye_layer.plane = PLANE_LIGHTING_ABOVE
-
+ eye_layer.appearance_flags = appearance_flags //VOREStation Edit. Make eye overlays respect the mob's scaling settings.
add_overlay(eye_layer)
/mob/living/simple_mob/proc/remove_eyes()
diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm
index 71e7736ebb..3b063e1ac4 100644
--- a/code/modules/mob/living/simple_mob/simple_mob.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob.dm
@@ -212,9 +212,7 @@
return ..()
*/
/mob/living/simple_mob/movement_delay()
- var/tally = 0 //Incase I need to add stuff other than "speed" later
-
- tally = movement_cooldown
+ . = movement_cooldown
if(force_max_speed)
return -3
@@ -223,25 +221,27 @@
if(!isnull(M.haste) && M.haste == TRUE)
return -3
if(!isnull(M.slowdown))
- tally += M.slowdown
+ . += M.slowdown
// Turf related slowdown
var/turf/T = get_turf(src)
if(T && T.movement_cost && !hovering) // Flying mobs ignore turf-based slowdown. Aquatic mobs ignore water slowdown, and can gain bonus speed in it.
if(istype(T,/turf/simulated/floor/water) && aquatic_movement)
- tally -= aquatic_movement - 1
+ . -= aquatic_movement - 1
else
- tally += T.movement_cost
+ . += T.movement_cost
if(purge)//Purged creatures will move more slowly. The more time before their purge stops, the slower they'll move.
- if(tally <= 0)
- tally = 1
- tally *= purge
+ if(. <= 0)
+ . = 1
+ . *= purge
if(m_intent == "walk")
- tally *= 1.5
+ . *= 1.5
- return tally+config.animal_delay
+ . += config.animal_delay
+
+ . += ..()
/mob/living/simple_mob/Stat()
diff --git a/code/modules/mob/living/simple_mob/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
index 257aaff7f2..86380b5b26 100644
--- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
@@ -66,6 +66,7 @@
var/obj/belly/B = belly
for(var/mob/living/M in B)
new_fullness += M.size_multiplier
+ new_fullness = new_fullness / size_multiplier //Divided by pred's size so a macro mob won't get macro belly from a regular prey.
new_fullness = round(new_fullness, 1) // Because intervals of 0.25 are going to make sprite artists cry.
vore_fullness = min(vore_capacity, new_fullness)
@@ -430,4 +431,4 @@
var/armor_soak = get_armor_soak(T, "melee")
T.apply_damage(20, HALLOSS,, armor_block, armor_soak)
if(prob(33))
- T.apply_effect(3, WEAKEN, armor_block)
\ No newline at end of file
+ T.apply_effect(3, WEAKEN, armor_block)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
index 7d32b7b350..6a52dd69b4 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
@@ -113,7 +113,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/aggressive/corrupthound/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
index 4ca3bbec4b..54afef8238 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
@@ -56,7 +56,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/aggressive/deathclaw/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm b/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
index e6b33604b9..323e0d9c9b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
@@ -80,7 +80,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/aggressive/dragon/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm b/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
index 42ee04c417..b58ebca5ae 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
@@ -72,7 +72,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/hippo/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm b/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
index b373dacfd7..8c9f08a471 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
@@ -46,7 +46,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/horse/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm b/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
index 97313f4db1..cf75159b27 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
@@ -285,7 +285,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/otie/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/panther.dm b/code/modules/mob/living/simple_mob/subtypes/vore/panther.dm
index e0e952d001..23c6c4b1d3 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/panther.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/panther.dm
@@ -51,7 +51,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/aggressive/panther/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
index 1c5443f6f5..11c19794f7 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
@@ -197,7 +197,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 3
/mob/living/simple_mob/vore/aggressive/rat/MouseDrop_T(mob/living/M, mob/living/user)
return
@@ -236,4 +236,4 @@
say_got_target = list("SQUEEK!")
/datum/ai_holder/simple_mob/melee/rat
- speak_chance = 3
+ speak_chance = 2
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm b/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
index a8bc70ac0c..65c64bb9f3 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
@@ -91,6 +91,7 @@
can_buckle = TRUE
buckle_movable = TRUE
buckle_lying = FALSE
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
/mob/living/simple_mob/animal/wolf/direwolf/Login()
. = ..()
@@ -98,7 +99,7 @@
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
- movement_cooldown = 0
+ movement_cooldown = 2
/mob/living/simple_mob/animal/wolf/direwolf/MouseDrop_T(mob/living/M, mob/living/user)
return
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index fc326c8d03..34a7035d22 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -15,7 +15,7 @@
if(matches) matches += " and "
matches += "ID ([client.computer_id])"
if(!config.disable_cid_warn_popup)
- spawn() alert("You have logged in already with another key this round, please log out of this one NOW or risk being banned!")
+ spawn() alert("You appear to have logged in with another key this round, which is not permitted. Please contact an administrator if you believe this message to be in error.")
if(matches)
if(M.client)
message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)].", 1)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 315a80702b..44a524155a 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -148,7 +148,18 @@
return 0
/mob/proc/movement_delay(oldloc, direct)
- return 0
+ . = 0
+ if(locate(/obj/item/weapon/grab) in src)
+ . += 7
+
+ // Movespeed delay based on movement mode
+ switch(m_intent)
+ if("run")
+ if(drowsyness > 0)
+ . += 6
+ . += config.run_speed
+ if("walk")
+ . += config.walk_speed
/mob/proc/Life()
// if(organStructure)
@@ -218,7 +229,7 @@
else
client.perspective = EYE_PERSPECTIVE
client.eye = loc
- return
+ return 1
/mob/proc/show_inv(mob/user as mob)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index c7a4a94ce8..3d0f88e7a7 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -37,6 +37,9 @@
if(isliving(usr))
var/mob/living/carbon/C = usr
if(!C.get_active_hand())
+ if(C.pulling)
+ C.stop_pulling()
+ return
to_chat(usr, "You have nothing to drop in your hand.")
return
drop_item()
@@ -246,26 +249,9 @@
// We are now going to move
moving = 1
- var/total_delay = 0
+ var/total_delay = my_mob.movement_delay(n, direct)
var/pre_move_loc = loc
- // Start tally'ing when we can next move
- // Grabs slow you down
- if(locate(/obj/item/weapon/grab) in my_mob)
- total_delay += 7
-
- // Movespeed delay based on movement mode
- switch(my_mob.m_intent)
- if("run")
- if(my_mob.drowsyness > 0)
- total_delay += 6
- total_delay += config.run_speed
- if("walk")
- total_delay += config.walk_speed
-
- // A billion other things can slow you down, ask the mob
- total_delay += my_mob.movement_delay(n, direct)
-
// Confused direction randomization
if(my_mob.confused)
switch(my_mob.m_intent)
@@ -278,7 +264,7 @@
direct = turn(direct, pick(90, -90))
n = get_step(my_mob, direct)
- total_delay = TICKS2DS(-round(-(DS2TICKS(total_delay)))) //Rounded to the next tick in equivalent ds
+ total_delay = DS2NEARESTTICK(total_delay) //Rounded to the next tick in equivalent ds
my_mob.setMoveCooldown(total_delay)
. = my_mob.SelfMove(n, direct, total_delay)
diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm
index 43b562b27e..9949b3f836 100644
--- a/code/modules/mob/new_player/login.dm
+++ b/code/modules/mob/new_player/login.dm
@@ -11,7 +11,7 @@ var/obj/effect/lobby_image = new /obj/effect/lobby_image
/obj/effect/lobby_image/Initialize()
icon = using_map.lobby_icon
- var/known_icon_states = icon_states(icon)
+ var/known_icon_states = cached_icon_states(icon)
for(var/lobby_screen in using_map.lobby_screens)
if(!(lobby_screen in known_icon_states))
error("Lobby screen '[lobby_screen]' did not exist in the icon set [icon].")
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 314186936b..7c5b354d42 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -348,8 +348,11 @@
if(!job.is_position_available()) return 0
if(jobban_isbanned(src,rank)) return 0
if(!job.player_old_enough(src.client)) return 0
- if(!is_job_whitelisted(src,rank)) return 0 //VOREStation Code
- if(!job.player_has_enough_pto(src.client)) return 0 //VOREStation Code
+ //VOREStation Add
+ if(!job.player_has_enough_playtime(src.client)) return 0
+ if(!is_job_whitelisted(src,rank)) return 0
+ if(!job.player_has_enough_pto(src.client)) return 0
+ //VOREStation Add End
return 1
@@ -365,7 +368,7 @@
if(!IsJobAvailable(rank))
alert(src,"[rank] is not available. Please try another.")
return 0
- if(!attempt_vr(src,"spawn_checks_vr",list())) return 0 // VOREStation Insert
+ if(!spawn_checks_vr(rank)) return 0 // VOREStation Insert
if(!client)
return 0
@@ -391,10 +394,10 @@
character = job_master.EquipRank(character, rank, 1) //equips the human
UpdateFactionList(character)
- // AIs don't need a spawnpoint, they must spawn at an empty core
- if(character.mind.assigned_role == "AI")
+ var/datum/job/J = SSjob.get_job(rank)
- character = character.AIize(move=0) // AIize the character, but don't move them yet
+ // AIs don't need a spawnpoint, they must spawn at an empty core
+ if(J.mob_type & JOB_SILICON_AI)
// IsJobAvailable for AI checks that there is an empty core available in this list
var/obj/structure/AIcore/deactivated/C = empty_playable_ai_cores[1]
@@ -402,11 +405,14 @@
character.loc = C.loc
+ // AIize the character, but don't move them yet
+ character = character.AIize(move = FALSE) // Dupe of code in /datum/controller/subsystem/ticker/proc/create_characters() for non-latespawn, unify?
+
AnnounceCyborg(character, rank, "has been transferred to the empty core in \the [character.loc.loc]")
ticker.mode.latespawn(character)
- qdel(C)
- qdel(src)
+ qdel(C) //Deletes empty core (really?)
+ qdel(src) //Deletes new_player
return
// Equip our custom items only AFTER deploying to spawn points eh?
@@ -420,18 +426,15 @@
character.buckled.set_dir(character.dir)
ticker.mode.latespawn(character)
-
- if(character.mind.assigned_role != "Cyborg")
+
+ if(J.mob_type & JOB_SILICON)
+ AnnounceCyborg(character, rank, join_message, announce_channel, character.z)
+ else
+ AnnounceArrival(character, rank, join_message, announce_channel, character.z)
data_core.manifest_inject(character)
ticker.minds += character.mind//Cyborgs and AIs handle this in the transform proc. //TODO!!!!! ~Carn
-
- //Grab some data from the character prefs for use in random news procs.
-
- AnnounceArrival(character, rank, join_message, announce_channel, character.z)
- else
- AnnounceCyborg(character, rank, join_message, announce_channel, character.z)
-
- qdel(src)
+
+ qdel(src) // Delete new_player mob
/mob/new_player/proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message, var/channel, var/zlevel)
if (ticker.current_state == GAME_STATE_PLAYING)
@@ -491,7 +494,6 @@
/mob/new_player/proc/create_character(var/turf/T)
- if (!attempt_vr(src,"spawn_checks_vr",list())) return 0 // VOREStation Insert
spawning = 1
close_spawn_windows()
@@ -606,6 +608,12 @@
/mob/new_player/hear_say(var/list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null)
return
+/mob/new_player/hear_holopad_talk(list/message_pieces, var/verb = "says", var/mob/speaker = null)
+ return
+
+/mob/new_player/hear_holopad_talk(list/message_pieces, var/verb = "says", var/mob/speaker = null)
+ return
+
// Prevents lobby players from seeing emotes, even with ghosteyes
/mob/new_player/show_message(msg, type, alt, alt_type)
return
diff --git a/code/modules/mob/new_player/new_player_vr.dm b/code/modules/mob/new_player/new_player_vr.dm
index 711332e692..1c56e278f8 100644
--- a/code/modules/mob/new_player/new_player_vr.dm
+++ b/code/modules/mob/new_player/new_player_vr.dm
@@ -1,36 +1,41 @@
-/mob/new_player/proc/spawn_checks_vr()
+/mob/new_player/proc/spawn_checks_vr(var/rank)
var/pass = TRUE
+ var/datum/job/J = SSjob.get_job(rank)
+
+ if(!J)
+ log_debug("Couldn't find job: [rank] for spawn_checks_vr, panic-returning that it's fine to spawn.")
+ return TRUE
//No Flavor Text
- if (config.require_flavor && client && client.prefs && client.prefs.flavor_texts && !client.prefs.flavor_texts["general"])
+ if (config.require_flavor && !client?.prefs?.flavor_texts["general"] && !(J.mob_type & JOB_SILICON))
to_chat(src,"Please set your general flavor text to give a basic description of your character. Set it using the 'Set Flavor text' button on the 'General' tab in character setup, and choosing 'General' category.")
pass = FALSE
//No OOC notes
- if (config.allow_Metadata && client && client.prefs && (isnull(client.prefs.metadata) || length(client.prefs.metadata) < 15))
+ if (config.allow_Metadata && !(client?.prefs?.metadata || length(client.prefs.metadata) < 15))
to_chat(src,"Please set informative OOC notes related to ERP preferences. Set them using the 'OOC Notes' button on the 'General' tab in character setup.")
pass = FALSE
//Are they on the VERBOTEN LIST?
- if (prevent_respawns.Find(client.prefs.real_name))
+ if (prevent_respawns.Find(client?.prefs?.real_name))
to_chat(src,"You've already quit the round as this character. You can't go back now that you've free'd your job slot. Play another character, or wait for the next round.")
pass = FALSE
//Do they have their scale properly setup?
- if(!client.prefs.size_multiplier)
+ if(!client?.prefs?.size_multiplier)
pass = FALSE
to_chat(src,"You have not set your scale yet. Do this on the VORE tab in character setup.")
//Can they play?
- if(!is_alien_whitelisted(src,GLOB.all_species[client.prefs.species]) && !check_rights(R_ADMIN, 0))
+ if(!is_alien_whitelisted(src,GLOB.all_species[client?.prefs?.species]) && !check_rights(R_ADMIN, 0))
pass = FALSE
to_chat(src,"You are not allowed to spawn in as this species.")
//Custom species checks
- if (client && client.prefs && client.prefs.species == "Custom Species")
+ if (client?.prefs?.species == "Custom Species")
//Didn't name it
- if(!client.prefs.custom_species)
+ if(!client?.prefs?.custom_species)
pass = FALSE
to_chat(src,"You have to name your custom species. Do this on the VORE tab in character setup.")
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 6db108fa6f..7a20d0ee8e 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -152,8 +152,8 @@
/mob/proc/find_valid_prefixes(message)
var/list/prefixes = list() // [["Common", start, end], ["Gutter", start, end]]
for(var/i in 1 to length(message))
- // This grabs trimmed 3 character substrings, to allow for up to 1 prefix and 1 letter language keys
- var/selection = trim_right(copytext(message, i, i + 2)) // VOREStation Edit: We use uppercase keys to avoid Polaris key duplication, but this had lowertext() in it
+ // This grabs 3 character substrings, to allow for up to 1 prefix, 1 letter language key, and one post-key character to more strictly control where the language breaks happen
+ var/selection = trim_right(copytext(message, i, i + 3)) // VOREStation Edit: We use uppercase keys to avoid Polaris key duplication, but this had lowertext() in it
// The first character in the selection will always be the prefix (if this is a valid language invocation)
var/prefix = copytext(selection, 1, 2)
var/language_key = copytext(selection, 2, 3)
@@ -161,6 +161,18 @@
// Okay, we're definitely now trying to invoke a language (probably)
// This "[]" is probably unnecessary but BYOND will runtime if a number is used
var/datum/language/L = GLOB.language_keys["[language_key]"]
+
+ // MULTILINGUAL_SPACE enforces a space after the language key
+ if(client && (client.prefs.multilingual_mode == MULTILINGUAL_SPACE) && (text2ascii(copytext(selection, 3, 4)) != 32)) // If we're looking for a space and we don't find one
+ continue
+
+ // MULTILINGUAL_DOUBLE_DELIMITER enforces a delimiter (valid prefix) after the language key
+ if(client && (client.prefs.multilingual_mode == MULTILINGUAL_DOUBLE_DELIMITER) && !is_language_prefix(copytext(selection, 3, 4)))
+ continue
+
+ if(client && (client.prefs.multilingual_mode in list(MULTILINGUAL_DEFAULT)))
+ selection = copytext(selection, 1, 3) // These modes only use two characters, not three
+
// It's kinda silly that we have to check L != null and this isn't done for us by can_speak (it runtimes instead), but w/e
if(L && can_speak(L))
// So we have a valid language invocation, and we can speak that language, let's make a piece for it
@@ -174,6 +186,10 @@
// This covers the case of "no prefixes in use."
prefixes[++prefixes.len] = list(get_default_language(), i, i)
+ // If multilingualism is disabled, then after the first pass we're guaranteed to have either found a language key at the start, or else there isn't one and we're using the default for the whole message
+ if(client && (client.prefs.multilingual_mode == MULTILINGUAL_OFF))
+ break
+
return prefixes
/mob/proc/strip_prefixes(message, mob/prefixer = null)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 0e4e42bbeb..2607f6fbdd 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -41,11 +41,11 @@
return src
-/mob/new_player/AIize()
+/mob/new_player/AIize(var/move)
spawning = 1
return ..()
-/mob/living/carbon/human/AIize(move=1) // 'move' argument needs defining here too because BYOND is dumb
+/mob/living/carbon/human/AIize(var/move = TRUE) // 'move' argument needs defining here too because BYOND is dumb
if (transforming)
return
for(var/t in organs)
@@ -53,7 +53,7 @@
return ..(move)
-/mob/living/carbon/AIize()
+/mob/living/carbon/AIize(var/move)
if (transforming)
return
for(var/obj/item/W in src)
@@ -64,10 +64,34 @@
invisibility = 101
return ..()
-/mob/proc/AIize(move=1)
+/mob/proc/AIize(var/move = TRUE)
if(client)
src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // stop the jams for AIs
- var/mob/living/silicon/ai/O = new (loc, using_map.default_law_type,,1)//No MMI but safety is in effect.
+
+ var/newloc = loc
+ if(move)
+ var/obj/loc_landmark
+ for(var/obj/effect/landmark/start/sloc in landmarks_list)
+ if (sloc.name != "AI")
+ continue
+ if ((locate(/mob/living) in sloc.loc) || (locate(/obj/structure/AIcore) in sloc.loc))
+ continue
+ loc_landmark = sloc
+ if (!loc_landmark)
+ for(var/obj/effect/landmark/tripai in landmarks_list)
+ if (tripai.name == "tripai")
+ if((locate(/mob/living) in tripai.loc) || (locate(/obj/structure/AIcore) in tripai.loc))
+ continue
+ loc_landmark = tripai
+ if (!loc_landmark)
+ to_chat(src, "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone.")
+ for(var/obj/effect/landmark/start/sloc in landmarks_list)
+ if (sloc.name == "AI")
+ loc_landmark = sloc
+
+ newloc = loc_landmark.loc
+
+ var/mob/living/silicon/ai/O = new (newloc, using_map.default_law_type,,1)//No MMI but safety is in effect.
O.invisibility = 0
O.aiRestorePowerRoutine = 0
@@ -101,28 +125,6 @@
if(LANGUAGE_ROOTLOCAL in B.alternate_languages)
O.add_language(LANGUAGE_ROOTLOCAL, 1)
- if(move)
- var/obj/loc_landmark
- for(var/obj/effect/landmark/start/sloc in landmarks_list)
- if (sloc.name != "AI")
- continue
- if ((locate(/mob/living) in sloc.loc) || (locate(/obj/structure/AIcore) in sloc.loc))
- continue
- loc_landmark = sloc
- if (!loc_landmark)
- for(var/obj/effect/landmark/tripai in landmarks_list)
- if (tripai.name == "tripai")
- if((locate(/mob/living) in tripai.loc) || (locate(/obj/structure/AIcore) in tripai.loc))
- continue
- loc_landmark = tripai
- if (!loc_landmark)
- to_chat(O, "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone.")
- for(var/obj/effect/landmark/start/sloc in landmarks_list)
- if (sloc.name == "AI")
- loc_landmark = sloc
-
- O.loc = loc_landmark.loc
-
O.on_mob_init()
O.add_ai_verbs()
diff --git a/code/modules/overmap/ships/computers/ship.dm b/code/modules/overmap/ships/computers/ship.dm
index 6e6304f1f8..497077a76e 100644
--- a/code/modules/overmap/ships/computers/ship.dm
+++ b/code/modules/overmap/ships/computers/ship.dm
@@ -58,6 +58,7 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
/obj/machinery/computer/ship/proc/look(var/mob/user)
if(linked)
+ apply_visual(user)
user.reset_view(linked)
user.set_viewsize(world.view + extra_view)
GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
diff --git a/code/modules/overmap/spacetravel.dm b/code/modules/overmap/spacetravel.dm
index a51cfc3f6d..ac5846202a 100644
--- a/code/modules/overmap/spacetravel.dm
+++ b/code/modules/overmap/spacetravel.dm
@@ -63,11 +63,16 @@ proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A)
if (!M)
return
+ // Don't let AI eyes yeet themselves off the map
+ if(istype(A, /mob/observer/eye))
+ return
+
if(A.lost_in_space())
if(!QDELETED(A))
qdel(A)
return
+
var/nx = 1
var/ny = 1
var/nz = 1
diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm
index 4c927b376e..cbbe7eeb4e 100644
--- a/code/modules/paperwork/papershredder.dm
+++ b/code/modules/paperwork/papershredder.dm
@@ -25,14 +25,9 @@
/obj/item/weapon/paper_bundle = 3,
)
-/obj/machinery/papershredder/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- RefreshParts()
+/obj/machinery/papershredder/Initialize()
+ . = ..()
+ default_apply_parts()
update_icon()
/obj/machinery/papershredder/attackby(var/obj/item/W, var/mob/user)
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 6dcadea0a6..71a110b4bd 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -16,14 +16,9 @@
var/toner = 30 //how much toner is left! woooooo~
var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier!
-/obj/machinery/photocopier/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- RefreshParts()
+/obj/machinery/photocopier/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/photocopier/examine(mob/user as mob)
. = ..()
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index d7a6e0783f..91e73c4451 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -39,6 +39,10 @@
#define POWERCHAN_ON 2 // Power channel is on until there is no power
#define POWERCHAN_ON_AUTO 3 // Power channel is on until power drops below a threshold
+#define NIGHTSHIFT_AUTO 1
+#define NIGHTSHIFT_NEVER 2
+#define NIGHTSHIFT_ALWAYS 3
+
//NOTE: STUFF STOLEN FROM AIRLOCK.DM thx
/obj/machinery/power/apc/critical
@@ -121,6 +125,7 @@
var/alarms_hidden = FALSE //If power alarms from this APC are visible on consoles
var/nightshift_lights = FALSE
+ var/nightshift_setting = NIGHTSHIFT_AUTO
var/last_nightshift_switch = 0
/obj/machinery/power/apc/updateDialog()
@@ -801,6 +806,7 @@
"siliconUser" = issilicon(user) || isobserver(user), //I add observer here so admins can have more control, even if it makes 'siliconUser' seem inaccurate.
"emergencyLights" = !emergency_lights,
"nightshiftLights" = nightshift_lights,
+ "nightshiftSetting" = nightshift_setting,
"powerChannels" = list(
list(
@@ -921,11 +927,12 @@
return 1
if(href_list["nightshift"])
- if(last_nightshift_switch > world.time + 10 SECONDS) // don't spam...
+ if(last_nightshift_switch > world.time - 10 SECONDS) // don't spam...
to_chat(usr, "[src]'s night lighting circuit breaker is still cycling!")
return 0
last_nightshift_switch = world.time
- set_nightshift(!nightshift_lights)
+ nightshift_setting = text2num(href_list["nightshift"])
+ update_nightshift()
return 1
if(locked && !issilicon(usr) )
@@ -1382,8 +1389,19 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on)
if(automated && istype(area, /area/shuttle))
return
nightshift_lights = on
+ update_nightshift()
+
+/obj/machinery/power/apc/proc/update_nightshift()
+ var/new_state = nightshift_lights
+
+ switch(nightshift_setting)
+ if(NIGHTSHIFT_NEVER)
+ new_state = FALSE
+ if(NIGHTSHIFT_ALWAYS)
+ new_state = TRUE
+
for(var/obj/machinery/light/L in area)
- L.nightshift_mode(on)
+ L.nightshift_mode(new_state)
CHECK_TICK
#undef APC_UPDATE_ICON_COOLDOWN
diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm
index d6fe46fa2b..f6bc1c9ff6 100644
--- a/code/modules/power/batteryrack.dm
+++ b/code/modules/power/batteryrack.dm
@@ -40,7 +40,6 @@
component_parts += new /obj/item/weapon/stock_parts/capacitor/
component_parts += new /obj/item/weapon/stock_parts/matter_bin/ // Matter Bin: Max. amount of cells.
-
/obj/machinery/power/smes/batteryrack/RefreshParts()
var/capacitor_efficiency = 0
var/maxcells = 0
diff --git a/code/modules/power/debug_items.dm b/code/modules/power/debug_items.dm
index 6fee9cce22..c7ca43705b 100644
--- a/code/modules/power/debug_items.dm
+++ b/code/modules/power/debug_items.dm
@@ -8,20 +8,22 @@
/obj/machinery/power/debug_items/examine(mob/user)
. = ..()
if(show_extended_information)
- show_info(user)
+ . += show_info(user)
/obj/machinery/power/debug_items/proc/show_info(var/mob/user)
+ var/list/extra_info = list()
if(!powernet)
- to_chat(user, "This device is not connected to a powernet")
+ extra_info += "This device is not connected to a powernet"
return
- to_chat(user, "Connected to powernet: [powernet]")
- to_chat(user, "Available power: [num2text(powernet.avail, 20)] W")
- to_chat(user, "Load: [num2text(powernet.viewload, 20)] W")
- to_chat(user, "Has alert: [powernet.problem ? "YES" : "NO"]")
- to_chat(user, "Cables: [powernet.cables.len]")
- to_chat(user, "Nodes: [powernet.nodes.len]")
+ extra_info += "Connected to powernet: [powernet]"
+ extra_info += "Available power: [num2text(powernet.avail, 20)] W"
+ extra_info += "Load: [num2text(powernet.viewload, 20)] W"
+ extra_info += "Has alert: [powernet.problem ? "YES" : "NO"]"
+ extra_info += "Cables: [powernet.cables.len]"
+ extra_info += "Nodes: [powernet.nodes.len]"
+ return extra_info
// An infinite power generator. Adds energy to connected cable.
/obj/machinery/power/debug_items/infinite_generator
@@ -33,8 +35,8 @@
add_avail(power_generation_rate)
/obj/machinery/power/debug_items/infinite_generator/show_info(var/mob/user)
- ..()
- to_chat(user, "Generator is providing [num2text(power_generation_rate, 20)] W")
+ . = ..()
+ . += "Generator is providing [num2text(power_generation_rate, 20)] W"
// A cable powersink, without the explosion/network alarms normal powersink causes.
@@ -48,9 +50,9 @@
last_used = draw_power(power_usage_rate)
/obj/machinery/power/debug_items/infinite_cable_powersink/show_info(var/mob/user)
- ..()
- to_chat(user, "Power sink is demanding [num2text(power_usage_rate, 20)] W")
- to_chat(user, "[num2text(last_used, 20)] W was actually used last tick")
+ . = ..()
+ . += "Power sink is demanding [num2text(power_usage_rate, 20)] W"
+ . += "[num2text(last_used, 20)] W was actually used last tick"
/obj/machinery/power/debug_items/infinite_apc_powersink
@@ -60,6 +62,6 @@
active_power_usage = 0
/obj/machinery/power/debug_items/infinite_apc_powersink/show_info(var/mob/user)
- ..()
- to_chat(user, "Dummy load is using [num2text(active_power_usage, 20)] W")
- to_chat(user, "Powered: [powered() ? "YES" : "NO"]")
\ No newline at end of file
+ . = ..()
+ . += "Dummy load is using [num2text(active_power_usage, 20)] W"
+ . += "Powered: [powered() ? "YES" : "NO"]"
diff --git a/code/modules/power/grid_checker.dm b/code/modules/power/grid_checker.dm
index 93d4918af0..224eade429 100644
--- a/code/modules/power/grid_checker.dm
+++ b/code/modules/power/grid_checker.dm
@@ -15,17 +15,12 @@
var/wire_allow_manual_3 = FALSE
var/opened = FALSE
-/obj/machinery/power/grid_checker/New()
- ..()
+/obj/machinery/power/grid_checker/Initialize()
+ . = ..()
connect_to_network()
update_icon()
wires = new(src)
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/stack/cable_coil(src, 10)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/power/grid_checker/Destroy()
qdel(wires)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index c2f119dfb8..33331e82f6 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -901,7 +901,7 @@ var/global/list/light_type_cache = list()
var/brightness_color = LIGHT_COLOR_INCANDESCENT_TUBE
var/nightshift_range = 8
- var/nightshift_power = 0.7
+ var/nightshift_power = 1
var/nightshift_color = LIGHT_COLOR_NIGHTSHIFT
/obj/item/weapon/light/tube
@@ -921,7 +921,7 @@ var/global/list/light_type_cache = list()
brightness_power = 9
nightshift_range = 10
- nightshift_power = 0.9
+ nightshift_power = 1.5
/obj/item/weapon/light/bulb
name = "light bulb"
@@ -935,7 +935,7 @@ var/global/list/light_type_cache = list()
brightness_color = LIGHT_COLOR_INCANDESCENT_BULB
nightshift_range = 3
- nightshift_power = 0.35
+ nightshift_power = 0.5
/obj/item/weapon/light/throw_impact(atom/hit_atom)
..()
diff --git a/code/modules/power/pacman2.dm b/code/modules/power/pacman2.dm
index 33fb1fb97a..26a534e222 100644
--- a/code/modules/power/pacman2.dm
+++ b/code/modules/power/pacman2.dm
@@ -6,8 +6,8 @@
name = "Pacman II"
desc = "P.A.C.M.A.N. type II portable generator. Uses liquid phoron as a fuel source."
power_gen = 4500
+ circuit = /obj/item/weapon/circuitboard/pacman2
var/obj/item/weapon/tank/phoron/P = null
- var/board_path = "/obj/item/weapon/circuitboard/pacman2"
var/emagged = 0
var/heat = 0
/*
@@ -30,16 +30,9 @@
P.air_contents.phoron -= 0.01
return
- New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new board_path(src)
- RefreshParts()
+ Initialize()
+ . = ..()
+ default_apply_parts()
RefreshParts()
var/temp_rating = 0
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 852d4d5d0f..10b638121f 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -112,18 +112,10 @@
/obj/machinery/power/port_gen/pacman/Initialize()
. = ..()
+ default_apply_parts()
if(anchored)
connect_to_network()
-
-/obj/machinery/power/port_gen/pacman/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/stack/cable_coil(src, 2)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- RefreshParts()
-
+
/obj/machinery/power/port_gen/pacman/Destroy()
DropFuel()
return ..()
diff --git a/code/modules/power/singularity/act.dm b/code/modules/power/singularity/act.dm
index 5d33ee440e..9c3a5b8621 100644
--- a/code/modules/power/singularity/act.dm
+++ b/code/modules/power/singularity/act.dm
@@ -47,12 +47,19 @@
return 2
/obj/singularity_pull(S, current_size)
- if(simulated)
- if(anchored)
- if(current_size >= STAGE_FIVE)
- step_towards(src, S)
- else
- step_towards(src, S)
+ set waitfor = 0
+
+ if(anchored)
+ return
+
+ sleep(0) //this is needed or multiple items will be thrown sequentially and not simultaneously
+ if(current_size >= STAGE_FOUR)
+ step_towards(src,S)
+ sleep(1)
+ step_towards(src,S)
+ else if(current_size > STAGE_ONE)
+ step_towards(src,S)
+ else ..()
/obj/effect/beam/singularity_pull()
return
@@ -60,20 +67,6 @@
/obj/effect/overlay/singularity_pull()
return
-/obj/item/singularity_pull(S, current_size)
- spawn(0) //this is needed or multiple items will be thrown sequentially and not simultaneously
- if(current_size >= STAGE_FOUR)
- //throw_at(S, 14, 3)
- step_towards(src,S)
- sleep(1)
- step_towards(src,S)
- else if(current_size > STAGE_ONE)
- step_towards(src,S)
- else ..()
-
-/obj/machinery/atmospherics/pipe/singularity_pull()
- return
-
/obj/machinery/power/supermatter/shard/singularity_act()
qdel(src)
return 5000
@@ -113,30 +106,6 @@
ChangeTurf(get_base_turf_by_area(src))
return 2
-/turf/simulated/floor/singularity_pull(S, current_size)
- if(flooring && current_size >= STAGE_THREE)
- if(prob(current_size / 2))
- var/leave_tile = TRUE
- if(broken || burnt || flooring.flags & TURF_IS_FRAGILE)
- leave_tile = FALSE
- playsound(src, 'sound/items/crowbar.ogg', 50, 1)
- make_plating(leave_tile)
-
-/turf/simulated/wall/singularity_pull(S, current_size)
-
- if(!reinf_material)
- if(current_size >= STAGE_FIVE)
- if(prob(75))
- dismantle_wall()
- return
- if(current_size == STAGE_FOUR)
- if(prob(30))
- dismantle_wall()
- else
- if(current_size >= STAGE_FIVE)
- if(prob(30))
- dismantle_wall()
-
/turf/space/singularity_act()
return
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index 2ec394bc1f..10424cee18 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -459,17 +459,17 @@
take_damage(250 / severity)
/obj/machinery/power/smes/examine(var/mob/user)
- ..()
- to_chat(user, "The service hatch is [panel_open ? "open" : "closed"].")
+ . = ..()
+ . += "The service hatch is [panel_open ? "open" : "closed"]."
if(!damage)
return
var/damage_percentage = round((damage / maxdamage) * 100)
switch(damage_percentage)
if(75 to INFINITY)
- to_chat(user, "It's casing is severely damaged, and sparking circuitry may be seen through the holes!")
+ . += "It's casing is severely damaged, and sparking circuitry may be seen through the holes!"
if(50 to 74)
- to_chat(user, "It's casing is considerably damaged, and some of the internal circuits appear to be exposed!")
+ . += "It's casing is considerably damaged, and some of the internal circuits appear to be exposed!"
if(25 to 49)
- to_chat(user, "It's casing is quite seriously damaged.")
+ . += "It's casing is quite seriously damaged."
if(0 to 24)
- to_chat(user, "It's casing has some minor damage.")
\ No newline at end of file
+ . += "It's casing has some minor damage."
\ No newline at end of file
diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm
index aadcc41ec4..558e879a87 100644
--- a/code/modules/power/smes_construction.dm
+++ b/code/modules/power/smes_construction.dm
@@ -41,23 +41,23 @@
// These are used on individual outposts as backup should power line be cut, or engineering outpost lost power.
// 1M Charge, 150K I/O
-/obj/machinery/power/smes/buildable/outpost_substation/New()
- ..(0)
+/obj/machinery/power/smes/buildable/outpost_substation/Initialize()
+ . = ..()
component_parts += new /obj/item/weapon/smes_coil/weak(src)
recalc_coils()
// This one is pre-installed on engineering shuttle. Allows rapid charging/discharging for easier transport of power to outpost
// 11M Charge, 2.5M I/O
-/obj/machinery/power/smes/buildable/power_shuttle/New()
- ..(0)
+/obj/machinery/power/smes/buildable/power_shuttle/Initialize()
+ . = ..()
component_parts += new /obj/item/weapon/smes_coil/super_io(src)
component_parts += new /obj/item/weapon/smes_coil/super_io(src)
component_parts += new /obj/item/weapon/smes_coil(src)
recalc_coils()
// Pre-installed and pre-charged SMES hidden from the station, for use in submaps.
-/obj/machinery/power/smes/buildable/point_of_interest/New()
- ..(1)
+/obj/machinery/power/smes/buildable/point_of_interest/Initialize()
+ . = ..()
charge = 1e7 // Should be enough for an individual POI.
RCon = FALSE
input_level = input_level_max
@@ -119,7 +119,8 @@
// Proc: New()
// Parameters: None
// Description: Adds standard components for this SMES, and forces recalculation of properties.
-/obj/machinery/power/smes/buildable/New(var/install_coils = 1)
+/obj/machinery/power/smes/buildable/Initialize(var/install_coils = 1)
+ . = ..()
component_parts = list()
component_parts += new /obj/item/stack/cable_coil(src,30)
wires = new /datum/wires/smes(src)
@@ -129,7 +130,6 @@
for(var/i = 1, i <= cur_coils, i++)
component_parts += new /obj/item/weapon/smes_coil(src)
recalc_coils()
- ..()
// Proc: attack_hand()
// Parameters: None
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index b89b906e8a..621cdcba0b 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -25,11 +25,21 @@
// Base variants are applied to everyone on the same Z level
// Range variants are applied on per-range basis: numbers here are on point blank, it scales with the map size (assumes square shaped Z levels)
-#define DETONATION_RADS 20
-#define DETONATION_HALLUCINATION_BASE 300
-#define DETONATION_HALLUCINATION_RANGE 300
-#define DETONATION_HALLUCINATION 600
+#define DETONATION_RADS 40
+#define DETONATION_MOB_CONCUSSION 4 // Value that will be used for Weaken() for mobs.
+// Base amount of ticks for which a specific type of machine will be offline for. +- 20% added by RNG.
+// This does pretty much the same thing as an electrical storm, it just affects the whole Z level instantly.
+#define DETONATION_APC_OVERLOAD_PROB 10 // prob() of overloading an APC's lights.
+#define DETONATION_SHUTDOWN_APC 120 // Regular APC.
+#define DETONATION_SHUTDOWN_CRITAPC 10 // Critical APC. AI core and such. Considerably shorter as we don't want to kill the AI with a single blast. Still a nuisance.
+#define DETONATION_SHUTDOWN_SMES 60 // SMES
+#define DETONATION_SHUTDOWN_RNG_FACTOR 20 // RNG factor. Above shutdown times can be +- X%, where this setting is the percent. Do not set to 100 or more.
+#define DETONATION_SOLAR_BREAK_CHANCE 60 // prob() of breaking solar arrays (this is per-panel, and only affects the Z level SM is on)
+
+// If power level is between these two, explosion strength will be scaled accordingly between min_explosion_power and max_explosion_power
+#define DETONATION_EXPLODE_MIN_POWER 200 // If power level is this or lower, minimal detonation strength will be used
+#define DETONATION_EXPLODE_MAX_POWER 2000 // If power level is this or higher maximal detonation strength will be used
#define WARNING_DELAY 20 //seconds between warnings.
@@ -65,7 +75,8 @@
var/pull_radius = 14
// Time in ticks between delamination ('exploding') and exploding (as in the actual boom)
var/pull_time = 100
- var/explosion_power = 8
+ var/min_explosion_power = 8
+ var/max_explosion_power = 16
var/emergency_issued = 0
@@ -142,29 +153,71 @@
/obj/machinery/power/supermatter/proc/explode()
+
+ set waitfor = 0
+
message_admins("Supermatter exploded at ([x],[y],[z] - JMP)",0,1)
log_game("SUPERMATTER([x],[y],[z]) Exploded. Power:[power], Oxygen:[oxygen], Damage:[damage], Integrity:[get_integrity()]")
anchored = 1
grav_pulling = 1
exploded = 1
- var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, mecha, or other container shouldn't block it's effects that way.
- if(!TS)
+ sleep(pull_time)
+ var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, exosuit, or other container shouldn't block it's effects that way.
+ if(!istype(TS))
return
- for(var/z in GetConnectedZlevels(TS.z))
+
+ var/list/affected_z = GetConnectedZlevels(TS.z)
+
+ // Effect 1: Radiation, weakening to all mobs on Z level
+ for(var/z in affected_z)
SSradiation.z_radiate(locate(1, 1, z), DETONATION_RADS, 1)
+
for(var/mob/living/mob in living_mob_list)
- var/turf/T = get_turf(mob)
- if(T && (loc.z == T.z))
- if(istype(mob, /mob/living/carbon/human))
- //Hilariously enough, running into a closet should make you get hit the hardest.
- var/mob/living/carbon/human/H = mob
- H.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) )
- spawn(pull_time)
- explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1)
- spawn(5) //to allow the explosion to finish
- new /obj/item/broken_sm(TS)
+ var/turf/TM = get_turf(mob)
+ if(!TM)
+ continue
+ if(!(TM.z in affected_z))
+ continue
+
+ mob.Weaken(DETONATION_MOB_CONCUSSION)
+ to_chat(mob, "An invisible force slams you against the ground!")
+
+ // Effect 2: Z-level wide electrical pulse
+ for(var/obj/machinery/power/apc/A in machines)
+ if(!(A.z in affected_z))
+ continue
+
+ // Overloads lights
+ if(prob(DETONATION_APC_OVERLOAD_PROB))
+ A.overload_lighting()
+ // Causes the APCs to go into system failure mode.
+ var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100
+ if(A.is_critical)
+ A.energy_fail(round(DETONATION_SHUTDOWN_CRITAPC * random_change))
+ else
+ A.energy_fail(round(DETONATION_SHUTDOWN_APC * random_change))
+
+ // Effect 3: Break solar arrays
+ for(var/obj/machinery/power/solar/S in machines)
+ if(!(S.z in affected_z))
+ continue
+ if(prob(DETONATION_SOLAR_BREAK_CHANCE))
+ S.health = -1
+ S.broken()
+
+ // Effect 4: Medium scale explosion
+ spawn(0)
+ var/explosion_power = min_explosion_power
+ if(power > 0)
+ // 0-100% where 0% is at DETONATION_EXPLODE_MIN_POWER or lower and 100% is at DETONATION_EXPLODE_MAX_POWER or higher
+ var/strength_percentage = between(0, (power - DETONATION_EXPLODE_MIN_POWER) / ((DETONATION_EXPLODE_MAX_POWER - DETONATION_EXPLODE_MIN_POWER) / 100), 100)
+ explosion_power = between(min_explosion_power, (((max_explosion_power - min_explosion_power) * (strength_percentage / 100)) + min_explosion_power), max_explosion_power)
+
+ explosion(TS, explosion_power/2, explosion_power, max_explosion_power, explosion_power * 4, 1)
qdel(src)
- return
+ // Allow the explosion to finish
+ spawn(5)
+ new /obj/item/broken_sm(TS)
//Changes color and luminosity of the light to these values if they were not already set
/obj/machinery/power/supermatter/proc/shift_light(var/lum, var/clr)
@@ -212,20 +265,6 @@
global_announcer.autosay(alert_msg, "Supermatter Monitor")
public_alert = 0
-
-/obj/machinery/power/supermatter/get_transit_zlevel()
- //don't send it back to the station -- most of the time
- if(prob(99))
- var/list/candidates = using_map.accessible_z_levels.Copy()
- for(var/zlevel in using_map.station_levels)
- candidates.Remove("[zlevel]")
- candidates.Remove("[src.z]")
-
- if(candidates.len)
- return text2num(pickweight(candidates))
-
- return ..()
-
/obj/machinery/power/supermatter/process()
var/turf/L = loc
@@ -460,7 +499,8 @@
pull_radius = 5
pull_time = 45
- explosion_power = 3
+ min_explosion_power = 3
+ max_explosion_power = 6
/obj/machinery/power/supermatter/shard/announce_warning() //Shards don't get announcements
return
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index b07cacd92b..01f4e6003a 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -201,7 +201,7 @@
/proc/magazine_icondata_cache_add(var/obj/item/ammo_magazine/M)
var/list/icon_keys = list()
var/list/ammo_states = list()
- var/list/states = icon_states(M.icon)
+ var/list/states = cached_icon_states(M.icon)
for(var/i = 0, i <= M.max_ammo, i++)
var/ammo_state = "[M.icon_state]-[i]"
if(ammo_state in states)
diff --git a/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon.dm b/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon.dm
index cc8240b9af..4c40da9721 100644
--- a/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon.dm
+++ b/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon.dm
@@ -20,6 +20,7 @@
icon_override = 'icons/vore/custom_guns_vr.dmi'
item_state = "multicannon"
slot_flags = SLOT_BACK
+ recoil = FALSE
/obj/item/weapon/gun/projectile/multi_cannon/update_icon()
. = ..()
diff --git a/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon_cells.dm b/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon_cells.dm
index 3df1ef5022..53dd7c0ad3 100644
--- a/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon_cells.dm
+++ b/code/modules/projectiles/guns/energy/cell_loaded_vr/multi_cannon_cells.dm
@@ -11,7 +11,7 @@
var/charge
var/max_charge = 10
var/ticks = 1
- var/ticks_to_charge = 5 //10 secs per shot charged
+ var/ticks_to_charge = 15 //10 secs per shot charged
/obj/item/ammo_casing/macrobattery/Initialize(mapload, ...)
. = ..()
@@ -77,7 +77,7 @@
name = "Macrobattery - LETHAL"
icon_state = "macrobat_ouchie"
bat_colour = "#cc3300"
- projectile_type = /obj/item/projectile/beam
+ projectile_type = /obj/item/projectile/beam/heavylaser/lessheavy
/obj/item/ammo_casing/macrobattery/healie
name = "Macrobattery - RESTORE"
@@ -97,4 +97,8 @@
target.adjustToxLoss(-15)
target.radiation = max(target.radiation - 75, 0) //worse than mlem for rad, better for tox.
else
- return 1
\ No newline at end of file
+ return 1
+
+/obj/item/projectile/beam/heavylaser/lessheavy //all bark. no (or little) bite.
+ damage = 15
+ fire_sound = 'sound/weapons/Gunshot_cannon.ogg'
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index 230bfb4bab..181514ef0c 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -365,14 +365,10 @@
/obj/item/stack/material/glass/phoronglass = list("platinum", "silicon", "silicon", "silicon"), //5 platinum, 15 silicon,
)
-/obj/machinery/reagentgrinder/New()
- ..()
+/obj/machinery/reagentgrinder/Initialize()
+ . = ..()
beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- RefreshParts()
- return
+ default_apply_parts()
/obj/machinery/reagentgrinder/update_icon()
icon_state = "juicer"+num2text(!isnull(beaker))
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index 4cc755d158..91b04cf494 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -38,13 +38,7 @@
operating = FORWARDS
setmove()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/weapon/stock_parts/gear(src)
- component_parts += new /obj/item/weapon/stock_parts/motor(src)
- component_parts += new /obj/item/stack/cable_coil(src,5)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/conveyor/proc/setmove()
if(operating == FORWARDS)
diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm
index f9ff3adb51..468c7ff6bb 100644
--- a/code/modules/research/circuitprinter.dm
+++ b/code/modules/research/circuitprinter.dm
@@ -26,12 +26,7 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid).
/obj/machinery/r_n_d/circuit_imprinter/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/r_n_d/circuit_imprinter/process()
..()
diff --git a/code/modules/research/designs/misc.dm b/code/modules/research/designs/misc.dm
index 8faf037136..2ce34f3485 100644
--- a/code/modules/research/designs/misc.dm
+++ b/code/modules/research/designs/misc.dm
@@ -63,3 +63,12 @@ datum/design/item/general/laserpointer
materials = list(DEFAULT_WALL_MATERIAL = 500)
build_path = /obj/item/weapon/storage/box/syndie_kit/chameleon
sort_string = "TBAAB"
+
+/datum/design/item/general/bsflare
+ name = "bluespace flare"
+ desc = "A marker that can be detected by shuttle landing systems."
+ id = "bsflare"
+ req_tech = list(TECH_DATA = 3, TECH_BLUESPACE = 4)
+ materials = list(DEFAULT_WALL_MATERIAL = 4000, MAT_GLASS = 2000, MAT_SILVER = 2000)
+ build_path = /obj/item/device/spaceflare
+ sort_string = "TBAAC"
diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm
index a17bf370bf..78d8f9d323 100644
--- a/code/modules/research/destructive_analyzer.dm
+++ b/code/modules/research/destructive_analyzer.dm
@@ -16,13 +16,9 @@ Note: Must be placed within 3 tiles of the R&D Console
idle_power_usage = 30
active_power_usage = 2500
-/obj/machinery/r_n_d/destructive_analyzer/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- RefreshParts()
+/obj/machinery/r_n_d/destructive_analyzer/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/r_n_d/destructive_analyzer/RefreshParts()
var/T = 0
diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm
index 1de0d5bed0..b2c7362d2e 100644
--- a/code/modules/research/protolathe.dm
+++ b/code/modules/research/protolathe.dm
@@ -40,14 +40,7 @@
/obj/machinery/r_n_d/protolathe/Initialize()
. = ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/r_n_d/protolathe/process()
..()
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index a1bc577bb8..4776646105 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -15,13 +15,9 @@
req_access = list(access_rd) //Only the R&D can change server settings.
circuit = /obj/item/weapon/circuitboard/rdserver
-/obj/machinery/r_n_d/server/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- RefreshParts()
+/obj/machinery/r_n_d/server/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/r_n_d/server/Destroy()
griefProtection()
diff --git a/code/modules/resleeving/computers.dm b/code/modules/resleeving/computers.dm
index 20457c98fc..d8c51a7030 100644
--- a/code/modules/resleeving/computers.dm
+++ b/code/modules/resleeving/computers.dm
@@ -356,7 +356,7 @@
//Body to sleeve into, but mind is in another living body.
if(active_mr.mind_ref.current && active_mr.mind_ref.current.stat < DEAD) //Mind is in a body already that's alive
- var/answer = alert(active_mr.mind_ref.current,"Someone is attempting to restore a backup of your mind. Do you want to abandon this body, and move there? You MAY suffer memory loss! (Same rules as CMD apply)","Resleeving","Yes","No")
+ var/answer = alert(active_mr.mind_ref.current,"Someone is attempting to restore a backup of your mind. Do you want to abandon this body, and move there? You MAY suffer memory loss! (Same rules as CMD apply)","Resleeving","No","Yes")
//They declined to be moved.
if(answer == "No")
diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm
index 7e393c99d1..a062d2a3d3 100644
--- a/code/modules/shuttles/shuttle.dm
+++ b/code/modules/shuttles/shuttle.dm
@@ -30,6 +30,8 @@
var/tmp/depart_time = 0 //Similar to above, set when the shuttle leaves when long jumping. Used for progress bars.
+ var/debug_logging = FALSE // If set to true, the shuttle will start broadcasting its debug messages to admins
+
// Future Thoughts: Baystation put "docking" stuff in a subtype, leaving base type pure and free of docking stuff. Is this best?
/datum/shuttle/New(_name, var/obj/effect/shuttle_landmark/initial_location)
@@ -52,7 +54,8 @@
else
current_location = SSshuttles.get_landmark(current_location)
if(!istype(current_location))
- log_debug("UM whoops, no initial? [src]")
+ if(debug_logging)
+ log_shuttle("UM whoops, no initial? [src]")
CRASH("Shuttle '[name]' could not find its starting location landmark [current_location].")
if(src.name in SSshuttles.shuttles)
@@ -239,14 +242,17 @@
// Returns TRUE if we actually moved, otherwise FALSE.
/datum/shuttle/proc/attempt_move(var/obj/effect/shuttle_landmark/destination, var/interim = FALSE)
if(current_location == destination)
- log_shuttle("Shuttle [src] attempted to move to [destination] but is already there!")
+ if(debug_logging)
+ log_shuttle("Shuttle [src] attempted to move to [destination] but is already there!")
return FALSE
if(!destination.is_valid(src))
- log_shuttle("Shuttle [src] aborting attempt_move() because destination=[destination] is not valid")
+ if(debug_logging)
+ log_shuttle("Shuttle [src] aborting attempt_move() because destination=[destination] is not valid")
return FALSE
if(current_location.cannot_depart(src))
- log_shuttle("Shuttle [src] aborting attempt_move() because current_location=[current_location] refuses.")
+ if(debug_logging)
+ log_shuttle("Shuttle [src] aborting attempt_move() because current_location=[current_location] refuses.")
return FALSE
// Observer pattern pre-move
@@ -254,19 +260,21 @@
GLOB.shuttle_pre_move_event.raise_event(src, old_location, destination)
current_location.shuttle_departed(src)
- log_shuttle("[src] moving to [destination]. Areas are [english_list(shuttle_area)]")
+ if(debug_logging)
+ log_shuttle("[src] moving to [destination]. Areas are [english_list(shuttle_area)]")
var/list/translation = list()
for(var/area/A in shuttle_area)
- log_shuttle("Translating [A]")
+ if(debug_logging)
+ log_shuttle("Translating [A]")
translation += get_turf_translation(get_turf(current_location), get_turf(destination), A.contents)
// Actually do it! (This never fails)
perform_shuttle_move(destination, translation)
-
+
// Observer pattern post-move
destination.shuttle_arrived(src)
GLOB.shuttle_moved_event.raise_event(src, old_location, destination)
-
+
return TRUE
@@ -274,7 +282,8 @@
//A note to anyone overriding move in a subtype. perform_shuttle_move() must absolutely not, under any circumstances, fail to move the shuttle.
//If you want to conditionally cancel shuttle launches, that logic must go in short_jump() or long_jump()
/datum/shuttle/proc/perform_shuttle_move(var/obj/effect/shuttle_landmark/destination, var/list/turf_translation)
- log_shuttle("perform_shuttle_move() current=[current_location] destination=[destination]")
+ if(debug_logging)
+ log_shuttle("perform_shuttle_move() current=[current_location] destination=[destination]")
//to_world("move_shuttle() called for [name] leaving [origin] en route to [destination].")
//to_world("area_coming_from: [origin]")
diff --git a/code/modules/shuttles/shuttle_autodock.dm b/code/modules/shuttles/shuttle_autodock.dm
index 4181af5b15..aa59856b50 100644
--- a/code/modules/shuttles/shuttle_autodock.dm
+++ b/code/modules/shuttles/shuttle_autodock.dm
@@ -65,7 +65,7 @@
current_dock_target = docking_controller_tag
shuttle_docking_controller = SSshuttles.docking_registry[current_dock_target]
if(current_dock_target && !shuttle_docking_controller)
- to_world("warning: shuttle [src] can't find its controller with tag [current_dock_target]!")
+ log_shuttle("warning: shuttle [src] can't find its controller with tag [current_dock_target]!") // No toggle because this is an error message that needs to be seen
/*
Docking stuff
*/
diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm
index 6d277edec1..3e3655ca5a 100644
--- a/code/modules/shuttles/shuttle_console.dm
+++ b/code/modules/shuttles/shuttle_console.dm
@@ -64,11 +64,13 @@
var/cannot_depart = shuttle.current_location.cannot_depart(shuttle)
if(cannot_depart)
to_chat(user, "[cannot_depart]")
- log_shuttle("Shuttle [shuttle] cannot depart [shuttle.current_location] because: [cannot_depart].")
+ if(shuttle.debug_logging)
+ log_shuttle("Shuttle [shuttle] cannot depart [shuttle.current_location] because: [cannot_depart].")
return FALSE
if(!shuttle.next_location.is_valid(shuttle))
to_chat(user, "Destination zone is invalid or obstructed.")
- log_shuttle("Shuttle [shuttle] destination [shuttle.next_location] is invalid.")
+ if(shuttle.debug_logging)
+ log_shuttle("Shuttle [shuttle] destination [shuttle.next_location] is invalid.")
return FALSE
return TRUE
diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm
index efb321e55c..6c584e1762 100644
--- a/code/modules/shuttles/shuttle_emergency.dm
+++ b/code/modules/shuttles/shuttle_emergency.dm
@@ -70,7 +70,7 @@
if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console
if (emergency_shuttle.autopilot)
emergency_shuttle.autopilot = 0
- to_chat(world, "Alert: The shuttle autopilot has been overridden. Launch sequence initiated!")
+ to_world("Alert: The shuttle autopilot has been overridden. Launch sequence initiated!")
if(usr)
log_admin("[key_name(usr)] has overridden the departure shuttle's autopilot and activated the launch sequence.")
@@ -84,7 +84,7 @@
if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console
if (emergency_shuttle.autopilot)
emergency_shuttle.autopilot = 0
- to_chat(world, "Alert: The shuttle autopilot has been overridden. Bluespace drive engaged!")
+ to_world("Alert: The shuttle autopilot has been overridden. Bluespace drive engaged!")
if(usr)
log_admin("[key_name(usr)] has overridden the departure shuttle's autopilot and forced immediate launch.")
diff --git a/code/modules/shuttles/shuttles_web.dm b/code/modules/shuttles/shuttles_web.dm
index 0aebd2bf42..00d9344b00 100644
--- a/code/modules/shuttles/shuttles_web.dm
+++ b/code/modules/shuttles/shuttles_web.dm
@@ -181,7 +181,7 @@
my_doors[find_doors[A.id_tag]] = A
find_doors -= A.id_tag
for(var/lost in find_doors)
- log_debug("[my_area] shuttle computer couldn't find [lost] door!")
+ log_shuttle("[my_area] shuttle computer couldn't find [lost] door!")
if(my_sensors)
var/list/find_sensors = my_sensors
@@ -191,7 +191,7 @@
my_sensors[find_sensors[S.id_tag]] = S
find_sensors -= S.id_tag
for(var/lost in find_sensors)
- log_debug("[my_area] shuttle computer couldn't find [lost] sensor!")
+ log_shuttle("[my_area] shuttle computer couldn't find [lost] sensor!")
/obj/machinery/computer/shuttle_control/web/attackby(obj/I, mob/user)
var/datum/shuttle/autodock/web_shuttle/shuttle = shuttle_controller.shuttles[shuttle_tag]
diff --git a/code/modules/shuttles/web_datums.dm b/code/modules/shuttles/web_datums.dm
index 3e2abf9443..bbba42dd58 100644
--- a/code/modules/shuttles/web_datums.dm
+++ b/code/modules/shuttles/web_datums.dm
@@ -72,7 +72,7 @@
/datum/shuttle_destination/New(var/new_master)
my_landmark = SSshuttles.get_landmark(my_landmark)
if(!my_landmark)
- log_debug("Web shuttle destination '[name]' could not find its landmark '[my_landmark]'.")
+ log_debug("Web shuttle destination '[name]' could not find its landmark '[my_landmark]'.") // Important error message
master = new_master
/datum/shuttle_destination/Destroy()
diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm
index f853e224fc..249c84be73 100644
--- a/code/modules/tables/tables.dm
+++ b/code/modules/tables/tables.dm
@@ -30,6 +30,9 @@ var/list/table_icon_cache = list()
var/item_place = 1 //allows items to be placed on the table, but not on benches.
+/obj/structure/table/examine_icon()
+ return icon(icon=initial(icon), icon_state=initial(icon_state)) //Basically the map preview version
+
/obj/structure/table/proc/update_material()
var/old_maxhealth = maxhealth
if(!material)
diff --git a/code/modules/tgs/core/_definitions.dm b/code/modules/tgs/core/_definitions.dm
new file mode 100644
index 0000000000..ebf6d17c2a
--- /dev/null
+++ b/code/modules/tgs/core/_definitions.dm
@@ -0,0 +1,2 @@
+#define TGS_UNIMPLEMENTED "___unimplemented"
+#define TGS_VERSION_PARAMETER "server_service_version"
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
new file mode 100644
index 0000000000..144f33926f
--- /dev/null
+++ b/code/modules/tgs/core/core.dm
@@ -0,0 +1,171 @@
+/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
+ var/current_api = TGS_READ_GLOBAL(tgs)
+ if(current_api)
+ TGS_ERROR_LOG("TgsNew(): TGS API datum already set ([current_api])! Was TgsNew() called more than once?")
+ return
+
+#ifdef TGS_V3_API
+ minimum_required_security_level = TGS_SECURITY_TRUSTED
+#endif
+ var/raw_parameter = world.params[TGS_VERSION_PARAMETER]
+ if(!raw_parameter)
+ return
+
+ var/datum/tgs_version/version = new(raw_parameter)
+ if(!version.Valid(FALSE))
+ TGS_ERROR_LOG("Failed to validate TGS version parameter: [raw_parameter]!")
+ return
+
+ var/api_datum
+ switch(version.suite)
+ if(3)
+#ifndef TGS_V3_API
+ TGS_ERROR_LOG("Detected V3 API but TGS_V3_API isn't defined!")
+#else
+ switch(version.minor)
+ if(2)
+ api_datum = /datum/tgs_api/v3210
+#endif
+ if(4)
+ switch(version.minor)
+ if(0)
+ api_datum = /datum/tgs_api/v4
+ if(5)
+ api_datum = /datum/tgs_api/v5
+
+ var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion();
+ if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter)
+ TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.")
+ api_datum = /datum/tgs_api/latest
+
+ if(!api_datum)
+ TGS_ERROR_LOG("Found unsupported API version: [raw_parameter]. If this is a valid version please report this, backporting is done on demand.")
+ return
+
+ TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]")
+ var/datum/tgs_api/new_api = new api_datum(version)
+
+ TGS_WRITE_GLOBAL(tgs, new_api)
+
+ var/result = new_api.OnWorldNew(event_handler, minimum_required_security_level)
+ if(!result || result == TGS_UNIMPLEMENTED)
+ TGS_WRITE_GLOBAL(tgs, null)
+ TGS_ERROR_LOG("Failed to activate API!")
+
+/world/TgsMaximumAPIVersion()
+ return new /datum/tgs_version("5.x.x")
+
+/world/TgsMinimumAPIVersion()
+ return new /datum/tgs_version("3.2.x")
+
+/world/TgsInitializationComplete()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.OnInitializationComplete()
+
+/world/proc/TgsTopic(T)
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ var/result = api.OnTopic(T)
+ if(result != TGS_UNIMPLEMENTED)
+ return result
+
+/world/TgsRevision()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ var/result = api.Revision()
+ if(result != TGS_UNIMPLEMENTED)
+ return result
+
+/world/TgsReboot()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.OnReboot()
+
+/world/TgsAvailable()
+ return TGS_READ_GLOBAL(tgs) != null
+
+/world/TgsVersion()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ return api.version
+
+/world/TgsApiVersion()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ return api.ApiVersion()
+
+/world/TgsInstanceName()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ var/result = api.InstanceName()
+ if(result != TGS_UNIMPLEMENTED)
+ return result
+
+/world/TgsTestMerges()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ var/result = api.TestMerges()
+ if(result != TGS_UNIMPLEMENTED)
+ return result
+ return list()
+
+/world/TgsEndProcess()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.EndProcess()
+
+/world/TgsChatChannelInfo()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ var/result = api.ChatChannelInfo()
+ if(result != TGS_UNIMPLEMENTED)
+ return result
+ return list()
+
+/world/TgsChatBroadcast(message, list/channels)
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.ChatBroadcast(message, channels)
+
+/world/TgsTargetedChatBroadcast(message, admin_only)
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.ChatTargetedBroadcast(message, admin_only)
+
+/world/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.ChatPrivateMessage(message, user)
+
+/world/TgsSecurityLevel()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ api.SecurityLevel()
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
new file mode 100644
index 0000000000..3adecbb556
--- /dev/null
+++ b/code/modules/tgs/core/datum.dm
@@ -0,0 +1,82 @@
+TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
+
+/datum/tgs_api
+ var/datum/tgs_version/version
+
+/datum/tgs_api/New(datum/tgs_version/version)
+ . = ..()
+ src.version = version
+
+/datum/tgs_api/latest
+ parent_type = /datum/tgs_api/v5
+
+TGS_PROTECT_DATUM(/datum/tgs_api)
+
+/datum/tgs_api/proc/ApiVersion()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/OnWorldNew(datum/tgs_event_handler/event_handler)
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/OnInitializationComplete()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/OnTopic(T)
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/OnReboot()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/InstanceName()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/TestMerges()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/EndProcess()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/Revision()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/ChatChannelInfo()
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/ChatBroadcast(message, list/channels)
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/ChatTargetedBroadcast(message, admin_only)
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/ChatPrivateMessage(message, admin_only)
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/SecurityLevel()
+ return TGS_UNIMPLEMENTED
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/core/tgs_version.dm b/code/modules/tgs/core/tgs_version.dm
new file mode 100644
index 0000000000..a5dae1241a
--- /dev/null
+++ b/code/modules/tgs/core/tgs_version.dm
@@ -0,0 +1,28 @@
+/datum/tgs_version/New(raw_parameter)
+ src.raw_parameter = raw_parameter
+ deprefixed_parameter = replacetext(raw_parameter, "/tg/station 13 Server v", "")
+ var/list/version_bits = splittext(deprefixed_parameter, ".")
+
+ suite = text2num(version_bits[1])
+ if(version_bits.len > 1)
+ minor = text2num(version_bits[2])
+ if(version_bits.len > 2)
+ patch = text2num(version_bits[3])
+ if(version_bits.len == 4)
+ deprecated_patch = text2num(version_bits[4])
+
+/datum/tgs_version/proc/Valid(allow_wildcards = FALSE)
+ if(suite == null)
+ return FALSE
+ if(allow_wildcards)
+ return TRUE
+ return !Wildcard()
+
+/datum/tgs_version/Wildcard()
+ return minor == null || patch == null
+
+/datum/tgs_version/Equals(datum/tgs_version/other_version)
+ if(!istype(other_version))
+ return FALSE
+
+ return suite == other_version.suite && minor == other_version.minor && patch == other_version.patch && deprecated_patch == other_version.deprecated_patch
diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm
new file mode 100644
index 0000000000..764adbc3a9
--- /dev/null
+++ b/code/modules/tgs/includes.dm
@@ -0,0 +1,45 @@
+#include "core\_definitions.dm"
+#include "core\core.dm"
+#include "core\datum.dm"
+#include "core\tgs_version.dm"
+
+#ifdef TGS_V3_API
+#include "v3210\api.dm"
+#include "v3210\commands.dm"
+#endif
+
+#include "v4\api.dm"
+#include "v4\commands.dm"
+
+#include "v5\_defines.dm"
+#include "v5\api.dm"
+#include "v5\commands.dm"
+#include "v5\chat_commands.dm"
+#include "v5\undef.dm"
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm
new file mode 100644
index 0000000000..5327b9276b
--- /dev/null
+++ b/code/modules/tgs/v3210/api.dm
@@ -0,0 +1,255 @@
+#define REBOOT_MODE_NORMAL 0
+#define REBOOT_MODE_HARD 1
+#define REBOOT_MODE_SHUTDOWN 2
+
+#define SERVICE_WORLD_PARAM "server_service"
+#define SERVICE_INSTANCE_PARAM "server_instance"
+#define SERVICE_PR_TEST_JSON "prtestjob.json"
+#define SERVICE_INTERFACE_DLL "TGDreamDaemonBridge.dll"
+#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint"
+
+#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
+#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"
+#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce"
+#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands"
+#define SERVICE_CMD_API_COMPATIBLE "api_compat"
+#define SERVICE_CMD_PLAYER_COUNT "client_count"
+
+#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
+#define SERVICE_CMD_PARAM_COMMAND "command"
+#define SERVICE_CMD_PARAM_SENDER "sender"
+#define SERVICE_CMD_PARAM_CUSTOM "custom"
+
+#define SERVICE_REQUEST_KILL_PROCESS "killme"
+#define SERVICE_REQUEST_IRC_BROADCAST "irc"
+#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
+#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
+#define SERVICE_REQUEST_API_VERSION "api_ver"
+
+#define SERVICE_RETURN_SUCCESS "SUCCESS"
+
+/datum/tgs_api/v3210
+ var/reboot_mode = REBOOT_MODE_NORMAL
+ var/comms_key
+ var/instance_name
+ var/originmastercommit
+ var/commit
+ var/list/cached_custom_tgs_chat_commands
+ var/warned_revison = FALSE
+ var/warned_custom_commands = FALSE
+
+/datum/tgs_api/v3210/ApiVersion()
+ return new /datum/tgs_version("3.2.1.0")
+
+/datum/tgs_api/v3210/proc/trim_left(text)
+ for (var/i = 1 to length(text))
+ if (text2ascii(text, i) > 32)
+ return copytext(text, i)
+ return ""
+
+/datum/tgs_api/v3210/proc/trim_right(text)
+ for (var/i = length(text), i > 0, i--)
+ if (text2ascii(text, i) > 32)
+ return copytext(text, 1, i + 1)
+ return ""
+
+/datum/tgs_api/v3210/proc/file2list(filename)
+ return splittext(trim_left(trim_right(file2text(filename))), "\n")
+
+/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) //don't use event handling in this version
+ . = FALSE
+
+ comms_key = world.params[SERVICE_WORLD_PARAM]
+ instance_name = world.params[SERVICE_INSTANCE_PARAM]
+ if(!instance_name)
+ instance_name = "TG Station Server" //maybe just upgraded
+
+ var/list/logs = file2list(".git/logs/HEAD")
+ if(logs.len)
+ logs = splittext(logs[logs.len - 1], " ")
+ commit = logs[2]
+ logs = file2list(".git/logs/refs/remotes/origin/master")
+ if(logs.len)
+ originmastercommit = splittext(logs[logs.len - 1], " ")[2]
+
+ if(world.system_type != MS_WINDOWS)
+ TGS_ERROR_LOG("This API version is only supported on Windows. Not running on Windows. Aborting initialization!")
+ return
+ ListServiceCustomCommands(TRUE)
+ var/datum/tgs_version/api_version = ApiVersion()
+ ExportService("[SERVICE_REQUEST_API_VERSION] [api_version.deprefixed_parameter]", TRUE)
+ return TRUE
+
+//nothing to do for v3
+/datum/tgs_api/v3210/OnInitializationComplete()
+ return
+
+/datum/tgs_api/v3210/InstanceName()
+ return world.params[SERVICE_INSTANCE_PARAM]
+
+/datum/tgs_api/v3210/proc/ExportService(command, skip_compat_check = FALSE)
+ . = FALSE
+ if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL))
+ TGS_ERROR_LOG("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.")
+ return
+ call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval
+ return TRUE
+
+/datum/tgs_api/v3210/OnTopic(T)
+ var/list/params = params2list(T)
+ var/their_sCK = params[SERVICE_CMD_PARAM_KEY]
+ if(!their_sCK)
+ return FALSE //continue world/Topic
+
+ if(their_sCK != comms_key)
+ return "Invalid comms key!";
+
+ var/command = params[SERVICE_CMD_PARAM_COMMAND]
+ if(!command)
+ return "No command!"
+
+ switch(command)
+ if(SERVICE_CMD_API_COMPATIBLE)
+ return SERVICE_RETURN_SUCCESS
+ if(SERVICE_CMD_HARD_REBOOT)
+ if(reboot_mode != REBOOT_MODE_HARD)
+ reboot_mode = REBOOT_MODE_HARD
+ TGS_INFO_LOG("Hard reboot requested by service")
+ TGS_NOTIFY_ADMINS("The world will hard reboot at the end of the game. Requested by TGS.")
+ if(SERVICE_CMD_GRACEFUL_SHUTDOWN)
+ if(reboot_mode != REBOOT_MODE_SHUTDOWN)
+ reboot_mode = REBOOT_MODE_SHUTDOWN
+ TGS_INFO_LOG("Shutdown requested by service")
+ TGS_NOTIFY_ADMINS("The world will shutdown at the end of the game. Requested by TGS.")
+ if(SERVICE_CMD_WORLD_ANNOUNCE)
+ var/msg = params["message"]
+ if(!istext(msg) || !msg)
+ return "No message set!"
+ TGS_WORLD_ANNOUNCE(msg)
+ return SERVICE_RETURN_SUCCESS
+ if(SERVICE_CMD_PLAYER_COUNT)
+ return "[TGS_CLIENT_COUNT]"
+ if(SERVICE_CMD_LIST_CUSTOM)
+ return json_encode(ListServiceCustomCommands(FALSE))
+ else
+ var/custom_command_result = HandleServiceCustomCommand(lowertext(command), params[SERVICE_CMD_PARAM_SENDER], params[SERVICE_CMD_PARAM_CUSTOM])
+ if(custom_command_result)
+ return istext(custom_command_result) ? custom_command_result : SERVICE_RETURN_SUCCESS
+ return "Unknown command: [command]"
+
+/datum/tgs_api/v3210/OnReboot()
+ switch(reboot_mode)
+ if(REBOOT_MODE_HARD)
+ TGS_WORLD_ANNOUNCE("Hard reboot triggered, you will automatically reconnect...")
+ EndProcess()
+ if(REBOOT_MODE_SHUTDOWN)
+ TGS_WORLD_ANNOUNCE("The server is shutting down...")
+ EndProcess()
+ else
+ ExportService(SERVICE_REQUEST_WORLD_REBOOT) //just let em know
+
+/datum/tgs_api/v3210/TestMerges()
+ //do the best we can here as the datum can't be completed using the v3 api
+ . = list()
+ if(!fexists(SERVICE_PR_TEST_JSON))
+ return
+ var/list/json = json_decode(file2text(SERVICE_PR_TEST_JSON))
+ if(!json)
+ return
+ for(var/I in json)
+ var/datum/tgs_revision_information/test_merge/tm = new
+ tm.number = text2num(I)
+ var/list/entry = json[I]
+ tm.pull_request_commit = entry["commit"]
+ tm.author = entry["author"]
+ tm.title = entry["title"]
+ . += tm
+
+/datum/tgs_api/v3210/Revision()
+ if(!warned_revison)
+ var/datum/tgs_version/api_version = ApiVersion()
+ TGS_ERROR_LOG("Use of TgsRevision on [api_version.deprefixed_parameter] origin_commit only points to master!")
+ warned_revison = TRUE
+ var/datum/tgs_revision_information/ri = new
+ ri.commit = commit
+ ri.origin_commit = originmastercommit
+ return ri
+
+/datum/tgs_api/v3210/EndProcess()
+ sleep(world.tick_lag) //flush the buffers
+ ExportService(SERVICE_REQUEST_KILL_PROCESS)
+
+/datum/tgs_api/v3210/ChatChannelInfo()
+ return list()
+
+/datum/tgs_api/v3210/ChatBroadcast(message, list/channels)
+ if(channels)
+ return TGS_UNIMPLEMENTED
+ ChatTargetedBroadcast(message, TRUE)
+ ChatTargetedBroadcast(message, FALSE)
+
+/datum/tgs_api/v3210/ChatTargetedBroadcast(message, admin_only)
+ ExportService("[admin_only ? SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE : SERVICE_REQUEST_IRC_BROADCAST] [message]")
+
+/datum/tgs_api/v3210/ChatPrivateMessage(message, datum/tgs_chat_user/user)
+ return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/v3210/SecurityLevel()
+ return TGS_SECURITY_TRUSTED
+
+#undef REBOOT_MODE_NORMAL
+#undef REBOOT_MODE_HARD
+#undef REBOOT_MODE_SHUTDOWN
+
+#undef SERVICE_WORLD_PARAM
+#undef SERVICE_INSTANCE_PARAM
+#undef SERVICE_PR_TEST_JSON
+#undef SERVICE_INTERFACE_DLL
+#undef SERVICE_INTERFACE_FUNCTION
+
+#undef SERVICE_CMD_HARD_REBOOT
+#undef SERVICE_CMD_GRACEFUL_SHUTDOWN
+#undef SERVICE_CMD_WORLD_ANNOUNCE
+#undef SERVICE_CMD_LIST_CUSTOM
+#undef SERVICE_CMD_API_COMPATIBLE
+#undef SERVICE_CMD_PLAYER_COUNT
+
+#undef SERVICE_CMD_PARAM_KEY
+#undef SERVICE_CMD_PARAM_COMMAND
+#undef SERVICE_CMD_PARAM_SENDER
+#undef SERVICE_CMD_PARAM_CUSTOM
+
+#undef SERVICE_REQUEST_KILL_PROCESS
+#undef SERVICE_REQUEST_IRC_BROADCAST
+#undef SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE
+#undef SERVICE_REQUEST_WORLD_REBOOT
+#undef SERVICE_REQUEST_API_VERSION
+
+#undef SERVICE_RETURN_SUCCESS
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v3210/commands.dm b/code/modules/tgs/v3210/commands.dm
new file mode 100644
index 0000000000..5046631981
--- /dev/null
+++ b/code/modules/tgs/v3210/commands.dm
@@ -0,0 +1,78 @@
+#define SERVICE_JSON_PARAM_HELPTEXT "help_text"
+#define SERVICE_JSON_PARAM_ADMINONLY "admin_only"
+#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters"
+
+/datum/tgs_api/v3210/proc/ListServiceCustomCommands(warnings_only)
+ if(!warnings_only)
+ . = list()
+ var/list/command_name_types = list()
+ var/list/warned_command_names = warnings_only ? list() : null
+ var/warned_about_the_dangers_of_robutussin = !warnings_only
+ for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
+ if(!warned_about_the_dangers_of_robutussin)
+ TGS_ERROR_LOG("Custom chat commands in [ApiVersion()] lacks the /datum/tgs_chat_user/sender.channel field!")
+ warned_about_the_dangers_of_robutussin = TRUE
+ var/datum/tgs_chat_command/stc = I
+ var/command_name = initial(stc.name)
+ if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
+ if(warnings_only && !warned_command_names[command_name])
+ TGS_ERROR_LOG("Custom command [command_name] can't be used as it is empty or contains illegal characters!")
+ warned_command_names[command_name] = TRUE
+ continue
+
+ if(command_name_types[command_name])
+ if(warnings_only)
+ TGS_ERROR_LOG("Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!")
+ continue
+ command_name_types[stc] = command_name
+
+ if(!warnings_only)
+ .[command_name] = list(SERVICE_JSON_PARAM_HELPTEXT = initial(stc.help_text), SERVICE_JSON_PARAM_ADMINONLY = initial(stc.admin_only), SERVICE_JSON_PARAM_REQUIREDPARAMETERS = 0)
+
+/datum/tgs_api/v3210/proc/HandleServiceCustomCommand(command, sender, params)
+ if(!cached_custom_tgs_chat_commands)
+ cached_custom_tgs_chat_commands = list()
+ for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
+ var/datum/tgs_chat_command/stc = I
+ cached_custom_tgs_chat_commands[lowertext(initial(stc.name))] = stc
+
+ var/command_type = cached_custom_tgs_chat_commands[command]
+ if(!command_type)
+ return FALSE
+ var/datum/tgs_chat_command/stc = new command_type
+ var/datum/tgs_chat_user/user = new
+ user.friendly_name = sender
+ user.mention = sender
+ return stc.Run(user, params) || TRUE
+
+/*
+
+#undef SERVICE_JSON_PARAM_HELPTEXT
+#undef SERVICE_JSON_PARAM_ADMINONLY
+#undef SERVICE_JSON_PARAM_REQUIREDPARAMETERS
+
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm
new file mode 100644
index 0000000000..5c98a1a7a7
--- /dev/null
+++ b/code/modules/tgs/v4/api.dm
@@ -0,0 +1,342 @@
+#define TGS4_PARAM_INFO_JSON "tgs_json"
+
+#define TGS4_INTEROP_ACCESS_IDENTIFIER "tgs_tok"
+
+#define TGS4_RESPONSE_SUCCESS "tgs_succ"
+
+#define TGS4_TOPIC_CHANGE_PORT "tgs_port"
+#define TGS4_TOPIC_CHANGE_REBOOT_MODE "tgs_rmode"
+#define TGS4_TOPIC_CHAT_COMMAND "tgs_chat_comm"
+#define TGS4_TOPIC_EVENT "tgs_event"
+#define TGS4_TOPIC_INTEROP_RESPONSE "tgs_interop"
+
+#define TGS4_COMM_NEW_PORT "tgs_new_port"
+#define TGS4_COMM_VALIDATE "tgs_validate"
+#define TGS4_COMM_SERVER_PRIMED "tgs_prime"
+#define TGS4_COMM_WORLD_REBOOT "tgs_reboot"
+#define TGS4_COMM_END_PROCESS "tgs_kill"
+#define TGS4_COMM_CHAT "tgs_chat_send"
+
+#define TGS4_PARAMETER_COMMAND "tgs_com"
+#define TGS4_PARAMETER_DATA "tgs_data"
+
+#define TGS4_PORT_CRITFAIL_MESSAGE " Must exit to let watchdog reboot..."
+
+#define EXPORT_TIMEOUT_DS 200
+
+/datum/tgs_api/v4
+ var/access_identifier
+ var/instance_name
+ var/json_path
+ var/chat_channels_json_path
+ var/chat_commands_json_path
+ var/server_commands_json_path
+ var/reboot_mode = TGS_REBOOT_MODE_NORMAL
+ var/security_level
+
+ var/requesting_new_port = FALSE
+
+ var/list/intercepted_message_queue
+
+ var/list/custom_commands
+
+ var/list/cached_test_merges
+ var/datum/tgs_revision_information/cached_revision
+
+ var/datum/tgs_event_handler/event_handler
+
+ var/export_lock = FALSE
+ var/list/last_interop_response
+
+/datum/tgs_api/v4/ApiVersion()
+ return new /datum/tgs_version("4.0.0.0")
+
+/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
+ json_path = world.params[TGS4_PARAM_INFO_JSON]
+ if(!json_path)
+ TGS_ERROR_LOG("Missing [TGS4_PARAM_INFO_JSON] world parameter!")
+ return
+ var/json_file = file2text(json_path)
+ if(!json_file)
+ TGS_ERROR_LOG("Missing specified json file: [json_path]")
+ return
+ var/cached_json = json_decode(json_file)
+ if(!cached_json)
+ TGS_ERROR_LOG("Failed to decode info json: [json_file]")
+ return
+
+ access_identifier = cached_json["accessIdentifier"]
+ server_commands_json_path = cached_json["serverCommandsJson"]
+
+ if(cached_json["apiValidateOnly"])
+ TGS_INFO_LOG("Validating API and exiting...")
+ Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = "[minimum_required_security_level]"))
+ del(world)
+
+ security_level = cached_json["securityLevel"]
+ chat_channels_json_path = cached_json["chatChannelsJson"]
+ chat_commands_json_path = cached_json["chatCommandsJson"]
+ src.event_handler = event_handler
+ instance_name = cached_json["instanceName"]
+
+ ListCustomCommands()
+
+ var/list/revisionData = cached_json["revision"]
+ if(revisionData)
+ cached_revision = new
+ cached_revision.commit = revisionData["commitSha"]
+ cached_revision.origin_commit = revisionData["originCommitSha"]
+
+ cached_test_merges = list()
+ var/list/json = cached_json["testMerges"]
+ for(var/entry in json)
+ var/datum/tgs_revision_information/test_merge/tm = new
+ tm.time_merged = text2num(entry["timeMerged"])
+
+ var/list/revInfo = entry["revision"]
+ if(revInfo)
+ tm.commit = revInfo["commitSha"]
+ tm.origin_commit = revInfo["originCommitSha"]
+
+ tm.title = entry["titleAtMerge"]
+ tm.body = entry["bodyAtMerge"]
+ tm.url = entry["url"]
+ tm.author = entry["author"]
+ tm.number = entry["number"]
+ tm.pull_request_commit = entry["pullRequestRevision"]
+ tm.comment = entry["comment"]
+
+ cached_test_merges += tm
+
+ return TRUE
+
+/datum/tgs_api/v4/OnInitializationComplete()
+ Export(TGS4_COMM_SERVER_PRIMED)
+
+ var/tgs4_secret_sleep_offline_sauce = 24051994
+ var/old_sleep_offline = world.sleep_offline
+ world.sleep_offline = tgs4_secret_sleep_offline_sauce
+ sleep(1)
+ if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
+ world.sleep_offline = old_sleep_offline
+
+/datum/tgs_api/v4/OnTopic(T)
+ var/list/params = params2list(T)
+ var/their_sCK = params[TGS4_INTEROP_ACCESS_IDENTIFIER]
+ if(!their_sCK)
+ return FALSE //continue world/Topic
+
+ if(their_sCK != access_identifier)
+ return "Invalid comms key!";
+
+ var/command = params[TGS4_PARAMETER_COMMAND]
+ if(!command)
+ return "No command!"
+
+ . = TGS4_RESPONSE_SUCCESS
+
+ switch(command)
+ if(TGS4_TOPIC_CHAT_COMMAND)
+ var/result = HandleCustomCommand(params[TGS4_PARAMETER_DATA])
+ if(result == null)
+ result = "Error running chat command!"
+ return result
+ if(TGS4_TOPIC_EVENT)
+ intercepted_message_queue = list()
+ var/list/event_notification = json_decode(params[TGS4_PARAMETER_DATA])
+ var/list/event_parameters = event_notification["Parameters"]
+
+ var/list/event_call = list(event_notification["Type"])
+ if(event_parameters)
+ event_call += event_parameters
+
+ if(event_handler != null)
+ event_handler.HandleEvent(arglist(event_call))
+
+ . = json_encode(intercepted_message_queue)
+ intercepted_message_queue = null
+ return
+ if(TGS4_TOPIC_INTEROP_RESPONSE)
+ last_interop_response = json_decode(params[TGS4_PARAMETER_DATA])
+ return
+ if(TGS4_TOPIC_CHANGE_PORT)
+ var/new_port = text2num(params[TGS4_PARAMETER_DATA])
+ if (!(new_port > 0))
+ return "Invalid port: [new_port]"
+
+ //the topic still completes, miraculously
+ //I honestly didn't believe byond could do it
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port)
+ if(!world.OpenPort(new_port))
+ return "Port change failed!"
+ return
+ if(TGS4_TOPIC_CHANGE_REBOOT_MODE)
+ var/new_reboot_mode = text2num(params[TGS4_PARAMETER_DATA])
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode)
+ reboot_mode = new_reboot_mode
+ return
+
+ return "Unknown command: [command]"
+
+/datum/tgs_api/v4/proc/Export(command, list/data, override_requesting_new_port = FALSE)
+ if(!data)
+ data = list()
+ data[TGS4_PARAMETER_COMMAND] = command
+ var/json = json_encode(data)
+
+ while(requesting_new_port && !override_requesting_new_port)
+ sleep(1)
+
+ //we need some port open at this point to facilitate return communication
+ if(!world.port)
+ requesting_new_port = TRUE
+ if(!world.OpenPort(0)) //open any port
+ TGS_ERROR_LOG("Unable to open random port to retrieve new port![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+
+ //request a new port
+ export_lock = FALSE
+ var/list/new_port_json = Export(TGS4_COMM_NEW_PORT, list(TGS4_PARAMETER_DATA = "[world.port]"), TRUE) //stringify this on purpose
+
+ if(!new_port_json)
+ TGS_ERROR_LOG("No new port response from server![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+
+ var/new_port = new_port_json[TGS4_PARAMETER_DATA]
+ if(!isnum(new_port) || new_port <= 0)
+ TGS_ERROR_LOG("Malformed new port json ([json_encode(new_port_json)])![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+
+ if(new_port != world.port && !world.OpenPort(new_port))
+ TGS_ERROR_LOG("Unable to open port [new_port]![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+ requesting_new_port = FALSE
+
+ while(export_lock)
+ sleep(1)
+ export_lock = TRUE
+
+ last_interop_response = null
+ fdel(server_commands_json_path)
+ text2file(json, server_commands_json_path)
+
+ for(var/I = 0; I < EXPORT_TIMEOUT_DS && !last_interop_response; ++I)
+ sleep(1)
+
+ if(!last_interop_response)
+ TGS_ERROR_LOG("Failed to get export result for: [json]")
+ else
+ . = last_interop_response
+
+ export_lock = FALSE
+
+/datum/tgs_api/v4/OnReboot()
+ var/list/result = Export(TGS4_COMM_WORLD_REBOOT)
+ if(!result)
+ return
+
+ //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter
+
+ var/port = result[TGS4_PARAMETER_DATA]
+ if(!isnum(port))
+ return //this is valid, server may just want use to reboot
+
+ if(port == 0)
+ //to byond 0 means any port and "none" means close vOv
+ port = "none"
+
+ if(!world.OpenPort(port))
+ TGS_ERROR_LOG("Unable to set port to [port]!")
+
+/datum/tgs_api/v4/InstanceName()
+ return instance_name
+
+/datum/tgs_api/v4/TestMerges()
+ return cached_test_merges
+
+/datum/tgs_api/v4/EndProcess()
+ Export(TGS4_COMM_END_PROCESS)
+
+/datum/tgs_api/v4/Revision()
+ return cached_revision
+
+/datum/tgs_api/v4/ChatBroadcast(message, list/channels)
+ var/list/ids
+ if(length(channels))
+ ids = list()
+ for(var/I in channels)
+ var/datum/tgs_chat_channel/channel = I
+ ids += channel.id
+ message = list("message" = message, "channelIds" = ids)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Export(TGS4_COMM_CHAT, message)
+
+/datum/tgs_api/v4/ChatTargetedBroadcast(message, admin_only)
+ var/list/channels = list()
+ for(var/I in ChatChannelInfo())
+ var/datum/tgs_chat_channel/channel = I
+ if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only)))
+ channels += channel.id
+ message = list("message" = message, "channelIds" = channels)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Export(TGS4_COMM_CHAT, message)
+
+/datum/tgs_api/v4/ChatPrivateMessage(message, datum/tgs_chat_user/user)
+ message = list("message" = message, "channelIds" = list(user.channel.id))
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Export(TGS4_COMM_CHAT, message)
+
+/datum/tgs_api/v4/ChatChannelInfo()
+ . = list()
+ //no caching cause tgs may change this
+ var/list/json = json_decode(file2text(chat_channels_json_path))
+ for(var/I in json)
+ . += DecodeChannel(I)
+
+/datum/tgs_api/v4/proc/DecodeChannel(channel_json)
+ var/datum/tgs_chat_channel/channel = new
+ channel.id = channel_json["id"]
+ channel.friendly_name = channel_json["friendlyName"]
+ channel.connection_name = channel_json["connectionName"]
+ channel.is_admin_channel = channel_json["isAdminChannel"]
+ channel.is_private_channel = channel_json["isPrivateChannel"]
+ channel.custom_tag = channel_json["tag"]
+ return channel
+
+/datum/tgs_api/v4/SecurityLevel()
+ return security_level
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v4/commands.dm b/code/modules/tgs/v4/commands.dm
new file mode 100644
index 0000000000..1d9951bc04
--- /dev/null
+++ b/code/modules/tgs/v4/commands.dm
@@ -0,0 +1,69 @@
+/datum/tgs_api/v4/proc/ListCustomCommands()
+ var/results = list()
+ custom_commands = list()
+ for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
+ var/datum/tgs_chat_command/stc = new I
+ var/command_name = stc.name
+ if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
+ TGS_ERROR_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!")
+ continue
+
+ if(results[command_name])
+ var/datum/other = custom_commands[command_name]
+ TGS_ERROR_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!")
+ continue
+ results += list(list("name" = command_name, "help_text" = stc.help_text, "admin_only" = stc.admin_only))
+ custom_commands[command_name] = stc
+
+ var/commands_file = chat_commands_json_path
+ if(!commands_file)
+ return
+ text2file(json_encode(results), commands_file)
+
+/datum/tgs_api/v4/proc/HandleCustomCommand(command_json)
+ var/list/data = json_decode(command_json)
+ var/command = data["command"]
+ var/user = data["user"]
+ var/params = data["params"]
+
+ var/datum/tgs_chat_user/u = new
+ u.id = user["id"]
+ u.friendly_name = user["friendlyName"]
+ u.mention = user["mention"]
+ u.channel = DecodeChannel(user["channel"])
+
+ var/datum/tgs_chat_command/sc = custom_commands[command]
+ if(sc)
+ var/result = sc.Run(u, params)
+ if(result == null)
+ result = ""
+ return result
+ return "Unknown command: [command]!"
+
+/*
+
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm
new file mode 100644
index 0000000000..1117a1df50
--- /dev/null
+++ b/code/modules/tgs/v5/_defines.dm
@@ -0,0 +1,121 @@
+#define DMAPI5_PARAM_SERVER_PORT "tgs_port"
+#define DMAPI5_PARAM_ACCESS_IDENTIFIER "tgs_key"
+
+#define DMAPI5_BRIDGE_DATA "data"
+#define DMAPI5_TOPIC_DATA "tgs_data"
+
+#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0
+#define DMAPI5_BRIDGE_COMMAND_STARTUP 1
+#define DMAPI5_BRIDGE_COMMAND_PRIME 2
+#define DMAPI5_BRIDGE_COMMAND_REBOOT 3
+#define DMAPI5_BRIDGE_COMMAND_KILL 4
+#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5
+
+#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
+#define DMAPI5_RESPONSE_ERROR_MESSAGE "errorMessage"
+
+#define DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE "commandType"
+#define DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT "currentPort"
+#define DMAPI5_BRIDGE_PARAMETER_VERSION "version"
+#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage"
+#define DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS "customCommands"
+#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel"
+
+#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
+#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"
+
+#define DMAPI5_CHAT_MESSAGE_TEXT "text"
+#define DMAPI5_CHAT_MESSAGE_CHANNEL_IDS "channelIds"
+
+#define DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER "accessIdentifier"
+#define DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION "serverVersion"
+#define DMAPI5_RUNTIME_INFORMATION_SERVER_PORT "serverPort"
+#define DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY "apiValidateOnly"
+#define DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME "instanceName"
+#define DMAPI5_RUNTIME_INFORMATION_REVISION "revision"
+#define DMAPI5_RUNTIME_INFORMATION_TEST_MERGES "testMerges"
+#define DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL "securityLevel"
+
+#define DMAPI5_CHAT_UPDATE_CHANNELS "channels"
+
+#define DMAPI5_TEST_MERGE_TIME_MERGED "timeMerged"
+#define DMAPI5_TEST_MERGE_REVISION "revision"
+#define DMAPI5_TEST_MERGE_TITLE_AT_MERGE "titleAtMerge"
+#define DMAPI5_TEST_MERGE_BODY_AT_MERGE "bodyAtMerge"
+#define DMAPI5_TEST_MERGE_URL "url"
+#define DMAPI5_TEST_MERGE_AUTHOR "author"
+#define DMAPI5_TEST_MERGE_NUMBER "number"
+#define DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION "pullRequestRevision"
+#define DMAPI5_TEST_MERGE_COMMENT "comment"
+
+#define DMAPI5_CHAT_COMMAND_NAME "name"
+#define DMAPI5_CHAT_COMMAND_PARAMS "params"
+#define DMAPI5_CHAT_COMMAND_USER "user"
+
+#define DMAPI5_EVENT_NOTIFICATION_TYPE "type"
+#define DMAPI5_EVENT_NOTIFICATION_PARAMETERS "parameters"
+
+#define DMAPI5_TOPIC_COMMAND_CHAT_COMMAND 0
+#define DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION 1
+#define DMAPI5_TOPIC_COMMAND_CHANGE_PORT 2
+#define DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE 3
+#define DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED 4
+#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 4
+#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 5
+
+#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
+#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
+#define DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION "eventNotification"
+#define DMAPI5_TOPIC_PARAMETER_NEW_PORT "newPort"
+#define DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE "newRebootState"
+#define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName"
+#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate"
+
+#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage"
+#define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses"
+
+#define DMAPI5_REVISION_INFORMATION_COMMIT_SHA "commitSha"
+#define DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA "originCommitSha"
+
+#define DMAPI5_CHAT_USER_ID "id"
+#define DMAPI5_CHAT_USER_FRIENDLY_NAME "friendlyName"
+#define DMAPI5_CHAT_USER_MENTION "mention"
+#define DMAPI5_CHAT_USER_CHANNEL "channel"
+
+#define DMAPI5_CHAT_CHANNEL_ID "id"
+#define DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME "friendlyName"
+#define DMAPI5_CHAT_CHANNEL_CONNECTION_NAME "connectionName"
+#define DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL "isAdminChannel"
+#define DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL "isPrivateChannel"
+#define DMAPI5_CHAT_CHANNEL_TAG "tag"
+
+#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
+#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
+#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly"
+
+/*
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
new file mode 100644
index 0000000000..32f80c0ae4
--- /dev/null
+++ b/code/modules/tgs/v5/api.dm
@@ -0,0 +1,352 @@
+/datum/tgs_api/v5
+ var/server_port
+ var/access_identifier
+
+ var/instance_name
+ var/security_level
+
+ var/reboot_mode = TGS_REBOOT_MODE_NORMAL
+
+ var/list/intercepted_message_queue
+
+ var/list/custom_commands
+
+ var/list/test_merges
+ var/datum/tgs_revision_information/revision
+ var/list/chat_channels
+
+ var/datum/tgs_event_handler/event_handler
+
+/datum/tgs_api/v5/ApiVersion()
+ return new /datum/tgs_version("5.0.0")
+
+/datum/tgs_api/v5/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
+ src.event_handler = event_handler
+
+ server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
+ access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER]
+
+ var/datum/tgs_version/api_version = ApiVersion()
+ var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands()))
+ if(!istype(bridge_response))
+ TGS_ERROR_LOG("Failed initial bridge request!")
+ return FALSE
+
+ var/list/runtime_information = bridge_response[DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION]
+ if(!istype(runtime_information))
+ TGS_ERROR_LOG("Failed to decode runtime information from bridge response: [json_encode(bridge_response)]!")
+ return FALSE
+
+ if(runtime_information[DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY])
+ TGS_INFO_LOG("DMAPI validation, exiting...")
+ del(world)
+
+ security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL]
+ instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME]
+ version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION])
+
+ var/list/revisionData = runtime_information[DMAPI5_RUNTIME_INFORMATION_REVISION]
+ if(istype(revisionData))
+ revision = new
+ revision.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA]
+ revision.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA]
+ else
+ TGS_ERROR_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_REVISION] from runtime information!")
+
+ test_merges = list()
+ var/list/test_merge_json = runtime_information[DMAPI5_RUNTIME_INFORMATION_TEST_MERGES]
+ if(istype(test_merge_json))
+ for(var/entry in test_merge_json)
+ var/datum/tgs_revision_information/test_merge/tm = new
+ tm.number = entry[DMAPI5_TEST_MERGE_NUMBER]
+
+ var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION]
+ if(revInfo)
+ tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA]
+ tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA]
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_TEST_MERGE_REVISION] from test merge #[tm.number]!")
+
+ tm.time_merged = text2num(entry[DMAPI5_TEST_MERGE_TIME_MERGED])
+ tm.title = entry[DMAPI5_TEST_MERGE_TITLE_AT_MERGE]
+ tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE]
+ tm.url = entry[DMAPI5_TEST_MERGE_URL]
+ tm.author = entry[DMAPI5_TEST_MERGE_AUTHOR]
+ tm.pull_request_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION]
+ tm.comment = entry[DMAPI5_TEST_MERGE_COMMENT]
+
+ test_merges += tm
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_TEST_MERGES] from runtime information!")
+
+ chat_channels = list()
+ DecodeChannels(runtime_information)
+
+ return TRUE
+
+/datum/tgs_api/v5/OnInitializationComplete()
+ Bridge(DMAPI5_BRIDGE_COMMAND_PRIME)
+
+ var/tgs4_secret_sleep_offline_sauce = 29051994
+ var/old_sleep_offline = world.sleep_offline
+ world.sleep_offline = tgs4_secret_sleep_offline_sauce
+ sleep(1)
+ if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
+ world.sleep_offline = old_sleep_offline
+
+/datum/tgs_api/v5/proc/TopicResponse(error_message = null)
+ var/list/response = list()
+ response[DMAPI5_RESPONSE_ERROR_MESSAGE] = error_message
+
+ return json_encode(response)
+
+/datum/tgs_api/v5/OnTopic(T)
+ var/list/params = params2list(T)
+ var/json = params[DMAPI5_TOPIC_DATA]
+ if(!json)
+ return FALSE //continue world/Topic
+
+ var/list/topic_parameters = json_decode(json)
+ if(!topic_parameters)
+ return TopicResponse("Invalid topic parameters json!");
+
+ var/their_sCK = topic_parameters[DMAPI5_PARAMETER_ACCESS_IDENTIFIER]
+ if(their_sCK != access_identifier)
+ return TopicResponse("Failed to decode [DMAPI5_PARAMETER_ACCESS_IDENTIFIER] from: [json]!");
+
+ var/command = topic_parameters[DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE]
+ if(!isnum(command))
+ return TopicResponse("Failed to decode [DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE] from: [json]!")
+
+ switch(command)
+ if(DMAPI5_TOPIC_COMMAND_CHAT_COMMAND)
+ var/result = HandleCustomCommand(topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND])
+ if(!result)
+ result = TopicResponse("Error running chat command!")
+ return result
+ if(DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION)
+ intercepted_message_queue = list()
+ var/list/event_notification = topic_parameters[DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]
+ if(!istype(event_notification))
+ return TopicResponse("Invalid [DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]!")
+
+ var/event_type = event_notification[DMAPI5_EVENT_NOTIFICATION_TYPE]
+ if(!isnum(event_type))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_TYPE]!")
+
+ var/list/event_parameters = event_notification[DMAPI5_EVENT_NOTIFICATION_PARAMETERS]
+ if(event_parameters && !istype(event_parameters))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_PARAMETERS]!")
+
+ var/list/event_call = list(event_type)
+ if(event_parameters)
+ event_call += event_parameters
+
+ if(event_handler != null)
+ event_handler.HandleEvent(arglist(event_call))
+
+ var/list/response = list()
+ response[DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES] = intercepted_message_queue
+ intercepted_message_queue = null
+ return json_encode(response)
+ if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT)
+ var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
+ if (!isnum(new_port) || !(new_port > 0))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port)
+
+ //the topic still completes, miraculously
+ //I honestly didn't believe byond could do it without exploding
+ if(!world.OpenPort(new_port))
+ return TopicResponse("Port change failed!")
+
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE)
+ var/new_reboot_mode = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]
+ if(!isnum(new_reboot_mode))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]!")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode)
+
+ reboot_mode = new_reboot_mode
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED)
+ var/new_instance_name = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]
+ if(!istext(new_instance_name))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]!")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_INSTANCE_RENAMED, new_instance_name)
+
+ instance_name = new_instance_name
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE)
+ var/list/chat_update_json = topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]
+ if(!istype(chat_update_json))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]!")
+
+ DecodeChannels(chat_update_json)
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE)
+ var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
+ if (!isnum(new_port) || !(new_port > 0))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
+
+ server_port = new_port
+ return TopicResponse()
+
+ return TopicResponse("Unknown command: [command]")
+
+/datum/tgs_api/v5/proc/Bridge(command, list/data)
+ if(!data)
+ data = list()
+
+ data[DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE] = command
+ data[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] = access_identifier
+
+ var/json = json_encode(data)
+ var/encoded_json = url_encode(json)
+
+ // This is an infinite sleep until we get a response
+ var/export_response = world.Export("http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]")
+ if(!export_response)
+ TGS_ERROR_LOG("Failed export request: [json]")
+ return
+
+ var/response_json = file2text(export_response["CONTENT"])
+ if(!response_json)
+ TGS_ERROR_LOG("Failed export request, missing content!")
+ return
+
+ var/list/bridge_response = json_decode(response_json)
+ if(!bridge_response)
+ TGS_ERROR_LOG("Failed export request, bad json: [response_json]")
+ return
+
+ var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE]
+ if(error)
+ TGS_ERROR_LOG("Failed export request, bad request: [error]")
+ return
+
+ return bridge_response
+
+/datum/tgs_api/v5/OnReboot()
+ var/list/result = Bridge(DMAPI5_BRIDGE_COMMAND_REBOOT)
+ if(!result)
+ return
+
+ //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter
+
+ var/port = result[DMAPI5_BRIDGE_RESPONSE_NEW_PORT]
+ if(!isnum(port))
+ return //this is valid, server may just want use to reboot
+
+ if(port == 0)
+ //to byond 0 means any port and "none" means close vOv
+ port = "none"
+
+ if(!world.OpenPort(port))
+ TGS_ERROR_LOG("Unable to set port to [port]!")
+
+/datum/tgs_api/v5/InstanceName()
+ return instance_name
+
+/datum/tgs_api/v5/TestMerges()
+ return test_merges
+
+/datum/tgs_api/v5/EndProcess()
+ Bridge(DMAPI5_BRIDGE_COMMAND_KILL)
+
+/datum/tgs_api/v5/Revision()
+ return revision
+
+/datum/tgs_api/v5/ChatBroadcast(message, list/channels)
+ if(!length(channels))
+ channels = ChatChannelInfo()
+
+ var/list/ids = list()
+ for(var/I in channels)
+ var/datum/tgs_chat_channel/channel = I
+ ids += channel.id
+
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = ids)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatTargetedBroadcast(message, admin_only)
+ var/list/channels = list()
+ for(var/I in ChatChannelInfo())
+ var/datum/tgs_chat_channel/channel = I
+ if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only)))
+ channels += channel.id
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = channels)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatPrivateMessage(message, datum/tgs_chat_user/user)
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = list(user.channel.id))
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatChannelInfo()
+ return chat_channels
+
+/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
+ var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
+ if(istype(chat_channels_json))
+ chat_channels.Cut()
+ for(var/channel_json in chat_channels_json)
+ var/datum/tgs_chat_channel/channel = DecodeChannel(channel_json)
+ if(channel)
+ chat_channels += channel
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_CHAT_UPDATE_CHANNELS] from channel update!")
+
+/datum/tgs_api/v5/proc/DecodeChannel(channel_json)
+ var/datum/tgs_chat_channel/channel = new
+ channel.id = channel_json[DMAPI5_CHAT_CHANNEL_ID]
+ channel.friendly_name = channel_json[DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME]
+ channel.connection_name = channel_json[DMAPI5_CHAT_CHANNEL_CONNECTION_NAME]
+ channel.is_admin_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL]
+ channel.is_private_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL]
+ channel.custom_tag = channel_json[DMAPI5_CHAT_CHANNEL_TAG]
+ return channel
+
+/datum/tgs_api/v5/SecurityLevel()
+ return security_level
+
+/*
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/chat_commands.dm b/code/modules/tgs/v5/chat_commands.dm
new file mode 100644
index 0000000000..bc73602861
--- /dev/null
+++ b/code/modules/tgs/v5/chat_commands.dm
@@ -0,0 +1,15 @@
+/datum/tgs_chat_command/status
+ name = "status"
+ help_text = "Shows the current production server status"
+ admin_only = FALSE
+
+/datum/tgs_chat_command/status/Run(datum/tgs_chat_user/sender, params)
+ return "```Players logged in: [GLOB.clients.len] - Round Duration: [roundduration2text()]```"
+
+/datum/tgs_chat_command/parsetest
+ name = "parsetest"
+ help_text = "Shows the current production server status"
+ admin_only = FALSE
+
+/datum/tgs_chat_command/parsetest/Run(datum/tgs_chat_user/sender, params)
+ return "```You passed:[params]```"
diff --git a/code/modules/tgs/v5/commands.dm b/code/modules/tgs/v5/commands.dm
new file mode 100644
index 0000000000..2775157656
--- /dev/null
+++ b/code/modules/tgs/v5/commands.dm
@@ -0,0 +1,68 @@
+/datum/tgs_api/v5/proc/ListCustomCommands()
+ var/results = list()
+ custom_commands = list()
+ for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
+ var/datum/tgs_chat_command/stc = new I
+ var/command_name = stc.name
+ if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
+ TGS_WARNING_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!")
+ continue
+
+ if(results[command_name])
+ var/datum/other = custom_commands[command_name]
+ TGS_WARNING_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!")
+ continue
+ results += list(list(DMAPI5_CUSTOM_CHAT_COMMAND_NAME = command_name, DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT = stc.help_text, DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY = stc.admin_only))
+ custom_commands[command_name] = stc
+
+ return results
+
+/datum/tgs_api/v5/proc/HandleCustomCommand(list/command_json)
+ var/command = command_json[DMAPI5_CHAT_COMMAND_NAME]
+ var/user = command_json[DMAPI5_CHAT_COMMAND_USER]
+ var/params = command_json[DMAPI5_CHAT_COMMAND_PARAMS]
+
+ var/datum/tgs_chat_user/u = new
+ u.id = user[DMAPI5_CHAT_USER_ID]
+ u.friendly_name = user[DMAPI5_CHAT_USER_FRIENDLY_NAME]
+ u.mention = user[DMAPI5_CHAT_USER_MENTION]
+ u.channel = DecodeChannel(user[DMAPI5_CHAT_USER_CHANNEL])
+
+ var/datum/tgs_chat_command/sc = custom_commands[command]
+ if(sc)
+ var/text_response = sc.Run(u, params)
+ var/list/topic_response = list()
+ if(!istext(text_response))
+ TGS_ERROR_LOG("Custom command [command] should return a string! Got: \"[text_response]\"")
+ text_response = null
+ topic_response[DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE] = text_response
+ return json_encode(topic_response)
+ return TopicResponse("Unknown custom chat command: [command]!")
+
+/*
+
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/undef.dm b/code/modules/tgs/v5/undef.dm
new file mode 100644
index 0000000000..72d673b9b1
--- /dev/null
+++ b/code/modules/tgs/v5/undef.dm
@@ -0,0 +1,121 @@
+#undef DMAPI5_PARAM_SERVER_PORT
+#undef DMAPI5_PARAM_ACCESS_IDENTIFIER
+
+#undef DMAPI5_BRIDGE_DATA
+#undef DMAPI5_TOPIC_DATA
+
+#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE
+#undef DMAPI5_BRIDGE_COMMAND_STARTUP
+#undef DMAPI5_BRIDGE_COMMAND_PRIME
+#undef DMAPI5_BRIDGE_COMMAND_REBOOT
+#undef DMAPI5_BRIDGE_COMMAND_KILL
+#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND
+
+#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
+#undef DMAPI5_RESPONSE_ERROR_MESSAGE
+
+#undef DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE
+#undef DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT
+#undef DMAPI5_BRIDGE_PARAMETER_VERSION
+#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE
+#undef DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS
+#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL
+
+#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT
+#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION
+
+#undef DMAPI5_CHAT_MESSAGE_TEXT
+#undef DMAPI5_CHAT_MESSAGE_CHANNEL_IDS
+
+#undef DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER
+#undef DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION
+#undef DMAPI5_RUNTIME_INFORMATION_SERVER_PORT
+#undef DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY
+#undef DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME
+#undef DMAPI5_RUNTIME_INFORMATION_REVISION
+#undef DMAPI5_RUNTIME_INFORMATION_TEST_MERGES
+#undef DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL
+
+#undef DMAPI5_CHAT_UPDATE_CHANNELS
+
+#undef DMAPI5_TEST_MERGE_TIME_MERGED
+#undef DMAPI5_TEST_MERGE_REVISION
+#undef DMAPI5_TEST_MERGE_TITLE_AT_MERGE
+#undef DMAPI5_TEST_MERGE_BODY_AT_MERGE
+#undef DMAPI5_TEST_MERGE_URL
+#undef DMAPI5_TEST_MERGE_AUTHOR
+#undef DMAPI5_TEST_MERGE_NUMBER
+#undef DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION
+#undef DMAPI5_TEST_MERGE_COMMENT
+
+#undef DMAPI5_CHAT_COMMAND_NAME
+#undef DMAPI5_CHAT_COMMAND_PARAMS
+#undef DMAPI5_CHAT_COMMAND_USER
+
+#undef DMAPI5_EVENT_NOTIFICATION_TYPE
+#undef DMAPI5_EVENT_NOTIFICATION_PARAMETERS
+
+#undef DMAPI5_TOPIC_COMMAND_CHAT_COMMAND
+#undef DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION
+#undef DMAPI5_TOPIC_COMMAND_CHANGE_PORT
+#undef DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE
+#undef DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED
+#undef DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE
+#undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE
+
+#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
+#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
+#undef DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION
+#undef DMAPI5_TOPIC_PARAMETER_NEW_PORT
+#undef DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE
+#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME
+#undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE
+
+#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE
+#undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES
+
+#undef DMAPI5_REVISION_INFORMATION_COMMIT_SHA
+#undef DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA
+
+#undef DMAPI5_CHAT_USER_ID
+#undef DMAPI5_CHAT_USER_FRIENDLY_NAME
+#undef DMAPI5_CHAT_USER_MENTION
+#undef DMAPI5_CHAT_USER_CHANNEL
+
+#undef DMAPI5_CHAT_CHANNEL_ID
+#undef DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME
+#undef DMAPI5_CHAT_CHANNEL_CONNECTION_NAME
+#undef DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL
+#undef DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL
+#undef DMAPI5_CHAT_CHANNEL_TAG
+
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY
+
+/*
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/vchat/vchat_client.dm b/code/modules/vchat/vchat_client.dm
index 6e0ac509b0..8456c5225f 100644
--- a/code/modules/vchat/vchat_client.dm
+++ b/code/modules/vchat/vchat_client.dm
@@ -266,31 +266,45 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic
var/list/partial = splittext(iconData, "{")
return replacetext(copytext(partial[2], 3, -5), "\n", "")
+/proc/expire_bicon_cache(key)
+ if(GLOB.bicon_cache[key])
+ GLOB.bicon_cache -= key
+ return TRUE
+ return FALSE
+
+GLOBAL_LIST_EMPTY(bicon_cache) // Cache of the
tag results, not the icons
/proc/bicon(var/obj, var/use_class = 1, var/custom_classes = "")
var/class = use_class ? "class='icon misc [custom_classes]'" : null
- if (!obj)
+ if(!obj)
return
- var/static/list/bicon_cache = list()
- if (isicon(obj))
- //Icon refs get reused all the time especially on temporarily made ones like chat tags, too difficult to cache.
- //if (!bicon_cache["\ref[obj]"]) // Doesn't exist yet, make it.
- //bicon_cache["\ref[obj]"] = icon2base64(obj)
-
+ // Try to avoid passing bicon an /icon directly. It is better to pass it an atom so it can cache.
+ if(isicon(obj)) // Passed an icon directly, nothing to cache-key on, as icon refs get reused *often*
return "
"
// Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with.
var/atom/A = obj
- var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
- if (!bicon_cache[key]) // Doesn't exist, make it.
- var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1)
- if (ishuman(obj))
- I = getFlatIcon(obj) //Ugly
- bicon_cache[key] = icon2base64(I, key)
+ var/key
+ var/changes_often = ishuman(A) || isobserver(A) // If this ends up with more, move it into a proc or var on atom.
+
+ if(changes_often)
+ key = "\ref[A]"
+ else
+ key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
+
+ var/base64 = GLOB.bicon_cache[key]
+ // Non-human atom, no cache
+ if(!base64) // Doesn't exist, make it.
+ base64 = icon2base64(A.examine_icon(), key)
+ GLOB.bicon_cache[key] = base64
+ if(changes_often)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/expire_bicon_cache, key), 50 SECONDS, TIMER_UNIQUE)
+
+ // May add a class to the img tag created by bicon
if(use_class)
class = "class='icon [A.icon_state] [custom_classes]'"
- return "
"
+ return "
"
//Checks if the message content is a valid to_chat message
/proc/is_valid_tochat_message(message)
diff --git a/code/modules/vehicles/bike.dm b/code/modules/vehicles/bike.dm
index 5d8abe9fbd..1d4cb49a3b 100644
--- a/code/modules/vehicles/bike.dm
+++ b/code/modules/vehicles/bike.dm
@@ -54,6 +54,12 @@
return
..()
+/obj/vehicle/bike/CtrlClick(var/mob/user)
+ if(Adjacent(user) && anchored)
+ toggle()
+ else
+ return ..()
+
/obj/vehicle/bike/verb/toggle()
set name = "Toggle Engine"
set category = "Vehicle"
@@ -71,7 +77,13 @@
turn_off()
src.visible_message("\The [src] putters before turning off.", "You hear something putter slowly.")
-/obj/vehicle/bike/verb/kickstand(var/mob/user as mob) //TFF 22/3/20 - Tweaking the visible_message output so it's not "You put kickstand down" to everyone.
+/obj/vehicle/bike/AltClick(var/mob/user)
+ if(Adjacent(user))
+ kickstand(user)
+ else
+ return ..()
+
+/obj/vehicle/bike/verb/kickstand(var/mob/user as mob)
set name = "Toggle Kickstand"
set category = "Vehicle"
set src in view(0)
diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm
index eb4f1141b8..939c72110e 100644
--- a/code/modules/vehicles/cargo_train.dm
+++ b/code/modules/vehicles/cargo_train.dm
@@ -197,6 +197,22 @@
. += "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition."
. += "The charge meter reads [cell? round(cell.percent(), 0.01) : 0]%"
+
+/obj/vehicle/train/engine/CtrlClick(var/mob/user)
+ if(Adjacent(user))
+ if(on)
+ stop_engine()
+ else
+ start_engine()
+ else
+ return ..()
+
+/obj/vehicle/train/engine/AltClick(var/mob/user)
+ if(Adjacent(user))
+ remove_key()
+ else
+ return ..()
+
/obj/vehicle/train/engine/verb/start_engine()
set name = "Start engine"
set category = "Vehicle"
diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm
index d7814bdaab..4f9cceb981 100644
--- a/code/modules/vore/appearance/sprite_accessories_vr.dm
+++ b/code/modules/vore/appearance/sprite_accessories_vr.dm
@@ -484,6 +484,8 @@
name = "tritail kitsune ears (Rosey)"
desc = ""
icon_state = "rosey"
+ do_colouration = 1
+ color_blend_mode = ICON_MULTIPLY
ckeys_allowed = list("joey4298")
/datum/sprite_accessory/ears/aronai
@@ -1030,6 +1032,8 @@
name = "pentatail kitsune tails (Rosey)" //I predict seven tails next. ~CK
desc = ""
icon_state = "rosey_five"
+ do_colouration = 1
+ color_blend_mode = ICON_MULTIPLY
ckeys_allowed = list("joey4298")
/datum/sprite_accessory/tail/scree
diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm
index 72575492ed..1c4079de15 100644
--- a/code/modules/vore/eating/vorepanel_vr.dm
+++ b/code/modules/vore/eating/vorepanel_vr.dm
@@ -935,7 +935,7 @@
if("Prevent Digestion")
user.digestable = FALSE
- message_admins("[key_name(user)] toggled their digestability to [user.digestable] ([user ? "JMP" : "null"])")
+ message_admins("[key_name(user)] toggled their digestability to [user.digestable] [ADMIN_COORDJMP(user)]")
if(user.client.prefs_vr)
user.client.prefs_vr.digestable = user.digestable
@@ -1002,7 +1002,7 @@
if("Prevent Mob Predation")
user.allowmobvore = FALSE
- message_admins("[key_name(user)] toggled their mob vore preference to [user.allowmobvore] ([user ? "JMP" : "null"])")
+ message_admins("[key_name(user)] toggled their mob vore preference to [user.allowmobvore] [ADMIN_COORDJMP(user)]")
if(user.client.prefs_vr)
user.client.prefs_vr.allowmobvore = user.allowmobvore
diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm
index 45db1edb3e..6927fba35d 100644
--- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm
+++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm
@@ -1887,7 +1887,7 @@ Departamental Swimsuits, for general use
species_restricted = list("exclude", SPECIES_TESHARI)
-/obj/item/clothing/under/fluff/slime_skeleton/mob_can_equip(M as mob, slot)
+/obj/item/clothing/under/fluff/slime_skeleton/mob_can_equip(M as mob, slot, disable_warning = FALSE)
if(!..())
return 0
diff --git a/code/modules/vore/resizing/resize_vr.dm b/code/modules/vore/resizing/resize_vr.dm
index b7e671e9b3..07d3a7831f 100644
--- a/code/modules/vore/resizing/resize_vr.dm
+++ b/code/modules/vore/resizing/resize_vr.dm
@@ -158,6 +158,10 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2
* @return false if normal code should continue, true to prevent normal code.
*/
/mob/living/proc/handle_micro_bump_helping(mob/living/tmob)
+ //Riding and being moved to us or something similar
+ if(tmob in buckled_mobs)
+ return TRUE
+
//Both small! Go ahead and go.
if(get_effective_size() <= RESIZE_A_SMALLTINY && tmob.get_effective_size() <= RESIZE_A_SMALLTINY)
return TRUE
@@ -214,6 +218,10 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2
if(!canmove || buckled)
return
+ //Riding and being moved to us or something similar
+ if(tmob in buckled_mobs)
+ return TRUE
+
//Test/set if human
var/mob/living/carbon/human/pred = src
if(!istype(pred))
diff --git a/code/modules/xenobio2/machinery/core_extractor.dm b/code/modules/xenobio2/machinery/core_extractor.dm
index 1a23dcd758..01068e4cd1 100644
--- a/code/modules/xenobio2/machinery/core_extractor.dm
+++ b/code/modules/xenobio2/machinery/core_extractor.dm
@@ -18,16 +18,10 @@
var/operatingcolor = "#FFFF22"
-/obj/machinery/slime/extractor/New()
- ..()
+/obj/machinery/slime/extractor/Initialize()
+ . = ..()
+ default_apply_parts()
update_light_color()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- RefreshParts()
/obj/machinery/slime/extractor/attackby(var/obj/item/W, var/mob/user)
diff --git a/code/modules/xenobio2/machinery/gene_manipulators.dm b/code/modules/xenobio2/machinery/gene_manipulators.dm
index 761a2a98d4..91ff77fc94 100644
--- a/code/modules/xenobio2/machinery/gene_manipulators.dm
+++ b/code/modules/xenobio2/machinery/gene_manipulators.dm
@@ -123,17 +123,10 @@
var/datum/xeno/traits/genetics // Currently scanned xeno genetic structure.
var/degradation = 0 // Increments with each scan, stops allowing gene mods after a certain point.
-/obj/machinery/xenobio/extractor/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- RefreshParts()
-
+/obj/machinery/xenobio/extractor/Initialize()
+ . = ..()
+ default_apply_parts()
+
/obj/machinery/xenobio/extractor/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W,/obj/item/xenoproduct))
if(product)
@@ -265,16 +258,9 @@
var/mob/living/simple_mob/xeno/slime/occupant
-/obj/machinery/xenobio/editor/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
- RefreshParts()
+/obj/machinery/xenobio/editor/Initialize()
+ . = ..()
+ default_apply_parts()
/obj/machinery/xenobio/editor/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W,/obj/item/weapon/grab))
diff --git a/code/modules/xenobio2/machinery/injector.dm b/code/modules/xenobio2/machinery/injector.dm
index 59dfbf69c6..2c0454a8e2 100644
--- a/code/modules/xenobio2/machinery/injector.dm
+++ b/code/modules/xenobio2/machinery/injector.dm
@@ -19,18 +19,13 @@
circuit = /obj/item/weapon/circuitboard/xenobioinjectormachine
-/obj/machinery/xenobio2/manualinjector/New()
- ..()
+/obj/machinery/xenobio2/manualinjector/Initialize()
+ . = ..()
var/datum/reagents/R = new/datum/reagents(1000)
reagents = R
R.my_atom = src
beaker = new /obj/item/weapon/reagent_containers/glass/beaker(src)
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- RefreshParts()
+ default_apply_parts()
/obj/machinery/xenobio2/manualinjector/update_icon()
if(beaker)
diff --git a/code/modules/xenobio2/machinery/slime_replicator.dm b/code/modules/xenobio2/machinery/slime_replicator.dm
index 4d45d6ca2a..b5e49b7c62 100644
--- a/code/modules/xenobio2/machinery/slime_replicator.dm
+++ b/code/modules/xenobio2/machinery/slime_replicator.dm
@@ -17,17 +17,11 @@
var/emptycolor = "#FF2222"
var/operatingcolor = "#FFFF22"
-/obj/machinery/slime/replicator/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- RefreshParts()
+/obj/machinery/slime/replicator/Initialize()
+ . = ..()
+ default_apply_parts()
update_light_color()
-
/obj/machinery/slime/replicator/attackby(var/obj/item/W, var/mob/user)
//Let's try to deconstruct first.
if(W.is_screwdriver() && !inuse)
diff --git a/config/example/config.txt b/config/example/config.txt
index cf7be2756f..ff0340bcea 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -531,4 +531,7 @@ SQLITE_FEEDBACK_MIN_AGE 7
#DISABLE_CID_WARN_POPUP
## Comment this out if you don't want to use the 'nightshift lighting' subsystem to adjust lights based on ingame time
-ENABLE_NIGHT_SHIFTS
\ No newline at end of file
+ENABLE_NIGHT_SHIFTS
+
+## Comment this out to enable playtime restrictions for jobs in their respective departments (mostly for heads)
+# USE_PLAYTIME_RESTRICTION_FOR_JOBS
\ No newline at end of file
diff --git a/html/changelogs/atermonera_multilingual_pref.yml b/html/changelogs/atermonera_multilingual_pref.yml
new file mode 100644
index 0000000000..84552b9a13
--- /dev/null
+++ b/html/changelogs/atermonera_multilingual_pref.yml
@@ -0,0 +1,11 @@
+author: Atermonera
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Added a preference to control multilingual parsing behaviour, with a few different modes. Should hopefully be less punishing to people who stutter and use hyphens as a language key."
+ - tweak: "The examine mode preference should now persist across reconnections during a single round, but if the server is fully restarted it still appears to reset. This issue is also present for the multilingual preference, and I'm still looking into it. Savefiles are crpytic."
diff --git a/html/changelogs/atlantiscze-sm.yml b/html/changelogs/atlantiscze-sm.yml
new file mode 100644
index 0000000000..d6d8ddbfcf
--- /dev/null
+++ b/html/changelogs/atlantiscze-sm.yml
@@ -0,0 +1,6 @@
+author: atlantiscze
+
+delete-after: True
+
+changes:
+ - tweak: "Supermatter delamination effects have been tweaked. Delamination is considerably less laggy, and less directly destructive. Instead, it causes larger health hazard and secondary engineering problems such as power outage or partial damage of solar arrays."
\ No newline at end of file
diff --git a/icons/misc/pic_in_pic.dmi b/icons/misc/pic_in_pic.dmi
new file mode 100644
index 0000000000..cdac129513
Binary files /dev/null and b/icons/misc/pic_in_pic.dmi differ
diff --git a/icons/mob/chronos_mob_vr.dmi b/icons/mob/chronos_mob_vr.dmi
new file mode 100644
index 0000000000..06b1ca6686
Binary files /dev/null and b/icons/mob/chronos_mob_vr.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 4bfb8bf479..f192f80d1d 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/mob/screen_ai.dmi b/icons/mob/screen_ai.dmi
index ad813aad75..ce12203c7c 100644
Binary files a/icons/mob/screen_ai.dmi and b/icons/mob/screen_ai.dmi differ
diff --git a/icons/mob/species/seromi/suit.dmi b/icons/mob/species/seromi/suit.dmi
index d10902a6ff..726fb11a8a 100644
Binary files a/icons/mob/species/seromi/suit.dmi and b/icons/mob/species/seromi/suit.dmi differ
diff --git a/icons/mob/species/vulpkanin/helmet.dmi b/icons/mob/species/vulpkanin/helmet.dmi
index 47d3fd12ab..b1490dec6d 100644
Binary files a/icons/mob/species/vulpkanin/helmet.dmi and b/icons/mob/species/vulpkanin/helmet.dmi differ
diff --git a/icons/mob/species/vulpkanin/suit.dmi b/icons/mob/species/vulpkanin/suit.dmi
index 452c1fca56..c70734d3ae 100644
Binary files a/icons/mob/species/vulpkanin/suit.dmi and b/icons/mob/species/vulpkanin/suit.dmi differ
diff --git a/icons/mob/vore/ears_vr.dmi b/icons/mob/vore/ears_vr.dmi
index c2f4bcbd98..cd9c9f1492 100644
Binary files a/icons/mob/vore/ears_vr.dmi and b/icons/mob/vore/ears_vr.dmi differ
diff --git a/icons/mob/vore/tails_vr.dmi b/icons/mob/vore/tails_vr.dmi
index 9bb4bf0dd3..9ba6850f30 100644
Binary files a/icons/mob/vore/tails_vr.dmi and b/icons/mob/vore/tails_vr.dmi differ
diff --git a/icons/obj/butts_vr.dmi b/icons/obj/butts_vr.dmi
new file mode 100644
index 0000000000..104906120d
Binary files /dev/null and b/icons/obj/butts_vr.dmi differ
diff --git a/icons/obj/chronos_vr.dmi b/icons/obj/chronos_vr.dmi
new file mode 100644
index 0000000000..e544110b5d
Binary files /dev/null and b/icons/obj/chronos_vr.dmi differ
diff --git a/icons/obj/decals_vr.dmi b/icons/obj/decals_vr.dmi
index 6b05d6a003..391d37b918 100644
Binary files a/icons/obj/decals_vr.dmi and b/icons/obj/decals_vr.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index ba795e6576..606e8dbfe8 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/stationobjs_vr.dmi b/icons/obj/stationobjs_vr.dmi
index 3438e97b9f..5801c5302d 100644
Binary files a/icons/obj/stationobjs_vr.dmi and b/icons/obj/stationobjs_vr.dmi differ
diff --git a/icons/turf/areas.dmi b/icons/turf/areas.dmi
index 1132fa10a9..72a49c07c7 100644
Binary files a/icons/turf/areas.dmi and b/icons/turf/areas.dmi differ
diff --git a/icons/turf/outdoors.dmi b/icons/turf/outdoors.dmi
index b8af78d986..8bcc4308f6 100644
Binary files a/icons/turf/outdoors.dmi and b/icons/turf/outdoors.dmi differ
diff --git a/maps/southern_cross/southern_cross-1.dmm b/maps/southern_cross/southern_cross-1.dmm
index da2ec6cd40..cb8e5deb27 100644
--- a/maps/southern_cross/southern_cross-1.dmm
+++ b/maps/southern_cross/southern_cross-1.dmm
@@ -8865,6 +8865,7 @@
"doy" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/machinery/newscaster{pixel_y = -30},/turf/simulated/floor/wood,/area/library)
"doz" = (/obj/machinery/firealarm{dir = 1; pixel_x = 0; pixel_y = -24},/turf/simulated/floor/carpet,/area/library)
"doA" = (/obj/structure/bed/chair/office/dark{dir = 1},/turf/simulated/floor/carpet,/area/library)
+"doB" = (/obj/effect/shuttle_landmark{landmark_tag = "response_ship_thirddeck"; name = "SC Near Deck 3 NE"},/turf/space,/area/shuttle/response_ship/thirddeck)
"doC" = (/obj/item/weapon/circuitboard/firealarm,/turf/simulated/floor/tiled/freezer,/area/construction/seconddeck/construction2)
"doD" = (/obj/item/frame/light,/turf/simulated/floor/tiled/freezer,/area/construction/seconddeck/construction2)
"doE" = (/turf/simulated/floor/tiled/freezer,/area/construction/seconddeck/construction2)
@@ -11629,7 +11630,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadaaaaaaaaaaafaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaadaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadAVaaaaaaaaaaafaaaaaaaaaaafaaaaaaaaadAVbjTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaadAVdAVdAVdAVdAVaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaafbfGaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaagaaaaaaaaaaaaaaaaaadAWdAWdAWdAWdAWdAWdAWdAWdAWdAWdAWaaaaaaaaaaaaaaaaaaaaaaaadAVaaaaaaaaaaafaaaaaaaaaaafaaaaaaaaadAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaadAVdAVdAVdAVdAVaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaadaaaaaaaadaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaadaaaaaaaaaaaaaaaaaadAWdAWdAWdAWdAWdAWdAWdAWdAWdAWdAWdAWaaaaaaaaaaaaaaaaaadAXdAXdAXaafaafaafaaaaaaaaaaafaafaafdAXdAXdAXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaafaafaafaafdAVdAVdAVdAVdAVaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaafaadaafabcaadaafaafaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaafaafaafaadaaaaaaaaaaaaaaaaaadAWdAWdAWdAWdAWdAWdAWdAWdAYdAWdAWdAWaaaaaaaaaaaaaaaaaadAVdAVdAVaaaaaaaafaaaaaaaaaaafaaaaaadAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaafaafaafaafdAVdAVdAVdAVdAVaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaafaadaafabcaadaafaafaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaafaafaafaadaaaaaaaaaaaaaaaaaadAWdAWdAWdAWdAWdAWdAWdAWdAYdAWdoBdAWaaaaaaaaaaaaaaaaaadAVdAVdAVaaaaaaaafaaaaaaaaaaafaaaaaadAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaadAVdAVdAVdAVdAVaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaafaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAZdAZdAZdAZdAZdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaadaaaaaaaaaaaaaaaaaadAWdAWdAWdAWdAWdAWdAWdAWdAWdAWdAWdAWaaaaaaaaaaaaaaaaaadAXdAXdAXaafaafaafaaaaaaaaaaafaafaafdAXdAXdAXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaafaaaaafaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaafaaaaaaaabaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAZdAZdAZdAZdAZdBadBadBadAZdAZdAZdAZdAZdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadAWdAWdAWdAWdAWdAWdAWdAWdAWdAWdAWaaaaaaaaaaaaaaaaaaaaaaaadAVaaaaaaaaaaafaaaaaaaaaaafaaaaaaaaadAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaadAVdAVdAVdAVdAVaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaafaaaaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAZdBadBadBadAVdAVdAVdAVdAVdBadBadBadAZdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadAVaaaaaaaaaaafaaaaaaaaaaafaaaaaaaaadAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/maps/submaps/surface_submaps/wilderness/DecoupledEngine.dmm b/maps/submaps/surface_submaps/wilderness/DecoupledEngine.dmm
index 840f2055c4..15a2bf604f 100644
--- a/maps/submaps/surface_submaps/wilderness/DecoupledEngine.dmm
+++ b/maps/submaps/surface_submaps/wilderness/DecoupledEngine.dmm
@@ -9,7 +9,6 @@
"ai" = (/obj/item/stack/material/steel,/turf/template_noop,/area/submap/DecoupledEngine)
"aj" = (/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
"ak" = (/obj/structure/lattice,/obj/structure/girder/displaced,/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
-"al" = (/obj/item/projectile/bullet/magnetic/fuelrod,/turf/template_noop,/area/submap/DecoupledEngine)
"am" = (/obj/item/weapon/arrow/rod,/turf/template_noop,/area/submap/DecoupledEngine)
"an" = (/turf/simulated/floor/water,/area/submap/DecoupledEngine)
"ao" = (/obj/structure/lattice,/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
@@ -23,10 +22,9 @@
"aw" = (/obj/structure/girder,/obj/item/stack/material/steel,/turf/simulated/floor,/area/submap/DecoupledEngine)
"ax" = (/obj/structure/lattice,/obj/structure/grille/broken,/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
"ay" = (/obj/effect/floor_decal/rust,/obj/item/stack/material/steel,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"az" = (/obj/machinery/atmospherics/pipe/simple/visible{ icon_state = "intact"; dir = 6},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
+"az" = (/obj/machinery/atmospherics/pipe/simple/visible{icon_state = "intact"; dir = 6},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aA" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aB" = (/obj/structure/shuttle/engine/heater{icon_state = "heater"; dir = 4},/obj/effect/floor_decal/rust,/obj/effect/decal/cleanable/cobweb2,/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor,/area/submap/DecoupledEngine)
-"aC" = (/obj/structure/shuttle/engine/propulsion{ icon_state = "propulsion_r"; dir = 4},/turf/simulated/floor/water,/area/submap/DecoupledEngine)
"aD" = (/obj/structure/lattice,/obj/structure/grille,/turf/template_noop,/area/submap/DecoupledEngine)
"aE" = (/obj/structure/lattice,/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/template_noop,/area/submap/DecoupledEngine)
"aF" = (/obj/structure/sign/warning/radioactive{dir = 8},/turf/simulated/wall/durasteel,/area/submap/DecoupledEngine)
@@ -35,7 +33,7 @@
"aI" = (/obj/effect/decal/cleanable/blood/oil/streak{amount = 0},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aJ" = (/obj/machinery/power/rad_collector,/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor,/area/submap/DecoupledEngine)
"aK" = (/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/turf/simulated/floor,/area/submap/DecoupledEngine)
-"aL" = (/obj/structure/grille/broken,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 4},/obj/item/weapon/material/shard/phoron,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
+"aL" = (/obj/structure/grille/broken,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/item/weapon/material/shard/phoron,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aM" = (/obj/machinery/atmospherics/pipe/manifold4w/visible,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aN" = (/obj/structure/shuttle/engine/heater{icon_state = "heater"; dir = 4},/obj/effect/floor_decal/rust,/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor,/area/submap/DecoupledEngine)
"aO" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_r"; dir = 4},/turf/simulated/floor/water,/area/submap/DecoupledEngine)
@@ -45,8 +43,8 @@
"aS" = (/obj/structure/closet/crate/oldreactor{anchored = 1},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aT" = (/obj/item/poi/brokenoldreactor{anchored = 1},/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor,/area/submap/DecoupledEngine)
"aU" = (/obj/machinery/atmospherics/pipe/simple/visible,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"aV" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor,/area/submap/DecoupledEngine)
-"aW" = (/obj/machinery/atmospherics/pipe/simple/visible{ icon_state = "intact"; dir = 5},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
+"aV" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor,/area/submap/DecoupledEngine)
+"aW" = (/obj/machinery/atmospherics/pipe/simple/visible{icon_state = "intact"; dir = 5},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aX" = (/obj/structure/shuttle/engine/router,/turf/simulated/floor,/area/submap/DecoupledEngine)
"aY" = (/obj/structure/shuttle/engine/propulsion{dir = 4},/turf/simulated/floor/water,/area/submap/DecoupledEngine)
"aZ" = (/obj/item/stack/material/steel,/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
@@ -54,22 +52,22 @@
"bb" = (/obj/structure/lattice,/obj/structure/grille,/obj/structure/window/reinforced{dir = 2; health = 1e+006},/turf/template_noop,/area/submap/DecoupledEngine)
"bc" = (/obj/structure/lattice,/obj/structure/grille,/obj/structure/window/reinforced{dir = 2; health = 1e+006},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1; health = 1e+006},/turf/template_noop,/area/submap/DecoupledEngine)
"bd" = (/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"be" = (/obj/machinery/power/rad_collector,/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 8},/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{dir = 10},/turf/simulated/floor,/area/submap/DecoupledEngine)
+"be" = (/obj/machinery/power/rad_collector,/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{dir = 10},/turf/simulated/floor,/area/submap/DecoupledEngine)
"bf" = (/obj/machinery/power/rad_collector,/obj/structure/window/phoronreinforced,/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"bg" = (/obj/machinery/power/rad_collector,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced,/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor,/area/submap/DecoupledEngine)
+"bg" = (/obj/machinery/power/rad_collector,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced,/obj/effect/floor_decal/rust,/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor,/area/submap/DecoupledEngine)
"bh" = (/obj/structure/shuttle/engine/propulsion{dir = 4},/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
"bi" = (/obj/machinery/atmospherics/tvalve/digital{dir = 8},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"bj" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"bk" = (/obj/machinery/atmospherics/pipe/manifold/visible,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"bl" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/obj/structure/grille,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor,/area/submap/DecoupledEngine)
+"bl" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/obj/structure/grille,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor,/area/submap/DecoupledEngine)
"bm" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_l"; dir = 4},/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
"bn" = (/obj/effect/floor_decal/rust,/obj/structure/closet/crate/radiation,/turf/simulated/floor,/area/submap/DecoupledEngine)
"bo" = (/obj/effect/decal/cleanable/blood/oil,/obj/effect/floor_decal/rust,/turf/simulated/floor,/area/submap/DecoupledEngine)
"bp" = (/obj/effect/floor_decal/rust,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/rcd,/turf/simulated/floor,/area/submap/DecoupledEngine)
"bq" = (/obj/structure/sign/warning/radioactive,/turf/simulated/wall/durasteel,/area/submap/DecoupledEngine)
-"br" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"bs" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced,/turf/simulated/floor,/area/submap/DecoupledEngine)
-"bt" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced,/turf/simulated/floor,/area/submap/DecoupledEngine)
+"br" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced,/turf/simulated/floor,/area/submap/DecoupledEngine)
+"bs" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced,/turf/simulated/floor,/area/submap/DecoupledEngine)
+"bt" = (/obj/structure/grille,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced,/turf/simulated/floor,/area/submap/DecoupledEngine)
"bu" = (/obj/structure/sign/poi/engineleft,/turf/simulated/wall/durasteel,/area/submap/DecoupledEngine)
"bv" = (/obj/structure/sign/poi/engineright,/turf/simulated/wall/r_wall,/area/submap/DecoupledEngine)
"bw" = (/obj/structure/girder,/turf/simulated/floor/outdoors/rocks,/area/submap/DecoupledEngine)
@@ -86,12 +84,12 @@ aaababababababababababadababababacababababababababababababaa
aaababafabababababababababababababababababababababababababaa
aaabababababababababababababagababababababababababababababaa
aaabababababadabahabababababababababaiabababababababababajaa
-aaababababababakababababababababababalababababababababababaa
+aaababababababakababababababababababacababababababababababaa
aaababababababababababababababababababababababababajabajabaa
aaabababaiababababababababababafababababamabajabajababababaa
aaabababababacabababababababajajabababababajanajajajabadabaa
aaabadabafababaoaoaoaoacabaoapaqaqarasatatanananajababababaa
-aaamababababauavavavawaxaoapayaqazaAaBaCanananajabababababaa
+aaamababababauavavavawaxaoapayaqazaAaBaOanananajabababababaa
aaababauauaDaEaFaGaHaIaJaoaKaIaLaMaAaNaOananajajabababababaa
aaababababaPaPaQaPaPaPaRaSaTaUaVaWaNaXaYanajajababababababaa
aaababaZbabbbcavbdbdaPbebfbgaUaVazaNaXbhajajabadabajabababaa
diff --git a/maps/tether/submaps/aerostat/submaps/DecoupledEngine.dmm b/maps/tether/submaps/aerostat/submaps/DecoupledEngine.dmm
index 322dbbf62e..03044d8196 100644
--- a/maps/tether/submaps/aerostat/submaps/DecoupledEngine.dmm
+++ b/maps/tether/submaps/aerostat/submaps/DecoupledEngine.dmm
@@ -42,8 +42,9 @@
/turf/simulated/floor/outdoors/rocks,
/area/submap/virgo2/DecoupledEngine)
"al" = (
-/obj/item/projectile/bullet/magnetic/fuelrod,
-/turf/simulated/mineral/floor/ignore_mapgen/virgo2,
+/obj/effect/floor_decal/rust,
+/obj/item/weapon/fuel_assembly/supermatter,
+/turf/simulated/floor,
/area/submap/virgo2/DecoupledEngine)
"am" = (
/obj/item/weapon/arrow/rod,
@@ -336,11 +337,6 @@
/obj/effect/floor_decal/rust,
/turf/simulated/floor,
/area/submap/virgo2/DecoupledEngine)
-"be" = (
-/obj/effect/floor_decal/rust,
-/obj/item/projectile/bullet/magnetic/fuelrod,
-/turf/simulated/floor,
-/area/submap/virgo2/DecoupledEngine)
"bf" = (
/obj/machinery/power/rad_collector,
/obj/structure/window/phoronreinforced,
@@ -865,7 +861,7 @@ ao
aw
aI
aP
-be
+al
aA
av
br
@@ -1113,7 +1109,7 @@ ab
ab
ad
ai
-al
+bB
ad
ad
ad
diff --git a/maps/tether/submaps/offmap/talon2.dmm b/maps/tether/submaps/offmap/talon2.dmm
index e23d847942..86b9c3669f 100644
--- a/maps/tether/submaps/offmap/talon2.dmm
+++ b/maps/tether/submaps/offmap/talon2.dmm
@@ -2049,7 +2049,9 @@
/obj/effect/floor_decal/borderfloor/corner2{
dir = 1
},
-/obj/machinery/computer/ship/helm,
+/obj/machinery/computer/ship/helm{
+ req_one_access = list(301)
+ },
/turf/simulated/floor/tiled/steel,
/area/talon/decktwo/tech)
"dD" = (
diff --git a/maps/tether/submaps/tether_misc.dmm b/maps/tether/submaps/tether_misc.dmm
index e4aaa7a057..a3b97d1337 100644
--- a/maps/tether/submaps/tether_misc.dmm
+++ b/maps/tether/submaps/tether_misc.dmm
@@ -588,6 +588,10 @@
/turf/simulated/floor/holofloor/wood,
/area/holodeck/source_courtroom)
"bN" = (
+/obj/effect/landmark/ai_multicam_room,
+/turf/unsimulated/ai_visible,
+/area/ai_multicam_room)
+"bO" = (
/obj/structure/shuttle/engine/propulsion{
icon_state = "burst_l"
},
@@ -596,21 +600,8 @@
dir = 1
},
/area/shuttle/supply)
-"bO" = (
-/obj/structure/shuttle/engine/propulsion,
-/turf/space,
-/turf/simulated/shuttle/plating/airless/carry{
- dir = 1
- },
-/area/shuttle/supply)
"bP" = (
/obj/structure/shuttle/engine/propulsion,
-/obj/effect/shuttle_landmark{
- base_area = /area/space;
- base_turf = /turf/space;
- landmark_tag = "supply_cc";
- name = "Centcom Supply Depot"
- },
/turf/space,
/turf/simulated/shuttle/plating/airless/carry{
dir = 1
@@ -642,8 +633,12 @@
/turf/simulated/floor/holofloor/desert,
/area/holodeck/source_picnicarea)
"bT" = (
-/obj/structure/shuttle/engine/propulsion{
- icon_state = "burst_r"
+/obj/structure/shuttle/engine/propulsion,
+/obj/effect/shuttle_landmark{
+ base_area = /area/space;
+ base_turf = /turf/space;
+ landmark_tag = "supply_cc";
+ name = "Centcom Supply Depot"
},
/turf/space,
/turf/simulated/shuttle/plating/airless/carry{
@@ -729,6 +724,9 @@
},
/turf/simulated/floor/holofloor/carpet,
/area/holodeck/source_courtroom)
+"cd" = (
+/turf/unsimulated/wall,
+/area/ai_multicam_room)
"ce" = (
/obj/effect/step_trigger/teleporter/planetary_fall/virgo3b,
/turf/space/transit/south,
@@ -752,6 +750,9 @@
},
/turf/space/transit/south,
/area/space)
+"ci" = (
+/turf/unsimulated/ai_visible,
+/area/ai_multicam_room)
"cj" = (
/obj/effect/floor_decal/industrial/warning{
icon_state = "warning";
@@ -759,6 +760,29 @@
},
/turf/simulated/floor/tiled/steel,
/area/space)
+"ck" = (
+/obj/structure/shuttle/engine/propulsion{
+ icon_state = "burst_r"
+ },
+/turf/space,
+/turf/simulated/shuttle/plating/airless/carry{
+ dir = 1
+ },
+/area/shuttle/supply)
+"cl" = (
+/obj/effect/step_trigger/teleporter/random{
+ affect_ghosts = 1;
+ name = "escapeshuttle_leave";
+ teleport_x = 25;
+ teleport_x_offset = 245;
+ teleport_y = 25;
+ teleport_y_offset = 245;
+ teleport_z = 4;
+ teleport_z_offset = 4
+ },
+/turf/space,
+/turf/space/transit/north,
+/area/space)
"cs" = (
/obj/machinery/door/airlock/glass_external{
frequency = 1380;
@@ -2191,20 +2215,6 @@
"Az" = (
/turf/unsimulated/beach/coastline,
/area/beach)
-"Bd" = (
-/obj/effect/step_trigger/teleporter/random{
- affect_ghosts = 1;
- name = "escapeshuttle_leave";
- teleport_x = 25;
- teleport_x_offset = 245;
- teleport_y = 25;
- teleport_y_offset = 245;
- teleport_z = 4;
- teleport_z_offset = 4
- },
-/turf/space,
-/turf/space/transit/north,
-/area/space)
"Bw" = (
/turf/unsimulated/beach/water,
/area/beach)
@@ -12798,25 +12808,25 @@ ap
ap
ap
ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
ap
ap
ap
@@ -12940,25 +12950,25 @@ ap
ap
ap
ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13082,25 +13092,25 @@ ap
ap
ap
ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13224,25 +13234,25 @@ ap
ap
ap
ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13366,25 +13376,25 @@ ap
ap
ap
ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13508,25 +13518,25 @@ ap
ap
ap
ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13650,25 +13660,25 @@ aI
aI
aI
ar
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13792,25 +13802,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -13934,25 +13944,25 @@ dF
ec
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14076,25 +14086,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+bN
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14218,25 +14228,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14360,25 +14370,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14437,10 +14447,10 @@ Jz
Jz
Jz
Jz
-Bd
-Bd
-Bd
-Bd
+cl
+cl
+cl
+cl
iO
El
El
@@ -14502,25 +14512,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14582,7 +14592,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -14644,25 +14654,25 @@ dF
ec
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14724,7 +14734,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -14786,25 +14796,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -14866,7 +14876,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -14928,25 +14938,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -15008,7 +15018,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -15070,25 +15080,25 @@ dF
dF
dF
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -15150,7 +15160,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -15212,25 +15222,25 @@ aL
aL
aL
ar
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+ci
+cd
ap
ap
ap
@@ -15292,7 +15302,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -15354,25 +15364,25 @@ fG
dG
dG
fZ
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
-ap
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
+cd
ap
ap
ap
@@ -15434,7 +15444,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -15576,7 +15586,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -15718,7 +15728,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -15860,7 +15870,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16002,7 +16012,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16144,7 +16154,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16286,7 +16296,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16428,7 +16438,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16570,7 +16580,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16712,7 +16722,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16854,7 +16864,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -16996,7 +17006,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -17138,7 +17148,7 @@ jf
Gs
Gs
Gs
-Bd
+cl
iO
El
El
@@ -17257,30 +17267,30 @@ ap
ap
ap
ap
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
-Bd
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
+cl
iO
El
El
@@ -20620,7 +20630,7 @@ di
by
bc
bc
-bN
+bO
aq
ae
ae
@@ -20762,7 +20772,7 @@ di
bn
bn
dE
-bO
+bP
aq
ae
ae
@@ -20904,7 +20914,7 @@ di
bn
bn
dE
-bP
+bT
aq
ae
ae
@@ -21046,7 +21056,7 @@ bn
bn
bn
dE
-bO
+bP
aq
ae
ae
@@ -21188,7 +21198,7 @@ bn
bz
bc
bc
-bT
+ck
aq
ae
ae
diff --git a/maps/tether/tether-01-surface1.dmm b/maps/tether/tether-01-surface1.dmm
index ba1c1625ce..caa717d6b7 100644
--- a/maps/tether/tether-01-surface1.dmm
+++ b/maps/tether/tether-01-surface1.dmm
@@ -53,16 +53,14 @@
name = "south bump";
pixel_y = -28
},
-/obj/structure/cable/green{
- d2 = 4;
- icon_state = "0-4"
+/obj/structure/cable{
+ icon_state = "0-4";
+ d2 = 4
},
/turf/simulated/floor/tiled/steel_dirty/virgo3b,
/area/tether/surfacebase/mining_main/external)
"aal" = (
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 8;
+/obj/structure/cable{
icon_state = "2-8"
},
/turf/simulated/floor/tiled/steel_dirty/virgo3b,
@@ -75,11 +73,6 @@
/turf/simulated/wall,
/area/tether/surfacebase/cargo/mining/airlock)
"aao" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/machinery/door/airlock/glass_external{
frequency = 1379;
icon_state = "door_locked";
@@ -87,6 +80,9 @@
locked = 1
},
/obj/effect/map_helper/airlock/door/ext_door,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/steel_grid,
/area/tether/surfacebase/cargo/mining/airlock)
"aap" = (
@@ -131,11 +127,6 @@
/obj/effect/floor_decal/industrial/warning{
dir = 8
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 4
},
@@ -153,9 +144,10 @@
pixel_x = -25;
pixel_y = 25
},
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 4;
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/structure/cable{
icon_state = "2-4"
},
/turf/simulated/floor/tiled,
@@ -181,7 +173,8 @@
name = "east bump";
pixel_x = 28
},
-/obj/structure/cable/green{
+/obj/structure/cable{
+ d2 = 8;
icon_state = "0-8"
},
/turf/simulated/floor/tiled,
@@ -200,11 +193,6 @@
/obj/effect/floor_decal/industrial/warning{
dir = 8
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/effect/floor_decal/steeldecal/steel_decals7{
dir = 6
},
@@ -214,6 +202,9 @@
/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{
dir = 4
},
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining/airlock)
"aax" = (
@@ -245,11 +236,6 @@
/obj/effect/floor_decal/industrial/warning{
dir = 8
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 5
},
@@ -262,6 +248,9 @@
/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{
dir = 4
},
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining/airlock)
"aaA" = (
@@ -294,11 +283,6 @@
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining/airlock)
"aaB" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/machinery/door/firedoor/glass,
/obj/machinery/door/airlock/glass_external{
frequency = 1379;
@@ -308,6 +292,9 @@
},
/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
/obj/effect/map_helper/airlock/door/int_door,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/steel_grid,
/area/tether/surfacebase/cargo/mining/airlock)
"aaC" = (
@@ -360,11 +347,6 @@
/obj/effect/floor_decal/corner/brown/bordercorner2{
dir = 8
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 4
},
@@ -375,6 +357,9 @@
dir = 6
},
/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
"aaH" = (
@@ -450,11 +435,6 @@
/obj/effect/floor_decal/corner/brown/border{
dir = 8
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
/obj/effect/floor_decal/steeldecal/steel_decals7{
dir = 5
},
@@ -462,6 +442,9 @@
dir = 6
},
/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
"aaN" = (
@@ -498,18 +481,24 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"aaP" = (
-/obj/machinery/door/airlock/glass_mining{
- name = "Warehouse"
+/obj/effect/floor_decal/borderfloor{
+ dir = 8
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
+/obj/effect/floor_decal/corner/brown/border{
+ dir = 8
+ },
+/obj/effect/floor_decal/steeldecal/steel_decals7{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/machinery/vending/wallmed_airlock{
+ pixel_x = -32
+ },
+/obj/structure/cable{
icon_state = "1-2"
},
-/turf/simulated/floor/tiled/steel_grid,
-/area/tether/surfacebase/cargo/warehouse)
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/mining)
"aaQ" = (
/obj/effect/floor_decal/borderfloor,
/obj/effect/floor_decal/corner/lightgrey/border,
@@ -606,6 +595,95 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
+"aaY" = (
+/obj/effect/floor_decal/borderfloor{
+ dir = 10
+ },
+/obj/effect/floor_decal/corner/brown/border{
+ dir = 10
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 6
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 6
+ },
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/mining)
+"aaZ" = (
+/obj/effect/floor_decal/borderfloor,
+/obj/effect/floor_decal/corner/brown/border,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/mining)
+"aba" = (
+/obj/effect/floor_decal/borderfloor/corner{
+ dir = 8
+ },
+/obj/effect/floor_decal/corner/brown/bordercorner{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
+ },
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/mining)
+"abb" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 10
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 10
+ },
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/mining)
+"abc" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/structure/catwalk,
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/machinery/door/airlock/maintenance/common{
+ name = "Mining Maintenance Access"
+ },
+/turf/simulated/floor/tiled/techfloor,
+/area/tether/surfacebase/cargo/mining)
"abd" = (
/obj/machinery/atmospherics/unary/vent_pump/on,
/obj/effect/floor_decal/borderfloor{
@@ -617,24 +695,26 @@
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
"abe" = (
-/obj/effect/floor_decal/borderfloor{
+/obj/machinery/light{
dir = 8
},
+/obj/effect/floor_decal/borderfloor{
+ dir = 10
+ },
/obj/effect/floor_decal/corner/brown/border{
- dir = 8
+ dir = 10
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/power/apc{
+ name = "south bump";
+ pixel_x = 0;
+ pixel_y = -32
},
-/obj/effect/floor_decal/steeldecal/steel_decals7{
- dir = 5
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
-/obj/machinery/vending/wallmed_airlock{
- pixel_x = -32
+/obj/machinery/light_switch{
+ dir = 1;
+ pixel_x = -13;
+ pixel_y = -30
},
+/obj/structure/cable,
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
"abf" = (
@@ -670,18 +750,18 @@
/turf/simulated/floor/tiled,
/area/rnd/hallway)
"abh" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 5
+ },
/obj/effect/floor_decal/borderfloor,
/obj/effect/floor_decal/corner/brown/border,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
@@ -704,40 +784,68 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
-"abl" = (
-/obj/effect/floor_decal/borderfloor/corner{
- dir = 8
- },
-/obj/effect/floor_decal/corner/brown/bordercorner{
- dir = 8
- },
+"abk" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
},
-/obj/structure/cable/green{
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/effect/floor_decal/borderfloor,
+/obj/effect/floor_decal/corner/brown/border,
+/obj/structure/cable{
d1 = 4;
d2 = 8;
- icon_state = "4-8"
+ icon_state = "4-8";
+ pixel_x = 0
},
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
-/obj/structure/cable/green{
- d1 = 2;
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/mining)
+"abl" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/effect/floor_decal/borderfloor,
+/obj/effect/floor_decal/corner/brown/border,
+/obj/structure/extinguisher_cabinet{
+ dir = 1;
+ icon_state = "extinguisher_closed";
+ pixel_y = -32
+ },
+/obj/structure/cable{
+ d1 = 4;
d2 = 8;
- icon_state = "2-8"
+ icon_state = "4-8";
+ pixel_x = 0
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
"abm" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 10
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 10
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply,
+/obj/effect/floor_decal/borderfloor,
+/obj/effect/floor_decal/corner/brown/border,
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 9
},
-/obj/structure/cable/green{
- d1 = 2;
+/obj/effect/floor_decal/corner/brown/bordercorner2{
+ dir = 9
+ },
+/obj/machinery/firealarm{
+ dir = 1;
+ pixel_x = 0;
+ pixel_y = -24
+ },
+/obj/structure/cable{
+ d1 = 4;
d2 = 8;
- icon_state = "2-8"
+ icon_state = "4-8";
+ pixel_x = 0
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
@@ -825,42 +933,39 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"abv" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/cargo{
- name = "Mining Maintenance Access";
- req_one_access = list(48)
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
-/obj/structure/catwalk,
-/turf/simulated/floor/tiled/techfloor,
+/obj/machinery/alarm{
+ dir = 1;
+ pixel_y = -25
+ },
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
+ },
+/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
"abw" = (
-/obj/machinery/light{
+/obj/effect/floor_decal/steeldecal/steel_decals4{
+ dir = 5
+ },
+/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 8
},
-/obj/effect/floor_decal/borderfloor{
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 10
},
-/obj/effect/floor_decal/corner/brown/border{
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 10
},
-/obj/machinery/power/apc{
- name = "south bump";
- pixel_x = 0;
- pixel_y = -32
- },
-/obj/structure/cable/green,
-/obj/machinery/light_switch{
- dir = 1;
- pixel_x = -13;
- pixel_y = -30
+/obj/structure/cable{
+ icon_state = "2-8"
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
@@ -1000,21 +1105,17 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"abI" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 5
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 5
- },
-/obj/structure/cable/green{
+/obj/structure/catwalk,
+/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/visible/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/structure/cable{
d1 = 1;
- d2 = 4;
- icon_state = "1-4"
+ d2 = 2;
+ icon_state = "1-2"
},
-/obj/effect/floor_decal/borderfloor,
-/obj/effect/floor_decal/corner/brown/border,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
"abJ" = (
/obj/structure/catwalk,
/obj/structure/cable{
@@ -1023,42 +1124,25 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"abK" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
+/obj/machinery/door/airlock/glass_mining{
+ name = "Warehouse"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable{
+ icon_state = "1-2"
},
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/effect/floor_decal/borderfloor,
-/obj/effect/floor_decal/corner/brown/border,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/turf/simulated/floor/tiled/steel_grid,
+/area/tether/surfacebase/cargo/warehouse)
"abL" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable{
+ icon_state = "0-2";
+ d2 = 2
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/effect/floor_decal/borderfloor,
-/obj/effect/floor_decal/corner/brown/border,
-/obj/structure/extinguisher_cabinet{
- dir = 1;
- icon_state = "extinguisher_closed";
- pixel_y = -32
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/turf/simulated/floor/plating,
+/area/construction/vacant_mining_ops)
"abM" = (
/obj/structure/catwalk,
/obj/random/junk,
@@ -1068,30 +1152,22 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"abN" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
+/obj/structure/catwalk,
+/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan{
+ dir = 9;
+ icon_state = "intact"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
dir = 4
},
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply,
-/obj/effect/floor_decal/borderfloor,
-/obj/effect/floor_decal/corner/brown/border,
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 9
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
},
-/obj/effect/floor_decal/corner/brown/bordercorner2{
- dir = 9
- },
-/obj/machinery/firealarm{
- dir = 1;
- pixel_x = 0;
- pixel_y = -24
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
"abO" = (
/obj/machinery/door/airlock/maintenance/common{
name = "Trash Pit Access";
@@ -1105,23 +1181,19 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"abP" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
+/obj/effect/floor_decal/steeldecal/steel_decals4{
+ dir = 9
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable{
+ icon_state = "1-2"
},
-/obj/machinery/alarm{
- dir = 1;
- pixel_y = -25
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/turf/simulated/floor/tiled/steel_dirty,
+/area/tether/surfacebase/cargo/warehouse)
"abQ" = (
/obj/structure/catwalk,
/obj/structure/cable{
@@ -1154,25 +1226,13 @@
/turf/simulated/wall,
/area/maintenance/lower/mining_eva)
"abU" = (
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 5
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable{
+ icon_state = "1-2"
},
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 8
- },
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 8;
- icon_state = "2-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 10
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 10
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/turf/simulated/floor/plating,
+/area/construction/vacant_mining_ops)
"abV" = (
/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 5
@@ -1182,6 +1242,17 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/mining)
+"abW" = (
+/obj/structure/catwalk,
+/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/visible/supply,
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
"abX" = (
/obj/structure/catwalk,
/obj/effect/decal/cleanable/dirt,
@@ -1220,19 +1291,16 @@
/turf/simulated/wall,
/area/tether/surfacebase/cargo/warehouse)
"acd" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 9
- },
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
+ },
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
"ace" = (
@@ -1273,18 +1341,12 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/mining_eva)
"ach" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
},
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 4;
- icon_state = "1-4"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
"aci" = (
@@ -1307,25 +1369,27 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/mining_eva)
"ack" = (
-/obj/structure/cable/green{
- d1 = 4;
+/obj/machinery/power/apc{
+ dir = 4;
+ name = "east bump";
+ pixel_x = 28
+ },
+/obj/structure/cable{
d2 = 8;
- icon_state = "4-8"
+ icon_state = "0-8"
},
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
"acl" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/maintenance/common,
+/obj/structure/cable{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 8
- },
-/turf/simulated/floor/tiled/steel_dirty,
-/area/tether/surfacebase/cargo/warehouse)
+/turf/simulated/floor/plating,
+/area/tether/surfacebase/cargo)
"acm" = (
/obj/structure/window/reinforced,
/obj/structure/closet/crate,
@@ -1445,15 +1509,28 @@
/turf/simulated/floor/tiled,
/area/crew_quarters/visitor_laundry)
"acx" = (
-/obj/structure/cable/green{
- icon_state = "1-4"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+/obj/structure/catwalk,
+/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{
dir = 5
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+/obj/machinery/atmospherics/pipe/simple/visible/supply{
dir = 5
},
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
+"acy" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
+ dir = 8
+ },
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
"acz" = (
@@ -1469,15 +1546,101 @@
/obj/machinery/vending/loadout,
/turf/simulated/floor/tiled,
/area/crew_quarters/visitor_laundry)
-"acE" = (
-/obj/structure/cable/green{
- d2 = 8;
- icon_state = "0-8"
+"acA" = (
+/obj/effect/floor_decal/borderfloor{
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/brown/border{
+ dir = 1
},
/obj/machinery/power/apc{
- dir = 4;
- name = "east bump";
- pixel_x = 28
+ dir = 1;
+ name = "north bump";
+ pixel_x = 0;
+ pixel_y = 28
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/brown/bordercorner2{
+ dir = 1
+ },
+/obj/structure/cable{
+ icon_state = "0-2";
+ d2 = 2
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo)
+"acB" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/disposalpipe/segment{
+ dir = 2;
+ icon_state = "pipe-c"
+ },
+/obj/structure/window/reinforced{
+ dir = 8
+ },
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo)
+"acC" = (
+/obj/structure/table/rack,
+/obj/random/maintenance/cargo,
+/obj/random/maintenance/cargo,
+/obj/random/maintenance/clean,
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
+"acD" = (
+/obj/structure/catwalk,
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
+"acE" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 5
+ },
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
+ },
+/turf/simulated/floor/tiled/steel_dirty,
+/area/tether/surfacebase/cargo/warehouse)
+"acF" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
+ },
+/turf/simulated/floor/tiled/steel_dirty,
+/area/tether/surfacebase/cargo/warehouse)
+"acG" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
},
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
@@ -1487,6 +1650,27 @@
},
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
+"acI" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/shutters{
+ dir = 8;
+ id = "mine_warehouse";
+ name = "Warehouse Shutters"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8";
+ pixel_x = 0
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/warehouse)
"acJ" = (
/obj/effect/floor_decal/borderfloor,
/obj/effect/floor_decal/corner/lightgrey/border,
@@ -1534,16 +1718,16 @@
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
"acM" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/common,
-/turf/simulated/floor/plating,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
"acN" = (
/obj/structure/cable/ender{
@@ -1572,27 +1756,21 @@
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
"acP" = (
-/obj/effect/floor_decal/borderfloor{
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
dir = 1
},
-/obj/effect/floor_decal/corner/brown/border{
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
dir = 1
},
-/obj/machinery/power/apc{
- dir = 1;
- name = "north bump";
- pixel_x = 0;
- pixel_y = 28
+/obj/structure/disposalpipe/segment{
+ dir = 4;
+ icon_state = "pipe-c"
},
-/obj/structure/cable/green{
- d2 = 2;
- icon_state = "0-2"
+/obj/structure/cable{
+ icon_state = "2-8"
},
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 1
- },
-/obj/effect/floor_decal/corner/brown/bordercorner2{
- dir = 1
+/obj/structure/cable{
+ icon_state = "4-8"
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
@@ -1605,31 +1783,25 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/mining_eva)
"acR" = (
-/obj/effect/floor_decal/borderfloor{
- dir = 10
- },
-/obj/effect/floor_decal/corner/brown/border{
- dir = 10
- },
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 4;
- icon_state = "2-4"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 6
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 6
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
+ dir = 1
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 8;
+ icon_state = "1-8"
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
},
/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/mining)
+/area/tether/surfacebase/cargo)
"acS" = (
/obj/machinery/atmospherics/pipe/tank/air{
dir = 4
@@ -1778,6 +1950,21 @@
"adf" = (
/turf/simulated/wall,
/area/tether/surfacebase/cargo)
+"adg" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo)
"adh" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/structure/cable/green{
@@ -1850,6 +2037,21 @@
},
/turf/simulated/floor/plating,
/area/maintenance/lower/mining_eva)
+"adm" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo)
"adn" = (
/obj/effect/floor_decal/industrial/warning{
icon_state = "warning";
@@ -1874,65 +2076,64 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/mining_eva)
"adq" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
},
-/turf/simulated/floor/tiled/steel_dirty,
-/area/tether/surfacebase/cargo/warehouse)
-"adr" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
+/obj/structure/window/reinforced{
+ dir = 1
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/cable{
icon_state = "4-8"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
-/turf/simulated/floor/tiled/steel_dirty,
-/area/tether/surfacebase/cargo/warehouse)
-"ads" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/shutters{
- dir = 8;
- id = "mine_warehouse";
- name = "Warehouse Shutters"
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/warehouse)
-"adt" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
+"adr" = (
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
+ dir = 1
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/window/reinforced{
+ dir = 1
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo)
+"ads" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 9;
+ pixel_y = 0
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 9
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment,
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 8;
+ icon_state = "1-8"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo)
+"adt" = (
+/obj/machinery/space_heater,
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
"adu" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -1954,25 +2155,11 @@
/turf/simulated/floor/tiled,
/area/hallway/lower/first_west)
"adv" = (
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 8;
- icon_state = "2-8"
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 1
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 1
- },
-/obj/structure/disposalpipe/segment{
- dir = 4;
- icon_state = "pipe-c"
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/disposalpipe/segment,
+/obj/structure/cable{
+ icon_state = "1-2"
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
@@ -1986,24 +2173,24 @@
/turf/simulated/floor/plating,
/area/construction/vacant_mining_ops)
"ady" = (
-/obj/structure/cable/green{
- d2 = 2;
- icon_state = "0-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/turf/simulated/floor/plating,
-/area/construction/vacant_mining_ops)
+/obj/machinery/portable_atmospherics/powered/pump/filled,
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
"adz" = (
-/obj/structure/cable/green{
+/obj/structure/catwalk,
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable{
+ d1 = 2;
+ d2 = 4;
+ icon_state = "2-4"
+ },
+/obj/structure/cable{
d1 = 1;
d2 = 2;
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/turf/simulated/floor/plating,
-/area/construction/vacant_mining_ops)
+/turf/simulated/floor/tiled/techfloor,
+/area/maintenance/lower/mining_eva)
"adA" = (
/obj/structure/disposaloutlet{
dir = 8
@@ -2018,44 +2205,31 @@
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
"adB" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/effect/floor_decal/borderfloor,
+/obj/effect/floor_decal/corner/brown/border,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/structure/disposalpipe/segment{
- dir = 2;
- icon_state = "pipe-c"
- },
-/obj/structure/window/reinforced{
- dir = 8
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/disposalpipe/segment,
+/obj/structure/cable{
+ icon_state = "1-2"
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
"adC" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 8;
- icon_state = "1-8"
+/obj/machinery/door/airlock/glass_mining{
+ id_tag = "cargodoor";
+ name = "Cargo Office";
+ req_access = list(31);
+ req_one_access = list()
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 1
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/disposalpipe/segment,
+/obj/structure/cable{
+ icon_state = "1-2"
},
/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/area/tether/surfacebase/cargo/office)
"adD" = (
/obj/structure/disposalpipe/segment{
dir = 8;
@@ -2239,6 +2413,44 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
+"adQ" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/disposalpipe/segment,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/office)
+"adR" = (
+/obj/machinery/power/apc{
+ dir = 8;
+ name = "west bump";
+ pixel_x = -28
+ },
+/obj/structure/bed/chair/sofa/brown/left{
+ dir = 4
+ },
+/obj/effect/floor_decal/borderfloor{
+ dir = 8;
+ icon_state = "borderfloor";
+ pixel_x = 0
+ },
+/obj/effect/floor_decal/corner/brown/border{
+ dir = 8
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 8
+ },
+/obj/effect/floor_decal/corner/brown/bordercorner2{
+ dir = 8
+ },
+/obj/structure/cable{
+ icon_state = "0-4";
+ d2 = 4
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/cargo/office)
"adS" = (
/turf/simulated/floor/tiled/steel_dirty,
/area/tether/surfacebase/cargo/warehouse)
@@ -2252,22 +2464,11 @@
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo/warehouse)
"adU" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
+/obj/structure/cable{
icon_state = "4-8"
},
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/area/tether/surfacebase/cargo/office)
"adV" = (
/obj/structure/table/glass,
/obj/machinery/atmospherics/unary/vent_scrubber/on{
@@ -2366,62 +2567,62 @@
/turf/simulated/floor/tiled,
/area/tether/surfacebase/cargo)
"aea" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
+ dir = 5
},
/obj/structure/disposalpipe/segment{
- dir = 4
+ dir = 1;
+ icon_state = "pipe-c"
+ },
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 8;
+ icon_state = "1-8"
},
/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/area/tether/surfacebase/cargo/office)
"aeb" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
+/obj/structure/cable{
+ icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Atmospherics Substation"
},
-/obj/structure/window/reinforced{
- dir = 1
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
},
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/turf/simulated/floor/plating,
+/area/maintenance/substation/surface_atmos)
"aec" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/catwalk,
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Atmospherics";
+ req_access = list(24)
},
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 1
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
},
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 1
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/obj/structure/window/reinforced{
- dir = 1
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/turf/simulated/floor/plating,
+/area/engineering/atmos)
"aed" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -2477,23 +2678,25 @@
/turf/simulated/floor/plating,
/area/maintenance/lower/trash_pit)
"aej" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics Substation"
+ name = "Atmospherics";
+ req_access = list(24)
},
/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/door/blast/regular{
density = 0;
dir = 4;
icon_state = "pdoor0";
id = "atmoslockdown";
+ layer = 1;
name = "Atmospherics Lockdown";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor/plating,
-/area/maintenance/substation/surface_atmos)
+/area/engineering/atmos/processing)
"aek" = (
/obj/effect/floor_decal/techfloor,
/obj/structure/railing{
@@ -2567,24 +2770,23 @@
/turf/simulated/floor/tiled,
/area/hallway/lower/first_west)
"aer" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 8;
- icon_state = "1-8"
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Atmospherics";
+ req_access = list(24)
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 9;
- pixel_y = 0
+/obj/machinery/door/firedoor,
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 9
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/turf/simulated/floor/plating,
+/area/engineering/atmos)
"aes" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
@@ -2619,16 +2821,23 @@
/turf/simulated/floor/tiled,
/area/hallway/lower/first_west)
"aeu" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Atmospherics";
+ req_access = list(24)
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 1;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
+ },
+/obj/machinery/door/firedoor,
+/turf/simulated/floor/plating,
+/area/engineering/atmos/processing)
"aev" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
@@ -2661,9 +2870,6 @@
},
/turf/simulated/floor/tiled,
/area/hallway/lower/first_west)
-"aex" = (
-/turf/simulated/wall,
-/area/maintenance/substation/mining)
"aey" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -2833,23 +3039,6 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/north_stairs_one)
-"aeM" = (
-/obj/structure/catwalk,
-/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan{
- dir = 9;
- icon_state = "intact"
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 4
- },
-/turf/simulated/floor/tiled/techfloor,
-/area/maintenance/lower/mining_eva)
"aeN" = (
/obj/machinery/conveyor{
dir = 8;
@@ -2906,19 +3095,6 @@
dir = 8
},
/area/tether/surfacebase/surface_one_hall)
-"aeR" = (
-/obj/effect/floor_decal/borderfloor,
-/obj/effect/floor_decal/corner/brown/border,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo)
"aeS" = (
/obj/effect/floor_decal/borderfloor{
dir = 10
@@ -3092,23 +3268,6 @@
"afd" = (
/turf/simulated/floor/tiled/techfloor,
/area/maintenance/lower/mining_eva)
-"afe" = (
-/obj/machinery/door/airlock/glass_mining{
- id_tag = "cargodoor";
- name = "Cargo Office";
- req_access = list(31);
- req_one_access = list()
- },
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/office)
"aff" = (
/obj/machinery/door/firedoor/glass,
/obj/effect/floor_decal/steeldecal/steel_decals_central1{
@@ -3118,17 +3277,6 @@
dir = 4
},
/area/tether/surfacebase/cargo)
-"afg" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/office)
"afh" = (
/obj/effect/floor_decal/spline/plain{
dir = 4
@@ -3320,22 +3468,6 @@
/obj/machinery/lapvend,
/turf/simulated/floor/tiled,
/area/storage/primary)
-"afu" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 8;
- icon_state = "1-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 5
- },
-/obj/structure/disposalpipe/segment{
- dir = 1;
- icon_state = "pipe-c"
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/office)
"afv" = (
/obj/structure/closet/firecloset,
/turf/simulated/floor/tiled,
@@ -3661,12 +3793,6 @@
/obj/structure/table/standard,
/turf/simulated/floor/tiled,
/area/storage/primary)
-"afX" = (
-/obj/machinery/power/breakerbox/activated{
- RCon_tag = "Mining Substation Bypass"
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
"afY" = (
/obj/machinery/camera/network/civilian,
/turf/simulated/floor/tiled,
@@ -4049,18 +4175,6 @@
},
/turf/simulated/floor/tiled/white,
/area/rnd/chemistry_lab)
-"aha" = (
-/obj/structure/catwalk,
-/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/visible/supply,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
-/turf/simulated/floor/tiled/techfloor,
-/area/maintenance/lower/mining_eva)
"ahc" = (
/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary{
scrub_id = "atrium"
@@ -4710,25 +4824,6 @@
/obj/machinery/light/small,
/turf/simulated/floor/plating,
/area/storage/surface_eva)
-"aiB" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/catwalk,
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics";
- req_access = list(24)
- },
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos)
"aiD" = (
/obj/effect/floor_decal/borderfloor{
dir = 8
@@ -6154,17 +6249,6 @@
},
/turf/simulated/floor/tiled/techfloor,
/area/tether/surfacebase/public_garden)
-"alt" = (
-/obj/structure/catwalk,
-/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/visible/supply,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/turf/simulated/floor/tiled/techfloor,
-/area/maintenance/lower/mining_eva)
"alw" = (
/obj/effect/floor_decal/borderfloor{
dir = 10
@@ -6260,29 +6344,6 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/public_garden)
-"alC" = (
-/obj/structure/sign/securearea{
- desc = "A warning sign which reads 'HIGH VOLTAGE'";
- icon_state = "shock";
- name = "HIGH VOLTAGE"
- },
-/turf/simulated/wall,
-/area/maintenance/substation/mining)
-"alD" = (
-/obj/structure/catwalk,
-/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{
- dir = 5
- },
-/obj/machinery/atmospherics/pipe/simple/visible/supply{
- dir = 5
- },
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/turf/simulated/floor/tiled/techfloor,
-/area/maintenance/lower/mining_eva)
"alM" = (
/obj/effect/floor_decal/borderfloor{
dir = 10
@@ -6365,73 +6426,6 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/public_garden)
-"alS" = (
-/obj/machinery/power/sensor{
- name = "Powernet Sensor - Mining Subgrid";
- name_tag = "Mining Subgrid"
- },
-/obj/structure/cable/green{
- icon_state = "0-4"
- },
-/obj/structure/cable/green{
- d2 = 2;
- icon_state = "0-2"
- },
-/obj/effect/floor_decal/industrial/warning,
-/obj/random/drinkbottle,
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"alT" = (
-/obj/machinery/light/small{
- dir = 1
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/effect/floor_decal/industrial/warning/corner{
- dir = 8
- },
-/obj/effect/floor_decal/rust,
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"alU" = (
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 8;
- icon_state = "2-8"
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/effect/floor_decal/rust,
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"alV" = (
-/obj/machinery/door/airlock/engineering{
- name = "Mining Substation";
- req_one_access = list(11,24)
- },
-/obj/machinery/door/firedoor/glass,
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"alW" = (
-/obj/structure/catwalk,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 8;
- icon_state = "1-8"
- },
-/turf/simulated/floor/tiled/techfloor,
-/area/maintenance/lower/mining_eva)
"alX" = (
/obj/structure/railing{
dir = 8
@@ -6552,43 +6546,6 @@
},
/turf/simulated/floor/tiled,
/area/storage/primary)
-"amn" = (
-/obj/machinery/power/smes/buildable{
- charge = 0;
- output_attempt = 0;
- outputting = 0;
- RCon_tag = "Substation - Mining"
- },
-/obj/structure/cable/green,
-/obj/structure/cable/green{
- d2 = 2;
- icon_state = "0-2"
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"amo" = (
-/obj/effect/floor_decal/industrial/warning{
- dir = 8
- },
-/obj/machinery/power/terminal{
- dir = 8
- },
-/obj/structure/cable{
- icon_state = "0-2";
- d2 = 2
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"amp" = (
-/obj/machinery/power/apc{
- dir = 4;
- name = "east bump";
- pixel_x = 28
- },
-/obj/structure/cable/green,
-/obj/effect/floor_decal/rust,
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
"amq" = (
/obj/structure/railing{
dir = 8
@@ -6704,68 +6661,6 @@
},
/turf/simulated/floor/tiled,
/area/storage/primary)
-"amI" = (
-/obj/effect/floor_decal/industrial/warning/corner{
- dir = 1
- },
-/obj/structure/cable{
- d1 = 1;
- d2 = 4;
- icon_state = "1-4"
- },
-/obj/structure/cable{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8";
- pixel_x = 0
- },
-/obj/effect/floor_decal/industrial/warning{
- dir = 8
- },
-/obj/machinery/camera/network/engineering{
- dir = 1
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"amJ" = (
-/obj/structure/cable{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8";
- pixel_x = 0
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"amK" = (
-/obj/machinery/door/firedoor/glass,
-/obj/structure/cable{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8";
- pixel_x = 0
- },
-/obj/machinery/door/airlock/engineering{
- name = "Mining Substation";
- req_one_access = list(11,24)
- },
-/turf/simulated/floor,
-/area/maintenance/substation/mining)
-"amL" = (
-/obj/structure/catwalk,
-/obj/structure/cable{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8";
- pixel_x = 0
- },
-/obj/effect/decal/cleanable/dirt,
-/obj/structure/cable{
- d1 = 2;
- d2 = 4;
- icon_state = "2-4"
- },
-/turf/simulated/floor/tiled/techfloor,
-/area/maintenance/lower/mining_eva)
"amM" = (
/obj/structure/railing{
dir = 8
@@ -24019,24 +23914,6 @@
"aOR" = (
/turf/simulated/wall/r_wall,
/area/engineering/atmos/processing)
-"aOS" = (
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics";
- req_access = list(24)
- },
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos/processing)
"aOT" = (
/obj/effect/floor_decal/borderfloor{
dir = 8
@@ -26763,22 +26640,6 @@
},
/turf/simulated/floor/tiled/techmaint,
/area/engineering/atmos)
-"aTT" = (
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics";
- req_access = list(24)
- },
-/obj/machinery/door/firedoor,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos)
"aTU" = (
/obj/effect/floor_decal/steeldecal/steel_decals7{
dir = 6
@@ -27958,21 +27819,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/simulated/floor/plating,
/area/engineering/atmos/processing)
-"aVY" = (
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics";
- req_access = list(24)
- },
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 1;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos/processing)
"aVZ" = (
/obj/machinery/vending/boozeomat,
/turf/simulated/floor/wood,
@@ -30494,35 +30340,6 @@
},
/turf/simulated/floor/plating,
/area/tether/surfacebase/cargo/office)
-"bbs" = (
-/obj/machinery/power/apc{
- dir = 8;
- name = "west bump";
- pixel_x = -28
- },
-/obj/structure/cable/green{
- d2 = 4;
- icon_state = "0-4"
- },
-/obj/structure/bed/chair/sofa/brown/left{
- dir = 4
- },
-/obj/effect/floor_decal/borderfloor{
- dir = 8;
- icon_state = "borderfloor";
- pixel_x = 0
- },
-/obj/effect/floor_decal/corner/brown/border{
- dir = 8
- },
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 8
- },
-/obj/effect/floor_decal/corner/brown/bordercorner2{
- dir = 8
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/office)
"bbt" = (
/obj/effect/floor_decal/borderfloor{
dir = 5
@@ -30545,14 +30362,6 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/surface_one_hall)
-"bbv" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/cargo/office)
"bbw" = (
/obj/structure/table/rack,
/obj/random/maintenance/cargo,
@@ -31822,12 +31631,6 @@
/obj/random/trash_pile,
/turf/simulated/floor/plating,
/area/maintenance/lower/vacant_site)
-"obY" = (
-/obj/machinery/alarm{
- pixel_y = 22
- },
-/turf/simulated/floor/plating,
-/area/maintenance/substation/mining)
"orF" = (
/obj/machinery/light/small{
dir = 4;
@@ -31891,9 +31694,6 @@
},
/turf/simulated/floor/tiled/techmaint,
/area/looking_glass/lg_1)
-"vNx" = (
-/turf/simulated/floor/plating,
-/area/maintenance/substation/mining)
"xOH" = (
/obj/effect/floor_decal/spline/plain{
dir = 8
@@ -31909,11 +31709,6 @@
},
/turf/simulated/floor/tiled/techmaint,
/area/looking_glass/lg_1)
-"yiv" = (
-/obj/structure/closet/crate,
-/obj/random/maintenance/cargo,
-/turf/simulated/floor/plating,
-/area/maintenance/substation/mining)
(1,1,1) = {"
aaa
@@ -40241,7 +40036,7 @@ aLv
aJD
aJD
aJD
-aOS
+aej
aPm
aPN
aQr
@@ -41250,7 +41045,7 @@ aOR
aOR
aOR
aOR
-aVY
+aeu
aOR
aOR
aOR
@@ -41933,7 +41728,7 @@ aah
aah
aBO
aHd
-aej
+aeb
aIe
aIM
aJG
@@ -42031,12 +41826,12 @@ abT
abT
abT
abT
-aex
-aex
-aex
-aex
-aex
-aex
+abT
+abT
+abT
+abT
+abT
+abT
abT
abT
bbI
@@ -42173,12 +41968,12 @@ cGJ
acS
acS
adp
-aex
-yiv
-alS
-amn
-afX
-aex
+abT
+aah
+aah
+aah
+aah
+aah
aah
abT
bbJ
@@ -42315,12 +42110,12 @@ acj
acX
acX
adL
-aex
-vNx
-alT
-amo
-amI
-aex
+abT
+aah
+aah
+aah
+aah
+aah
aah
abT
bbI
@@ -42457,12 +42252,12 @@ acQ
adl
ado
adM
-aex
-obY
-alU
-amp
-amJ
-aex
+abT
+abT
+abT
+abT
+abT
+abT
aah
abT
bbI
@@ -42599,12 +42394,12 @@ aar
aar
abT
adN
-aex
-alC
-alV
-aex
-amK
-alC
+abT
+agd
+acC
+adt
+ady
+abT
abT
abT
bbI
@@ -42736,16 +42531,16 @@ aaz
aaB
aaG
aaM
-abe
-acR
-abv
-aha
-aeM
-alt
-alD
-alW
-afA
-amL
+aaP
+aaY
+abc
+abI
+abN
+abW
+acx
+acD
+acD
+adz
amW
amW
and
@@ -42879,7 +42674,7 @@ aaC
aaH
aaN
aaS
-abh
+aaZ
aar
abT
abT
@@ -43021,8 +42816,8 @@ aan
aar
aar
abi
-abl
-abw
+aba
+abe
abT
acg
abT
@@ -43070,7 +42865,7 @@ aFN
aGs
aHi
aHA
-aiB
+aec
aIT
aJL
aKu
@@ -43163,8 +42958,8 @@ aah
aah
aar
aaX
-abm
-abI
+abb
+abh
acc
acc
acc
@@ -43306,7 +43101,7 @@ aah
aar
aaX
agm
-abK
+abk
acc
abZ
abZ
@@ -43448,7 +43243,7 @@ aah
aar
aaX
agm
-abL
+abl
acc
adS
adS
@@ -43590,7 +43385,7 @@ aah
aar
abd
abn
-abN
+abm
acc
aca
adS
@@ -43658,7 +43453,7 @@ aRJ
aSe
aSO
aTr
-aTT
+aer
aTZ
aUE
aUE
@@ -43732,7 +43527,7 @@ aah
aar
aaX
agm
-abP
+abv
acc
adS
adS
@@ -43874,12 +43669,12 @@ aah
aar
aaX
agm
-abU
-aaP
+abw
+abK
+abP
acd
-ach
-acl
-acx
+acy
+acE
adS
afM
acc
@@ -44019,9 +43814,9 @@ abo
abV
abY
ace
-ack
+ach
acH
-adq
+acF
adS
aeJ
afm
@@ -44161,9 +43956,9 @@ aar
aar
acc
acf
-acE
+ack
acO
-adr
+acG
adS
agj
acc
@@ -44305,12 +44100,12 @@ acc
acc
acc
acc
-ads
+acI
adT
acc
amc
amP
-bbs
+adR
aHM
amc
aii
@@ -44447,12 +44242,12 @@ aaL
aaL
adf
acK
-adt
+acM
adZ
aeS
amw
afS
-bbv
+adU
bbC
amc
bbl
@@ -44589,12 +44384,12 @@ aaL
aaL
adf
acL
+acP
adv
-aeu
-aeR
-afe
-afg
-afu
+adB
+adC
+adQ
+aea
aeg
bbW
bbm
@@ -44730,8 +44525,8 @@ aaL
aaL
aaL
adf
-acP
-adC
+acA
+acR
aee
aeZ
amc
@@ -44873,7 +44668,7 @@ aaL
aaL
adf
afO
-adU
+adg
acY
acY
adE
@@ -45015,7 +44810,7 @@ aaL
aaL
adf
acU
-aea
+adm
aef
afb
amc
@@ -45157,7 +44952,7 @@ aaL
aaL
adf
aeE
-aeb
+adq
acY
aeU
amc
@@ -45299,7 +45094,7 @@ aaL
aaL
adf
adA
-aec
+adr
aes
aeY
afn
@@ -45437,11 +45232,11 @@ aaL
aaL
adw
adx
-ady
-adz
-acM
-adB
-aer
+abL
+abU
+acl
+acB
+ads
agq
acY
aff
diff --git a/maps/tether/tether-02-surface2.dmm b/maps/tether/tether-02-surface2.dmm
index 07208a4295..39011de5dd 100644
--- a/maps/tether/tether-02-surface2.dmm
+++ b/maps/tether/tether-02-surface2.dmm
@@ -2649,6 +2649,31 @@
},
/turf/simulated/floor/tiled/techfloor,
/area/maintenance/lower/bar)
+"afw" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/maintenance/command{
+ req_access = list(19)
+ },
+/obj/structure/disposalpipe/segment,
+/obj/structure/cable/green{
+ icon_state = "1-2";
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
+ },
+/turf/simulated/floor,
+/area/bridge_hallway)
"afx" = (
/obj/structure/catwalk,
/obj/structure/cable{
@@ -3154,6 +3179,33 @@
/obj/effect/floor_decal/industrial/outline/yellow,
/turf/simulated/floor/plating,
/area/maintenance/lower/bar)
+"agD" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/maintenance/command{
+ req_access = list(19)
+ },
+/obj/structure/cable/green{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 1;
+ icon_state = "pdoor0";
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
+ },
+/turf/simulated/floor,
+/area/bridge_hallway)
"agE" = (
/obj/structure/railing{
dir = 8
@@ -3298,6 +3350,30 @@
/obj/structure/catwalk,
/turf/simulated/floor/tiled/techfloor/grid,
/area/maintenance/lower/bar)
+"agX" = (
+/obj/structure/cable/cyan{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
+/obj/machinery/door/airlock/glass_atmos{
+ name = "Atmospherics";
+ req_access = list(24)
+ },
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
+ },
+/turf/simulated/floor/tiled,
+/area/engineering/lower/lobby)
"agY" = (
/obj/structure/sign/department/chapel,
/turf/simulated/wall,
@@ -3376,6 +3452,29 @@
},
/turf/simulated/floor/tiled/white,
/area/tether/surfacebase/medical/storage)
+"ahj" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/red,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/door/airlock/glass_atmos{
+ name = "Atmospherics";
+ req_access = list(24)
+ },
+/obj/structure/disposalpipe/segment,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
+ },
+/turf/simulated/floor/tiled,
+/area/engineering/lower/lobby)
"ahk" = (
/obj/structure/catwalk,
/obj/structure/disposalpipe/segment{
@@ -7876,27 +7975,26 @@
/turf/simulated/floor/tiled/techmaint,
/area/tether/surfacebase/surface_two_hall)
"apQ" = (
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Atmospherics";
+ req_access = list(24)
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/command{
- req_access = list(19)
- },
-/obj/structure/disposalpipe/segment,
-/obj/structure/cable/green{
- icon_state = "1-2";
- dir = 1
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/door/blast/regular{
density = 0;
- dir = 4;
+ dir = 1;
icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor,
-/area/bridge_hallway)
+/turf/simulated/floor/plating,
+/area/engineering/atmos)
"apR" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 9
@@ -9851,27 +9949,25 @@
/turf/simulated/floor/tiled,
/area/engineering/lower/lobby)
"atm" = (
-/obj/structure/cable/cyan{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
-/obj/machinery/door/airlock/glass_atmos{
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/door/airlock/maintenance/engi{
name = "Atmospherics";
req_access = list(24)
},
-/obj/machinery/door/firedoor/glass,
+/obj/structure/catwalk,
/obj/machinery/door/blast/regular{
density = 0;
dir = 4;
icon_state = "pdoor0";
id = "atmoslockdown";
+ layer = 1;
name = "Atmospherics Lockdown";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor/tiled,
-/area/engineering/lower/lobby)
+/turf/simulated/floor/plating,
+/area/engineering/atmos)
"atn" = (
/obj/structure/cable/cyan{
d1 = 4;
@@ -10833,25 +10929,29 @@
/turf/simulated/wall/r_wall,
/area/engineering/lower/lobby)
"avd" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/red,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/door/airlock/glass_atmos{
- name = "Atmospherics";
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Drone Bay";
req_access = list(24)
},
-/obj/structure/disposalpipe/segment,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
/obj/machinery/door/firedoor/glass,
/obj/machinery/door/blast/regular{
density = 0;
- dir = 4;
+ dir = 1;
icon_state = "pdoor0";
id = "atmoslockdown";
+ layer = 1;
name = "Atmospherics Lockdown";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor/tiled,
-/area/engineering/lower/lobby)
+/turf/simulated/floor/tiled/techfloor/grid,
+/area/engineering/drone_fabrication)
"ave" = (
/obj/effect/floor_decal/borderfloor{
dir = 1;
@@ -10990,6 +11090,25 @@
},
/turf/simulated/floor/plating,
/area/maintenance/lower/south)
+"avp" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Atmospherics Balcony";
+ req_access = list(24)
+ },
+/obj/structure/catwalk,
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 1;
+ icon_state = "pdoor0";
+ id = "atmoslockdown";
+ layer = 1;
+ name = "Atmospherics Lockdown";
+ opacity = 0;
+ open_layer = 1
+ },
+/turf/simulated/floor/plating,
+/area/engineering/atmos)
"avq" = (
/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
@@ -15739,25 +15858,6 @@
/obj/structure/catwalk,
/turf/simulated/floor/plating,
/area/maintenance/asmaint2)
-"aCY" = (
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics";
- req_access = list(24)
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 1;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos)
"aCZ" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -16646,24 +16746,6 @@
/obj/random/tech_supply,
/turf/simulated/floor/tiled/steel_dirty,
/area/maintenance/asmaint2)
-"aFa" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics";
- req_access = list(24)
- },
-/obj/structure/catwalk,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos)
"aFb" = (
/obj/structure/catwalk,
/turf/simulated/open,
@@ -24932,30 +25014,6 @@
/obj/structure/bed/padded,
/turf/simulated/floor/tiled,
/area/tether/surfacebase/security/solitary)
-"aTK" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/command{
- req_access = list(19)
- },
-/obj/structure/cable/green{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 1;
- icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
- },
-/turf/simulated/floor,
-/area/bridge_hallway)
"aTL" = (
/obj/structure/cable/green{
icon_state = "4-8"
@@ -26591,28 +26649,6 @@
},
/turf/simulated/floor/tiled/dark,
/area/tether/surfacebase/security/brig)
-"aVV" = (
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Drone Bay";
- req_access = list(24)
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 1;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/tiled/techfloor/grid,
-/area/engineering/drone_fabrication)
"aVW" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -27236,23 +27272,6 @@
},
/turf/simulated/floor/reinforced,
/area/rnd/outpost/xenobiology/outpost_slimepens)
-"aWN" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Atmospherics Balcony";
- req_access = list(24)
- },
-/obj/structure/catwalk,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 1;
- icon_state = "pdoor0";
- id = "atmoslockdown";
- name = "Atmospherics Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/plating,
-/area/engineering/atmos)
"aWO" = (
/obj/machinery/atmospherics/pipe/simple/hidden/green{
icon_state = "intact";
@@ -38423,7 +38442,7 @@ auk
aAT
aAT
aAT
-aVV
+avd
aAT
aAT
aAT
@@ -38560,7 +38579,7 @@ atJ
axP
auv
azl
-aCY
+apQ
aAT
aAT
aBW
@@ -39282,7 +39301,7 @@ aAU
aAT
azl
azl
-aWN
+avp
azl
azl
aEp
@@ -40399,7 +40418,7 @@ asF
ati
atT
auC
-atm
+agX
avH
awx
axm
@@ -40683,7 +40702,7 @@ asG
atk
atV
auE
-avd
+ahj
avJ
awz
axo
@@ -41798,7 +41817,7 @@ aYg
aXY
aqy
aob
-aTK
+agD
asc
avj
aWY
@@ -41934,7 +41953,7 @@ aiW
anx
apU
arp
-apQ
+afw
apS
aXG
aYa
@@ -42111,7 +42130,7 @@ ayh
ayO
azG
aAB
-aFa
+atm
aBN
aCj
aBO
diff --git a/maps/tether/tether-03-surface3.dmm b/maps/tether/tether-03-surface3.dmm
index a6148c7937..d4c6452678 100644
--- a/maps/tether/tether-03-surface3.dmm
+++ b/maps/tether/tether-03-surface3.dmm
@@ -13483,27 +13483,36 @@
/area/hallway/lower/third_south)
"awI" = (
/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/command{
- req_access = list(19)
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/obj/structure/disposalpipe/segment,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/machinery/door/airlock/glass_security{
+ id_tag = "SurfaceFoyer";
+ layer = 2.8;
+ name = "Security";
+ req_access = list(1)
},
/obj/machinery/door/blast/regular{
density = 0;
- dir = 4;
+ dir = 1;
icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
+ id = "surfbriglockdown";
+ layer = 1;
+ name = "Security Blast Doors";
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor,
-/area/bridge_hallway)
+/obj/structure/cable/green{
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/tiled/steel_grid,
+/area/tether/surfacebase/security/lobby)
"awJ" = (
/turf/simulated/wall,
/area/maintenance/lower/atrium)
@@ -27062,37 +27071,47 @@
/area/maintenance/lower/mining)
"aTt" = (
/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/glass_command{
- dir = 1;
- name = "Bridge";
+/obj/machinery/door/airlock/maintenance/command{
req_access = list(19)
},
+/obj/structure/disposalpipe/segment,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
- dir = 1;
+ dir = 4;
icon_state = "pdoor0";
id = "bridge blast";
+ layer = 1;
name = "Bridge Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor/tiled/dark,
-/area/bridge)
+/turf/simulated/floor,
+/area/bridge_hallway)
"aTu" = (
/obj/machinery/door/firedoor/glass,
/obj/machinery/door/airlock/glass_command{
+ dir = 1;
name = "Bridge";
req_access = list(19)
},
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 1;
icon_state = "pdoor0";
id = "bridge blast";
+ layer = 1;
name = "Bridge Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor/tiled/dark,
/area/bridge)
@@ -27758,34 +27777,26 @@
/area/tether/surfacebase/security/common)
"aUy" = (
/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
+/obj/machinery/door/airlock/glass_command{
+ name = "Bridge";
+ req_access = list(19)
},
/obj/structure/disposalpipe/segment{
dir = 4
},
-/obj/machinery/door/airlock/glass_security{
- id_tag = "SurfaceFoyer";
- layer = 2.8;
- name = "Security";
- req_access = list(1)
- },
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 1;
icon_state = "pdoor0";
- id = "surfbriglockdown";
- name = "Security Blast Doors";
- opacity = 0
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
},
-/obj/structure/cable/green{
- icon_state = "4-8"
- },
-/turf/simulated/floor/tiled/steel_grid,
-/area/tether/surfacebase/security/lobby)
+/turf/simulated/floor/tiled/dark,
+/area/bridge)
"aUz" = (
/obj/effect/floor_decal/steeldecal/steel_decals6{
dir = 9
@@ -29770,10 +29781,26 @@
/turf/simulated/floor/wood,
/area/library)
"aXx" = (
-/obj/structure/shuttle/engine/propulsion,
-/turf/simulated/floor/reinforced,
-/turf/simulated/shuttle/plating/carry,
-/area/shuttle/tether)
+/obj/structure/grille,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
+ },
+/obj/structure/window/reinforced/full,
+/obj/structure/window/reinforced,
+/obj/structure/cable/green{
+ icon_state = "0-4"
+ },
+/turf/simulated/floor/plating,
+/area/bridge)
"aXy" = (
/obj/structure/table/standard,
/obj/item/weapon/gun/energy/taser/xeno,
@@ -29813,12 +29840,29 @@
/turf/simulated/floor/tiled/white,
/area/rnd/outpost/xenobiology/outpost_first_aid)
"aXB" = (
-/obj/machinery/atmospherics/unary/engine{
- dir = 1
+/obj/structure/grille,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor/reinforced,
-/turf/simulated/shuttle/plating/carry,
-/area/shuttle/tourbus/engines)
+/obj/structure/window/reinforced/full,
+/obj/structure/window/reinforced,
+/obj/structure/cable/green{
+ icon_state = "0-4"
+ },
+/obj/structure/cable/green{
+ icon_state = "0-8"
+ },
+/turf/simulated/floor/plating,
+/area/bridge)
"aXC" = (
/obj/structure/bed/chair/office/dark{
dir = 8
@@ -29833,6 +29877,61 @@
},
/turf/simulated/floor/wood,
/area/library)
+"aXD" = (
+/obj/structure/grille,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
+ },
+/obj/structure/window/reinforced/full,
+/obj/structure/window/reinforced,
+/obj/structure/cable/green{
+ icon_state = "0-4"
+ },
+/obj/structure/cable/green{
+ icon_state = "0-8"
+ },
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 8;
+ icon_state = "1-8"
+ },
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
+ },
+/turf/simulated/floor/plating,
+/area/bridge)
+"aXE" = (
+/obj/structure/grille,
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "bridge blast";
+ layer = 1;
+ name = "Bridge Blast Doors";
+ opacity = 0;
+ open_layer = 1
+ },
+/obj/structure/window/reinforced/full,
+/obj/structure/window/reinforced,
+/obj/structure/cable/green{
+ icon_state = "0-8"
+ },
+/turf/simulated/floor/plating,
+/area/bridge)
"aXF" = (
/obj/machinery/power/apc{
dir = 2;
@@ -30004,6 +30103,18 @@
},
/turf/simulated/floor/tiled,
/area/rnd/research/researchdivision)
+"aXU" = (
+/obj/structure/shuttle/engine/propulsion,
+/turf/simulated/floor/reinforced,
+/turf/simulated/shuttle/plating/carry,
+/area/shuttle/tether)
+"aXV" = (
+/obj/machinery/atmospherics/unary/engine{
+ dir = 1
+ },
+/turf/simulated/floor/reinforced,
+/turf/simulated/shuttle/plating/carry,
+/area/shuttle/tourbus/engines)
"aXW" = (
/obj/structure/disposalpipe/segment{
dir = 4;
@@ -31244,24 +31355,6 @@
/obj/structure/cable/green,
/turf/simulated/floor/tiled,
/area/crew_quarters/heads/hop)
-"baq" = (
-/obj/structure/grille,
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
- },
-/obj/structure/window/reinforced/full,
-/obj/structure/window/reinforced,
-/obj/structure/cable/green{
- icon_state = "0-4"
- },
-/turf/simulated/floor/plating,
-/area/bridge)
"bar" = (
/obj/machinery/computer/communications,
/obj/machinery/light/small{
@@ -31297,58 +31390,6 @@
},
/turf/simulated/floor/tiled,
/area/crew_quarters/heads/hop)
-"baw" = (
-/obj/structure/grille,
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
- },
-/obj/structure/window/reinforced/full,
-/obj/structure/window/reinforced,
-/obj/structure/cable/green{
- icon_state = "0-4"
- },
-/obj/structure/cable/green{
- icon_state = "0-8"
- },
-/turf/simulated/floor/plating,
-/area/bridge)
-"bay" = (
-/obj/structure/grille,
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
- },
-/obj/structure/window/reinforced/full,
-/obj/structure/window/reinforced,
-/obj/structure/cable/green{
- icon_state = "0-4"
- },
-/obj/structure/cable/green{
- icon_state = "0-8"
- },
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 8;
- icon_state = "1-8"
- },
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 4;
- icon_state = "1-4"
- },
-/turf/simulated/floor/plating,
-/area/bridge)
"baz" = (
/obj/effect/floor_decal/borderfloor,
/obj/effect/floor_decal/corner/lightgrey/border,
@@ -31361,24 +31402,6 @@
/obj/structure/disposalpipe/segment,
/turf/simulated/floor/tiled,
/area/tether/surfacebase/surface_three_hall)
-"baA" = (
-/obj/structure/grille,
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "bridge blast";
- name = "Bridge Blast Doors";
- opacity = 0
- },
-/obj/structure/window/reinforced/full,
-/obj/structure/window/reinforced,
-/obj/structure/cable/green{
- icon_state = "0-8"
- },
-/turf/simulated/floor/plating,
-/area/bridge)
"baG" = (
/obj/structure/bed/chair/comfy/brown{
dir = 8
@@ -42927,7 +42950,7 @@ ahy
ahx
ahx
ahx
-aUy
+awI
aVN
aWb
aWn
@@ -43697,7 +43720,7 @@ mfi
jHw
jpB
qWU
-aXB
+aXV
aKU
aOI
aPb
@@ -44085,7 +44108,7 @@ alj
alj
alj
asT
-aTt
+aTu
asT
alX
alX
@@ -44549,7 +44572,7 @@ isR
jHw
gHh
qWU
-aXB
+aXV
aKU
aOI
aPb
@@ -44657,7 +44680,7 @@ aYb
aYs
aYx
aYE
-baq
+aXx
bbF
ajM
ape
@@ -44799,7 +44822,7 @@ aYb
aYp
aYy
aYF
-baw
+aXB
bbF
ajM
apf
@@ -44941,7 +44964,7 @@ aYb
aYp
aYz
aYG
-baw
+aXB
bbF
ajM
apD
@@ -45083,7 +45106,7 @@ aYb
aYt
aYA
aYH
-baw
+aXB
bbF
aEq
apE
@@ -45207,7 +45230,7 @@ ajV
akn
aYO
aZs
-awI
+aTt
aEb
aSE
aYS
@@ -45225,7 +45248,7 @@ aYo
aYu
aYI
aPC
-bay
+aXD
bbF
avG
aNE
@@ -45367,7 +45390,7 @@ bae
aYv
aYB
aYJ
-baw
+aXB
bbF
ajR
akx
@@ -45509,7 +45532,7 @@ bae
aYb
aTv
aYK
-baw
+aXB
bbF
ajR
aEx
@@ -45651,7 +45674,7 @@ aZI
aYb
aYy
aYL
-baw
+aXB
bbF
avH
awq
@@ -45793,7 +45816,7 @@ aYp
aYw
aYD
aYM
-baA
+aXE
bbF
ajR
awp
@@ -46357,7 +46380,7 @@ ayx
alo
alo
asT
-aTu
+aUy
asT
alZ
alZ
@@ -46534,7 +46557,7 @@ aNk
uSA
aNJ
aNP
-aXx
+aXU
aKU
abg
aOk
@@ -46676,7 +46699,7 @@ aNl
aNl
aNK
aNP
-aXx
+aXU
aKU
abg
aOk
@@ -46818,7 +46841,7 @@ aNm
aNl
aNK
aNP
-aXx
+aXU
aKU
abg
aOk
diff --git a/maps/tether/tether-05-station1.dmm b/maps/tether/tether-05-station1.dmm
index 3df928336f..8d3a0bf1f0 100644
--- a/maps/tether/tether-05-station1.dmm
+++ b/maps/tether/tether-05-station1.dmm
@@ -2822,12 +2822,15 @@
/obj/machinery/door/firedoor/glass,
/obj/structure/disposalpipe/segment,
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 8;
icon_state = "pdoor0";
id = "secondary_bridge_blast";
+ layer = 1;
name = "Secondary Command Office Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor/tiled,
/area/bridge/secondary)
@@ -3705,26 +3708,23 @@
/turf/simulated/floor/tiled,
/area/hallway/station/atrium)
"agr" = (
-/obj/structure/cable{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/door/airlock/command{
+ name = "Secondary Command Office"
},
/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/engi{
- name = "Asteroid Command Substation";
- req_one_access = list(10,19)
- },
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 8;
icon_state = "pdoor0";
id = "secondary_bridge_blast";
+ layer = 1;
name = "Secondary Command Office Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor,
-/area/maintenance/substation/spacecommand)
+/turf/simulated/floor/tiled,
+/area/bridge/secondary)
"ags" = (
/obj/effect/floor_decal/borderfloor{
dir = 8
@@ -5113,20 +5113,29 @@
/turf/simulated/floor/carpet/bcarpet,
/area/tether/station/visitorhallway/office)
"aiw" = (
-/obj/machinery/door/airlock/command{
- name = "Secondary Command Office"
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
},
/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/maintenance/engi{
+ name = "Asteroid Command Substation";
+ req_one_access = list(10,19)
+ },
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 8;
icon_state = "pdoor0";
id = "secondary_bridge_blast";
+ layer = 1;
name = "Secondary Command Office Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
-/turf/simulated/floor/tiled,
-/area/bridge/secondary)
+/turf/simulated/floor,
+/area/maintenance/substation/spacecommand)
"aix" = (
/obj/structure/table/rack{
dir = 8;
@@ -11605,12 +11614,15 @@
dir = 4
},
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 1;
icon_state = "pdoor0";
id = "secondary_bridge_blast";
+ layer = 1;
name = "Secondary Command Office Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor,
/area/bridge/secondary/hallway)
@@ -16382,12 +16394,15 @@
req_one_access = list(17)
},
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 8;
icon_state = "pdoor0";
id = "secondary_bridge_blast";
+ layer = 1;
name = "Secondary Command Office Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor,
/area/bridge/secondary/teleporter)
@@ -17624,12 +17639,15 @@
/obj/machinery/door/firedoor/glass,
/obj/machinery/door/airlock/maintenance/command,
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 1;
icon_state = "pdoor0";
id = "secondary_bridge_blast";
+ layer = 1;
name = "Secondary Command Office Blast Doors";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor,
/area/bridge/meeting_room)
@@ -35267,7 +35285,7 @@ aix
aBx
ait
aut
-agr
+aiw
agB
ahj
aiu
@@ -35829,7 +35847,7 @@ acm
acm
acp
are
-aiw
+agr
asR
afd
afd
diff --git a/maps/tether/tether-06-station2.dmm b/maps/tether/tether-06-station2.dmm
index 82e8d15d44..562b659963 100644
--- a/maps/tether/tether-06-station2.dmm
+++ b/maps/tether/tether-06-station2.dmm
@@ -10492,24 +10492,40 @@
/turf/simulated/wall,
/area/medical/surgery_hallway)
"ps" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/medical{
- name = "Medical Waiting Room";
- req_one_access = list()
- },
-/obj/machinery/door/blast/shutters{
- density = 0;
- dir = 2;
- icon_state = "shutter0";
- id = "medbayquar";
- name = "Medbay Emergency Lockdown Shutters";
- opacity = 0
- },
/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/turf/simulated/floor/tiled/white,
-/area/medical/surgery_hallway)
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/machinery/door/airlock/glass_engineering{
+ closed_layer = 8;
+ layer = 2;
+ name = "Engineering Mezzenine";
+ open_layer = 2;
+ req_one_access = list()
+ },
+/obj/machinery/door/firedoor/glass{
+ closed_layer = 7;
+ layer = 1.5;
+ open_layer = 1.5
+ },
+/obj/machinery/door/blast/regular{
+ closed_layer = 10;
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "englockdown";
+ layer = 1;
+ level = 1;
+ name = "Engineering Lockdown";
+ opacity = 0;
+ open_layer = 1
+ },
+/turf/simulated/floor/tiled/steel_grid,
+/area/engineering/foyer_mezzenine)
"pt" = (
/obj/effect/floor_decal/borderfloor,
/obj/effect/floor_decal/corner/paleblue/border,
@@ -10699,45 +10715,40 @@
/turf/simulated/floor/plating,
/area/engineering/foyer_mezzenine)
"pL" = (
-/obj/structure/disposalpipe/segment,
/obj/machinery/door/airlock/glass_engineering{
+ closed_layer = 8;
+ layer = 2;
name = "Engineering Mezzenine";
+ open_layer = 2;
req_one_access = list()
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/door/firedoor/glass,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/door/firedoor/glass{
+ closed_layer = 7;
+ layer = 1.5;
+ open_layer = 1.5
},
/obj/machinery/door/blast/regular{
+ closed_layer = 10;
density = 0;
dir = 4;
icon_state = "pdoor0";
id = "englockdown";
+ layer = 1;
+ level = 1;
name = "Engineering Lockdown";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor/tiled/steel_grid,
/area/engineering/foyer_mezzenine)
"pM" = (
-/obj/machinery/door/airlock/glass_engineering{
- name = "Engineering Mezzenine";
- req_one_access = list()
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8;
+ icon_state = "propulsion_r"
},
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "englockdown";
- name = "Engineering Lockdown";
- opacity = 0
- },
-/turf/simulated/floor/tiled/steel_grid,
-/area/engineering/foyer_mezzenine)
+/turf/space,
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1)
"pN" = (
/obj/machinery/requests_console{
department = "Tech storage";
@@ -10804,13 +10815,27 @@
/turf/simulated/floor/tiled,
/area/hallway/station/starboard)
"pS" = (
-/obj/structure/shuttle/engine/propulsion{
- dir = 8;
- icon_state = "propulsion_r"
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/medical{
+ name = "Medical Waiting Room";
+ req_one_access = list()
},
-/turf/space,
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1)
+/obj/machinery/door/blast/shutters{
+ closed_layer = 10;
+ density = 0;
+ dir = 2;
+ icon_state = "shutter0";
+ id = "medbayquar";
+ layer = 1;
+ name = "Medbay Emergency Lockdown Shutters";
+ opacity = 0;
+ open_layer = 1
+ },
+/obj/structure/disposalpipe/segment,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/turf/simulated/floor/tiled/white,
+/area/medical/surgery_hallway)
"pT" = (
/obj/structure/cable{
d1 = 1;
@@ -16170,6 +16195,30 @@
},
/turf/simulated/floor/tiled/white,
/area/medical/ward)
+"yp" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/maintenance/medical,
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/machinery/door/blast/shutters{
+ closed_layer = 10;
+ density = 0;
+ dir = 8;
+ icon_state = "shutter0";
+ id = "medbayquar";
+ layer = 1;
+ name = "Medbay Emergency Lockdown Shutters";
+ opacity = 0;
+ open_layer = 1
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/turf/simulated/floor,
+/area/medical/surgery_hallway)
"ys" = (
/obj/structure/table/standard,
/obj/item/weapon/reagent_containers/spray/cleaner{
@@ -17512,27 +17561,6 @@
},
/turf/simulated/floor/tiled/white,
/area/medical/surgery_hallway)
-"AS" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/maintenance/medical,
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/door/blast/shutters{
- density = 0;
- dir = 8;
- icon_state = "shutter0";
- id = "medbayquar";
- name = "Medbay Emergency Lockdown Shutters";
- opacity = 0
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/simulated/floor,
-/area/medical/surgery_hallway)
"AT" = (
/obj/structure/cable/green{
d1 = 4;
@@ -30817,7 +30845,7 @@ nB
nk
oh
ox
-pL
+ps
qr
rh
rU
@@ -31101,7 +31129,7 @@ nD
oj
oN
qx
-pM
+pL
qt
rj
rV
@@ -32951,7 +32979,7 @@ lK
Fr
fH
op
-ps
+pS
qO
rx
sb
@@ -33965,7 +33993,7 @@ zQ
xf
pp
pp
-AS
+yp
pp
Ay
BM
@@ -37493,7 +37521,7 @@ ot
ou
ou
ou
-pS
+pM
oY
sW
ef
diff --git a/maps/tether/tether-07-station3.dmm b/maps/tether/tether-07-station3.dmm
index d3d445eb13..3878984045 100644
--- a/maps/tether/tether-07-station3.dmm
+++ b/maps/tether/tether-07-station3.dmm
@@ -16093,12 +16093,15 @@
name = "Medbay Lobby"
},
/obj/machinery/door/blast/shutters{
+ closed_layer = 10;
density = 0;
dir = 2;
icon_state = "shutter0";
id = "medbayquar";
+ layer = 1;
name = "Medbay Emergency Lockdown Shutters";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/obj/effect/floor_decal/steeldecal/steel_decals_central1{
dir = 8
@@ -16476,12 +16479,15 @@
"azr" = (
/obj/machinery/door/firedoor/glass,
/obj/machinery/door/blast/shutters{
+ closed_layer = 10;
density = 0;
dir = 2;
icon_state = "shutter0";
id = "medbayquar";
+ layer = 1;
name = "Medbay Emergency Lockdown Shutters";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
@@ -16499,12 +16505,15 @@
name = "EMT Bay"
},
/obj/machinery/door/blast/shutters{
+ closed_layer = 10;
density = 0;
dir = 2;
icon_state = "shutter0";
id = "medbayquar";
+ layer = 1;
name = "Medbay Emergency Lockdown Shutters";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/turf/simulated/floor/tiled/dark,
/area/medical/medbay_emt_bay)
@@ -24584,12 +24593,15 @@
/obj/machinery/door/firedoor/glass,
/obj/machinery/door/airlock/maintenance/medical,
/obj/machinery/door/blast/shutters{
+ closed_layer = 10;
density = 0;
dir = 8;
icon_state = "shutter0";
id = "medbayquar";
+ layer = 1;
name = "Medbay Emergency Lockdown Shutters";
- opacity = 0
+ opacity = 0;
+ open_layer = 1
},
/obj/structure/cable/green{
d1 = 4;
@@ -26017,7 +26029,7 @@
/area/shuttle/medivac/engines)
"aOc" = (
/obj/machinery/door/airlock/glass_mining{
- name = "Belter Shuttle";
+ name = "Mining Operations";
req_access = list(31);
req_one_access = list()
},
diff --git a/maps/tether/tether_phoronlock.dm b/maps/tether/tether_phoronlock.dm
index 4921680f15..9118284285 100644
--- a/maps/tether/tether_phoronlock.dm
+++ b/maps/tether/tether_phoronlock.dm
@@ -243,6 +243,7 @@ obj/machinery/airlock_sensor/phoron/airlock_exterior
if(STATE_PREPARE)
if (check_doors_secured())
if(target_state == TARGET_INOPEN)
+ playsound(master, 'sound/AI/airlockin.ogg', 100, 0)
if(memory["chamber_sensor_phoron"] > memory["target_phoron"])
state = STATE_CLEAN
signalScrubber(tag_scrubber, 1) // Start cleaning
@@ -256,11 +257,13 @@ obj/machinery/airlock_sensor/phoron/airlock_exterior
else if(memory["pump_status"] != "off")
signalPump(tag_airpump, 0)
else
+ playsound(master, 'sound/AI/airlockout.ogg', 100, 0)
cycleDoors(target_state)
state = STATE_IDLE
target_state = TARGET_NONE
if(STATE_CLEAN)
+ playsound(master, 'sound/machines/2beep.ogg', 100, 0)
if(!check_doors_secured())
//the airlock will not allow itself to continue to cycle when any of the doors are forced open.
stop_cycling()
@@ -271,12 +274,14 @@ obj/machinery/airlock_sensor/phoron/airlock_exterior
state = STATE_PRESSURIZE
if(STATE_PRESSURIZE)
+ playsound(master, 'sound/machines/2beep.ogg', 100, 0)
if(!check_doors_secured())
//the airlock will not allow itself to continue to cycle when any of the doors are forced open.
stop_cycling()
else if(memory["chamber_sensor_pressure"] >= memory["target_pressure"] * 0.95)
signalPump(tag_airpump, 0) // send a signal to stop pumping. No need to wait for it tho.
cycleDoors(target_state)
+ playsound(master, 'sound/AI/airlockdone.ogg', 100, 0)
state = STATE_IDLE
target_state = TARGET_NONE
diff --git a/maps/virgo_minitest/virgo_minitest-1.dmm b/maps/virgo_minitest/virgo_minitest-1.dmm
index 9ce7f531bf..fd81e96920 100644
--- a/maps/virgo_minitest/virgo_minitest-1.dmm
+++ b/maps/virgo_minitest/virgo_minitest-1.dmm
@@ -6,6 +6,7 @@
/turf/simulated/wall/r_wall,
/area/tcommsat/computer)
"ac" = (
+/obj/machinery/camera/network/civilian,
/turf/simulated/floor/tiled/dark,
/area/tcommsat/computer)
"ad" = (
@@ -493,6 +494,10 @@
/obj/machinery/atmospherics/pipe/simple/visible/yellow{
dir = 4
},
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 9
+ },
/turf/simulated/floor/plating,
/area/engineering/engine_room)
"bc" = (
@@ -703,6 +708,10 @@
pixel_x = -25;
pixel_y = 0
},
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 4
+ },
/turf/simulated/floor/plating,
/area/engineering/engine_room)
"br" = (
@@ -2289,6 +2298,10 @@
/obj/structure/cable{
icon_state = "0-8"
},
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 10
+ },
/turf/simulated/floor/tiled,
/area/crew_quarters/bar)
"eU" = (
@@ -3291,10 +3304,39 @@
/turf/space,
/turf/simulated/shuttle/plating/carry,
/area/shuttle/overmapdemo)
+"jA" = (
+/obj/machinery/cryopod,
+/turf/simulated/floor/tiled,
+/area/bridge)
"kU" = (
/obj/structure/shuttle,
/turf/simulated/shuttle/wall/voidcraft/green,
/area/shuttle/overmapdemo)
+"mj" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 10
+ },
+/turf/simulated/floor/tiled,
+/area/crew_quarters/bar)
+"nM" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 9
+ },
+/turf/simulated/floor/tiled,
+/area/crew_quarters/cafeteria)
+"nQ" = (
+/obj/machinery/cryopod/robot,
+/turf/simulated/floor/tiled,
+/area/bridge)
+"pG" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 9
+ },
+/turf/simulated/floor/tiled,
+/area/bridge)
"ql" = (
/obj/machinery/door/airlock/external{
frequency = 1379;
@@ -3311,11 +3353,43 @@
},
/turf/simulated/shuttle/floor/voidcraft/light,
/area/shuttle/overmapdemo)
+"qZ" = (
+/obj/machinery/camera/network/civilian,
+/turf/simulated/floor/tiled,
+/area/medical/medbay)
+"rn" = (
+/obj/machinery/computer/cryopod,
+/turf/simulated/floor/tiled,
+/area/bridge)
+"rK" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 10
+ },
+/turf/simulated/floor/bluegrid{
+ name = "Mainframe Base";
+ nitrogen = 100;
+ oxygen = 0;
+ temperature = 80
+ },
+/area/tcommsat/chamber)
"sA" = (
/obj/structure/shuttle/engine/heater,
/turf/space,
/turf/simulated/shuttle/plating/carry,
/area/shuttle/multidemo)
+"sB" = (
+/obj/effect/landmark{
+ name = "JoinLateCyborg"
+ },
+/turf/simulated/floor/tiled,
+/area/bridge)
+"vI" = (
+/obj/effect/landmark/start{
+ name = "AI"
+ },
+/turf/simulated/floor/tiled,
+/area/crew_quarters/bar)
"vP" = (
/obj/machinery/computer/ship/engines{
dir = 8;
@@ -3323,6 +3397,20 @@
},
/turf/simulated/shuttle/floor/voidcraft/light,
/area/shuttle/overmapdemo)
+"xM" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 5
+ },
+/turf/simulated/floor/tiled,
+/area/crew_quarters/cafeteria)
+"xX" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 4
+ },
+/turf/simulated/floor/tiled,
+/area/medical/medbay)
"zf" = (
/obj/effect/wingrille_spawn/reinforced,
/turf/simulated/shuttle/floor/voidcraft/external/light,
@@ -3338,10 +3426,24 @@
"Gz" = (
/turf/simulated/shuttle/wall/voidcraft/green,
/area/shuttle/overmapdemo)
+"GC" = (
+/obj/machinery/camera/network/civilian,
+/turf/simulated/floor/tiled,
+/area/bridge)
"JA" = (
/obj/effect/overmap/visitable/sector/virgo_minitest/station,
/turf/space,
/area/space)
+"La" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 9
+ },
+/turf/simulated/floor/tiled,
+/area/hallway/primary/fore)
"ML" = (
/obj/machinery/embedded_controller/radio/simple_docking_controller{
id_tag = "station_dock2";
@@ -3362,6 +3464,13 @@
},
/turf/simulated/shuttle/floor/voidcraft/light,
/area/shuttle/overmapdemo)
+"OA" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 10
+ },
+/turf/simulated/floor/tiled,
+/area/medical/medbay)
"Pg" = (
/obj/structure/shuttle/engine/propulsion,
/turf/space,
@@ -3376,16 +3485,47 @@
},
/turf/simulated/floor/tiled,
/area/bridge)
+"Ug" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 4
+ },
+/turf/simulated/floor/tiled,
+/area/medical/medbay2)
"Uh" = (
/obj/machinery/computer/ship/sensors{
dir = 1
},
/turf/simulated/shuttle/floor/voidcraft/light,
/area/shuttle/overmapdemo)
+"Vf" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 9
+ },
+/turf/simulated/floor/tiled,
+/area/crew_quarters/bar)
+"Xm" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/camera/network/civilian,
+/turf/simulated/floor/tiled,
+/area/hallway/primary/fore)
"XZ" = (
/obj/machinery/computer/ship/helm,
/turf/simulated/shuttle/floor/voidcraft/light,
/area/shuttle/overmapdemo)
+"Yb" = (
+/obj/machinery/camera/network/civilian{
+ icon_state = "camera";
+ dir = 9
+ },
+/turf/simulated/floor/tiled,
+/area/medical/medbay2)
(1,1,1) = {"
aa
@@ -4791,9 +4931,9 @@ aa
aa
fY
gf
-gf
-gf
-gf
+rn
+sB
+nQ
gf
gf
gf
@@ -4996,8 +5136,8 @@ aa
fY
gg
gf
-gf
-gf
+gC
+jA
gf
gx
gA
@@ -5205,7 +5345,7 @@ gf
gf
gy
gf
-gC
+gf
gf
gf
gf
@@ -5402,7 +5542,7 @@ sA
Pg
aa
fY
-gf
+GC
gf
gr
gf
@@ -5715,7 +5855,7 @@ gf
gf
gy
gf
-gC
+gf
gf
gf
gf
@@ -5875,7 +6015,7 @@ bW
bu
bu
bu
-bf
+rK
aP
aa
aa
@@ -6223,14 +6363,14 @@ gf
gv
gf
gf
-gf
+pG
gv
hk
hy
hl
gf
gv
-gf
+pG
gf
gf
fY
@@ -6413,7 +6553,7 @@ aa
aa
aa
fi
-fo
+Xm
fu
fi
aa
@@ -6595,14 +6735,14 @@ aa
cF
cM
cM
-cM
+xX
dd
cM
cM
cM
cM
cM
-cM
+xX
dd
cM
cM
@@ -6906,7 +7046,7 @@ cM
cM
cM
cM
-cM
+OA
du
cM
cM
@@ -7223,7 +7363,7 @@ eO
eO
eO
eO
-eO
+La
eO
eO
eO
@@ -7415,7 +7555,7 @@ cM
dh
cM
du
-cM
+qZ
cM
el
cM
@@ -8129,7 +8269,7 @@ cZ
dm
dv
cZ
-cZ
+Yb
cZ
dR
cZ
@@ -8639,7 +8779,7 @@ cZ
dl
cZ
cZ
-cZ
+Ug
cZ
dR
cZ
@@ -10298,7 +10438,7 @@ fI
fS
fI
fI
-fI
+xM
fS
fI
fI
@@ -10573,6 +10713,7 @@ cC
cK
cR
cW
+vI
cK
cK
cK
@@ -10580,8 +10721,7 @@ cK
cK
cK
cK
-cK
-cK
+mj
cR
eE
eL
@@ -10675,7 +10815,7 @@ cC
cK
cR
cK
-cK
+Vf
cK
cK
cK
@@ -11314,7 +11454,7 @@ aa
aa
fA
fI
-fI
+nM
fW
fI
fI
diff --git a/maps/virgo_minitest/virgo_minitest.dm b/maps/virgo_minitest/virgo_minitest.dm
index 5906fae2f6..4a7f68fbaf 100644
--- a/maps/virgo_minitest/virgo_minitest.dm
+++ b/maps/virgo_minitest/virgo_minitest.dm
@@ -10,7 +10,7 @@
#define USING_MAP_DATUM /datum/map/virgo_minitest
- #warning Please uncheck virgo_minitest.dm before committing.
+ #warn Please uncheck virgo_minitest before committing
#elif !defined(MAP_OVERRIDE)
diff --git a/maps/virgo_minitest/virgo_minitest_defines.dm b/maps/virgo_minitest/virgo_minitest_defines.dm
index 8432fb7f22..db438c6476 100644
--- a/maps/virgo_minitest/virgo_minitest_defines.dm
+++ b/maps/virgo_minitest/virgo_minitest_defines.dm
@@ -9,8 +9,8 @@
lobby_icon = 'icons/misc/title_vr.dmi'
lobby_screens = list("tether2_night")
- accessible_z_levels = list("[Z_LEVEL_MAIN_VIRGO_TESTING]" = 100)
- base_turf_by_z = list("[Z_LEVEL_MAIN_VIRGO_TESTING]" = /turf/space)
+ accessible_z_levels = list("1" = 100)
+ base_turf_by_z = list("1" = /turf/space)
use_overmap = TRUE
//var/overmap_size = 20 // Dimensions of overmap zlevel if overmap is used.
@@ -56,7 +56,7 @@
NETWORK_INTERROGATION
)
- allowed_spawns = list("Arrivals Shuttle")
+ allowed_spawns = list("Arrivals Shuttle","Gateway","Cryogenic Storage","Cyborg Storage")
/datum/map_z_level/minitest/station
z = Z_LEVEL_MAIN_VIRGO_TESTING
diff --git a/maps/~map_system/maps.dm b/maps/~map_system/maps.dm
index cd953e8217..5b497cdbff 100644
--- a/maps/~map_system/maps.dm
+++ b/maps/~map_system/maps.dm
@@ -147,15 +147,14 @@ var/list/all_maps = list()
/datum/map/proc/get_zlevel_time(var/z)
if(!z)
z = 1
- var/datum/planet/P = SSplanets.z_to_planet[z]
+ var/datum/planet/P = z <= SSplanets.z_to_planet.len ? SSplanets.z_to_planet[z] : null
// We found a planet tied to that zlevel, give them the time
- if(istype(P))
+ if(P?.current_time)
return P.current_time
// We have to invent a time
else
- var/seconds_stationtime = round(station_time_in_ticks*0.1) //Not actually ticks......
- var/datum/time/T = new(seconds_stationtime)
+ var/datum/time/T = new (station_time_in_ds)
return T
// Returns a boolean for if it's night or not on a particular zlevel
@@ -163,7 +162,7 @@ var/list/all_maps = list()
if(!z)
z = 1
var/datum/time/now = get_zlevel_time(z)
- var/percent = now.seconds_stored / now.seconds_in_day
+ var/percent = now.seconds_stored / now.seconds_in_day //practically all of these are in DS
// First quarter, last quarter
if(percent < 0.25 || percent > 0.75)
diff --git a/nano/templates/apc.tmpl b/nano/templates/apc.tmpl
index 9b39900a81..a26abef4a0 100644
--- a/nano/templates/apc.tmpl
+++ b/nano/templates/apc.tmpl
@@ -206,7 +206,9 @@
Night Lighting:
- {{:helper.link(data.nightshiftLights ? 'Enabled' : 'Disabled', data.nightshiftLights ? 'power' : 'close', {'nightshift' : 1}, null)}}
+ {{:helper.link('Disabled', null, {'nightshift' : 2}, data.nightshiftSetting == 2 ? 'selected' : null)}}
+ {{:helper.link('Automatic', null, {'nightshift' : 1}, data.nightshiftSetting == 1 ? 'selected' : null)}}
+ {{:helper.link('Enabled', null, {'nightshift' : 3}, data.nightshiftSetting == 3 ? 'selected' : null)}}
diff --git a/nano/templates/teleport_control.tmpl b/nano/templates/teleport_control.tmpl
new file mode 100644
index 0000000000..c849eb516f
--- /dev/null
+++ b/nano/templates/teleport_control.tmpl
@@ -0,0 +1,44 @@
+
+
+
Target:
+
+ {{:helper.link(data.locked_name, null, {'select_target' : 1}, null, null)}}
+
+
+
+
+
Calibrated:
+
+ {{:helper.link(data.calibrated ? 'Accurate' : 'Test Fire', data.calibrated ? 'check' : 'close', {'test_fire' : 1}, null, data.calibrated ? 'linkOn' : 'redButton')}}
+
+
+
+
+
Teleporter:
+
+ {{:helper.link(data.teleporter_on ? 'Online' : 'Offline', data.teleporter_on ? 'check' : 'close', {'toggle_on' : 1}, null, data.teleporter_on ? 'linkOn' : 'redButton')}}
+
+
+
+
+
Station:
+
+ {{if data.station_connected}}
+ Connected
+ {{else}}
+ Not Connected!
+ {{/if}}
+
+
+
+
+
Hub:
+
+ {{if data.hub_connected}}
+ Connected
+ {{else}}
+ Not Connected!
+ {{/if}}
+
+
+
\ No newline at end of file
diff --git a/sound/effects/footstep/HeavySand1.ogg b/sound/effects/footstep/HeavySand1.ogg
new file mode 100644
index 0000000000..68be7bed25
Binary files /dev/null and b/sound/effects/footstep/HeavySand1.ogg differ
diff --git a/sound/effects/footstep/HeavySand2.ogg b/sound/effects/footstep/HeavySand2.ogg
new file mode 100644
index 0000000000..6a32465a5b
Binary files /dev/null and b/sound/effects/footstep/HeavySand2.ogg differ
diff --git a/sound/effects/footstep/HeavySand3.ogg b/sound/effects/footstep/HeavySand3.ogg
new file mode 100644
index 0000000000..c71a89cea2
Binary files /dev/null and b/sound/effects/footstep/HeavySand3.ogg differ
diff --git a/sound/effects/footstep/HeavySand4.ogg b/sound/effects/footstep/HeavySand4.ogg
new file mode 100644
index 0000000000..088519fb75
Binary files /dev/null and b/sound/effects/footstep/HeavySand4.ogg differ
diff --git a/sound/effects/footstep/LightDirt2.ogg b/sound/effects/footstep/LightDirt2.ogg
new file mode 100644
index 0000000000..324fd82370
Binary files /dev/null and b/sound/effects/footstep/LightDirt2.ogg differ
diff --git a/sound/effects/footstep/LightDirt4.ogg b/sound/effects/footstep/LightDirt4.ogg
new file mode 100644
index 0000000000..8a72738b21
Binary files /dev/null and b/sound/effects/footstep/LightDirt4.ogg differ
diff --git a/sound/effects/footstep/LightStone1.ogg b/sound/effects/footstep/LightStone1.ogg
new file mode 100644
index 0000000000..a61d3ccfa2
Binary files /dev/null and b/sound/effects/footstep/LightStone1.ogg differ
diff --git a/sound/effects/footstep/LightStone2.ogg b/sound/effects/footstep/LightStone2.ogg
new file mode 100644
index 0000000000..3409c1f4d8
Binary files /dev/null and b/sound/effects/footstep/LightStone2.ogg differ
diff --git a/sound/effects/footstep/LightStone3.ogg b/sound/effects/footstep/LightStone3.ogg
new file mode 100644
index 0000000000..e0843c62af
Binary files /dev/null and b/sound/effects/footstep/LightStone3.ogg differ
diff --git a/sound/effects/footstep/LightStone4.ogg b/sound/effects/footstep/LightStone4.ogg
new file mode 100644
index 0000000000..b262be5f8e
Binary files /dev/null and b/sound/effects/footstep/LightStone4.ogg differ
diff --git a/sound/effects/footstep/MedDirt1.ogg b/sound/effects/footstep/MedDirt1.ogg
new file mode 100644
index 0000000000..8951c4580a
Binary files /dev/null and b/sound/effects/footstep/MedDirt1.ogg differ
diff --git a/sound/effects/footstep/MedDirt2.ogg b/sound/effects/footstep/MedDirt2.ogg
new file mode 100644
index 0000000000..7fee392796
Binary files /dev/null and b/sound/effects/footstep/MedDirt2.ogg differ
diff --git a/sound/effects/footstep/MedDirt3.ogg b/sound/effects/footstep/MedDirt3.ogg
new file mode 100644
index 0000000000..141c542f0a
Binary files /dev/null and b/sound/effects/footstep/MedDirt3.ogg differ
diff --git a/sound/effects/footstep/MedDirt4.ogg b/sound/effects/footstep/MedDirt4.ogg
new file mode 100644
index 0000000000..7b980e6e31
Binary files /dev/null and b/sound/effects/footstep/MedDirt4.ogg differ
diff --git a/sound/effects/footstep/bubbles3.ogg b/sound/effects/footstep/bubbles3.ogg
new file mode 100644
index 0000000000..62070813e3
Binary files /dev/null and b/sound/effects/footstep/bubbles3.ogg differ
diff --git a/sound/effects/footstep/bubbles4.ogg b/sound/effects/footstep/bubbles4.ogg
new file mode 100644
index 0000000000..f94889c060
Binary files /dev/null and b/sound/effects/footstep/bubbles4.ogg differ
diff --git a/sound/effects/footstep/bubbles5.ogg b/sound/effects/footstep/bubbles5.ogg
new file mode 100644
index 0000000000..43eff29193
Binary files /dev/null and b/sound/effects/footstep/bubbles5.ogg differ
diff --git a/sound/effects/footstep/mud1.ogg b/sound/effects/footstep/mud1.ogg
new file mode 100644
index 0000000000..c0f5276e41
Binary files /dev/null and b/sound/effects/footstep/mud1.ogg differ
diff --git a/sound/effects/footstep/mud2.ogg b/sound/effects/footstep/mud2.ogg
new file mode 100644
index 0000000000..36b311a2de
Binary files /dev/null and b/sound/effects/footstep/mud2.ogg differ
diff --git a/sound/effects/footstep/mud3.ogg b/sound/effects/footstep/mud3.ogg
new file mode 100644
index 0000000000..e44c7d05f3
Binary files /dev/null and b/sound/effects/footstep/mud3.ogg differ
diff --git a/sound/effects/footstep/mud4.ogg b/sound/effects/footstep/mud4.ogg
new file mode 100644
index 0000000000..158158125d
Binary files /dev/null and b/sound/effects/footstep/mud4.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index 67aade51ff..f3ac8d1a3c 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -86,6 +86,8 @@
#include "code\__defines\subsystems_vr.dm"
#include "code\__defines\supply.dm"
#include "code\__defines\targeting.dm"
+#include "code\__defines\tgs.config.dm"
+#include "code\__defines\tgs.dm"
#include "code\__defines\turfs.dm"
#include "code\__defines\typeids.dm"
#include "code\__defines\unit_tests.dm"
@@ -160,6 +162,7 @@
#include "code\_onclick\hud\human.dm"
#include "code\_onclick\hud\movable_screen_objects.dm"
#include "code\_onclick\hud\other_mobs.dm"
+#include "code\_onclick\hud\picture_in_picture.dm"
#include "code\_onclick\hud\radial.dm"
#include "code\_onclick\hud\radial_persistent.dm"
#include "code\_onclick\hud\robot.dm"
@@ -2607,6 +2610,7 @@
#include "code\modules\mob\living\silicon\ai\login.dm"
#include "code\modules\mob\living\silicon\ai\logout.dm"
#include "code\modules\mob\living\silicon\ai\malf.dm"
+#include "code\modules\mob\living\silicon\ai\multicam.dm"
#include "code\modules\mob\living\silicon\decoy\death.dm"
#include "code\modules\mob\living\silicon\decoy\decoy.dm"
#include "code\modules\mob\living\silicon\decoy\life.dm"
@@ -3507,6 +3511,7 @@
#include "code\modules\telesci\telepad.dm"
#include "code\modules\telesci\telesci_computer.dm"
#include "code\modules\tension\tension.dm"
+#include "code\modules\tgs\includes.dm"
#include "code\modules\tooltip\tooltip.dm"
#include "code\modules\turbolift\_turbolift.dm"
#include "code\modules\turbolift\turbolift.dm"