diff --git a/.gitignore b/.gitignore
index 423af10b7c0..03c676f53d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,13 @@ vchat.db*
data
data/
cfg/
-.vscode
+
+#Visual studio stuff
+*.vscode/*
+!/.vscode/launch.json
+!/.vscode/extensions.json
+!/.vscode/settings.json
+!/.vscode/tasks.json
code/game/gamemodes/technomancer/spells/projectile/overload.dm
code/game/gamemodes/technomancer/spells/projectile/overload.dm
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 00000000000..24779e223e7
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "byond",
+ "request": "launch",
+ "name": "Launch DreamDaemon",
+ "preLaunchTask": "dm: build - ${command:CurrentDME}",
+ "dmb": "${workspaceFolder}/${command:CurrentDMB}",
+ "dreamDaemon": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000000..64cfc2bb26d
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,36 @@
+{
+ "eslint.nodePath": "./tgui/.yarn/sdks",
+ "eslint.workingDirectories": [
+ "./tgui"
+ ],
+ "typescript.tsdk": "./tgui/.yarn/sdks/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true,
+ "search.exclude": {
+ "**/.yarn": true,
+ "**/.pnp.*": true
+ },
+ "workbench.editorAssociations": {
+ "*.dmi": "imagePreview.previewEditor"
+ },
+ "files.eol": "\n",
+ "gitlens.advanced.blame.customArguments": [
+ "-w"
+ ],
+ "tgstationTestExplorer.project.resultsType": "json",
+ "[javascript]": {
+ "editor.rulers": [
+ 120
+ ]
+ },
+ "[typescript]": {
+ "editor.rulers": [
+ 120
+ ]
+ },
+ "[scss]": {
+ "editor.rulers": [
+ 120
+ ]
+ },
+ "tgstationTestExplorer.project.DMEName": "tgmc.dme"
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 00000000000..a3cb84d5a81
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,38 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "dreammaker",
+ "dme": "vorestation.dme",
+ "problemMatcher": [
+ "$dreammaker"
+ ],
+ "group": "build",
+ "label": "dm: build - vorestation.dme"
+ },
+ {
+ "type": "shell",
+ "command": "tgui/bin/tgui",
+ "windows": {
+ "command": ".\\tgui\\bin\\tgui.bat"
+ },
+ "problemMatcher": [
+ "$tsc",
+ "$eslint-stylish"
+ ],
+ "group": "build",
+ "label": "tgui: build"
+ },
+ {
+ "type": "shell",
+ "command": "yarn build",
+ "options": {
+ "cwd": "tgui/packages/tgfont/",
+ },
+ "group": "build",
+ "problemMatcher": [],
+ "label": "tgui: build tgfont",
+ "detail": "node mkdist.cjs && fantasticon --config config.cjs"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
index f95b613466b..e43bc4b25ae 100644
--- a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
@@ -44,10 +44,10 @@
// TODO - Make these in actual icon states so its not silly like this
var/image/I = image(icon = icon, icon_state = "algae-pipe-overlay", dir = dir)
I.color = PIPE_COLOR_BLUE
- overlays += I
+ add_overlay(I)
I = image(icon = icon, icon_state = "algae-pipe-overlay", dir = reverse_dir[dir])
I.color = PIPE_COLOR_BLACK
- overlays += I
+ add_overlay(I)
/obj/machinery/atmospherics/binary/algae_farm/Destroy()
. = ..()
diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
index 86a87223ebc..896ad49eaca 100644
--- a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
@@ -64,7 +64,7 @@
if(!check_icon_cache())
return
- overlays.Cut()
+ cut_overlays()
var/vent_icon = "vent"
@@ -80,7 +80,7 @@
else
vent_icon += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
- overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
+ add_overlay(icon_manager.get_atmos_icon("device", , , vent_icon))
/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
if(..())
diff --git a/code/ATMOSPHERICS/components/binary_devices/pipeturbine.dm b/code/ATMOSPHERICS/components/binary_devices/pipeturbine.dm
index 7ef1858b2f5..c111b36b0a6 100644
--- a/code/ATMOSPHERICS/components/binary_devices/pipeturbine.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/pipeturbine.dm
@@ -73,15 +73,15 @@
network2.update = 1
/obj/machinery/atmospherics/pipeturbine/update_icon()
- overlays.Cut()
+ cut_overlays()
if (dP > 10)
- overlays += image('icons/obj/pipeturbine.dmi', "moto-turb")
+ add_overlay(image('icons/obj/pipeturbine.dmi', "moto-turb"))
if (kin_energy > 100000)
- overlays += image('icons/obj/pipeturbine.dmi', "low-turb")
+ add_overlay(image('icons/obj/pipeturbine.dmi', "low-turb"))
if (kin_energy > 500000)
- overlays += image('icons/obj/pipeturbine.dmi', "med-turb")
+ add_overlay(image('icons/obj/pipeturbine.dmi', "med-turb"))
if (kin_energy > 1000000)
- overlays += image('icons/obj/pipeturbine.dmi', "hi-turb")
+ add_overlay(image('icons/obj/pipeturbine.dmi', "hi-turb"))
/obj/machinery/atmospherics/pipeturbine/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_wrench())
diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm
index 792d53d65d9..488855a71f6 100644
--- a/code/ATMOSPHERICS/components/unary/vent_pump.dm
+++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm
@@ -19,6 +19,7 @@
power_rating = 30000 //7500 W ~ 10 HP //VOREStation Edit - 30000 W
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY //connects to regular and supply pipes
+ blocks_emissive = FALSE
var/area/initial_loc
level = 1
@@ -141,7 +142,7 @@
if(!check_icon_cache())
return
- overlays.Cut()
+ cut_overlays()
var/vent_icon = "vent"
@@ -159,7 +160,7 @@
else
vent_icon += "[pump_direction ? "out" : "in"]"
- overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
+ add_overlay(icon_manager.get_atmos_icon("device", , , vent_icon))
/obj/machinery/atmospherics/unary/vent_pump/update_underlays()
if(..())
diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm
index 1443b296d0e..515cd37e7f4 100644
--- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm
+++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm
@@ -54,7 +54,7 @@
if(!check_icon_cache())
return
- overlays.Cut()
+ cut_overlays()
var/scrubber_icon = "scrubber"
@@ -67,7 +67,7 @@
else
scrubber_icon += "[use_power ? "[scrubbing ? "on" : "in"]" : "off"]"
- overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon)
+ add_overlay(icon_manager.get_atmos_icon("device", , , scrubber_icon))
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
if(..())
diff --git a/code/ATMOSPHERICS/pipes/cap.dm b/code/ATMOSPHERICS/pipes/cap.dm
index 2a63bb3a20a..72c9e829917 100644
--- a/code/ATMOSPHERICS/pipes/cap.dm
+++ b/code/ATMOSPHERICS/pipes/cap.dm
@@ -53,9 +53,9 @@
alpha = 255
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap[icon_connect_type]")
-
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "cap[icon_connect_type]"))
+
/obj/machinery/atmospherics/pipe/cap/atmos_init()
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
if (can_be_node(target, 1))
diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm
index a17f78e50df..a02f0e66de0 100644
--- a/code/ATMOSPHERICS/pipes/manifold.dm
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -102,9 +102,9 @@
alpha = 255
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
- overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type))
+ add_overlay(icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type))
underlays.Cut()
var/turf/T = get_turf(src)
diff --git a/code/ATMOSPHERICS/pipes/manifold4w.dm b/code/ATMOSPHERICS/pipes/manifold4w.dm
index 7273ac5288e..eac8494a65d 100644
--- a/code/ATMOSPHERICS/pipes/manifold4w.dm
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -102,9 +102,9 @@
alpha = 255
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
- overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type))
+ add_overlay(icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type))
underlays.Cut()
var/turf/T = get_turf(src)
diff --git a/code/ATMOSPHERICS/pipes/simple.dm b/code/ATMOSPHERICS/pipes/simple.dm
index e0f6f7d9516..1f427fb151d 100644
--- a/code/ATMOSPHERICS/pipes/simple.dm
+++ b/code/ATMOSPHERICS/pipes/simple.dm
@@ -117,12 +117,12 @@
alpha = 255
- overlays.Cut()
+ cut_overlays()
if(node1 && node2)
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]")
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]"))
else
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]")
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]"))
/obj/machinery/atmospherics/pipe/simple/update_underlays()
return
diff --git a/code/ATMOSPHERICS/pipes/universal.dm b/code/ATMOSPHERICS/pipes/universal.dm
index a72ef219f78..e1df93ee673 100644
--- a/code/ATMOSPHERICS/pipes/universal.dm
+++ b/code/ATMOSPHERICS/pipes/universal.dm
@@ -16,8 +16,8 @@
alpha = 255
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "universal"))
underlays.Cut()
if (node1)
@@ -54,8 +54,8 @@
alpha = 255
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "universal"))
underlays.Cut()
if (node1)
diff --git a/code/ZAS/ConnectionGroup.dm b/code/ZAS/ConnectionGroup.dm
index 11b1e22a0ba..2811ff6c77f 100644
--- a/code/ZAS/ConnectionGroup.dm
+++ b/code/ZAS/ConnectionGroup.dm
@@ -57,14 +57,12 @@ Class Procs:
*/
-
-/connection_edge/var/zone/A
-
-/connection_edge/var/list/connecting_turfs = list()
-/connection_edge/var/direct = 0
-/connection_edge/var/sleeping = 1
-
-/connection_edge/var/coefficient = 0
+/connection_edge
+ var/zone/A
+ var/list/connecting_turfs = list()
+ var/direct = 0
+ var/sleeping = 1
+ var/coefficient = 0
/connection_edge/New()
CRASH("Cannot make connection edge without specifications.")
@@ -119,7 +117,8 @@ Class Procs:
-/connection_edge/zone/var/zone/B
+/connection_edge/zone
+ var/zone/B
/connection_edge/zone/New(zone/A, zone/B)
@@ -189,8 +188,11 @@ Class Procs:
if(A == from) return B
else return A
-/connection_edge/unsimulated/var/turf/B
-/connection_edge/unsimulated/var/datum/gas_mixture/air
+/connection_edge/unsimulated
+ var/turf/B
+
+/connection_edge/unsimulated
+ var/datum/gas_mixture/air
/connection_edge/unsimulated/New(zone/A, turf/B)
src.A = A
diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm
index be103e7a55f..7f7b5752469 100644
--- a/code/ZAS/Controller.dm
+++ b/code/ZAS/Controller.dm
@@ -170,7 +170,7 @@ Class Procs:
if(T.needs_air_update) return
tiles_to_update |= T
#ifdef ZASDBG
- T.overlays += mark
+ T.add_overlay(mark)
#endif
T.needs_air_update = 1
diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm
index 6f0a67fd3eb..5aa2c73df20 100644
--- a/code/ZAS/Debug.dm
+++ b/code/ZAS/Debug.dm
@@ -12,8 +12,8 @@ var/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark")
/turf/var/tmp/dbg_img
/turf/proc/dbg(image/img, d = 0)
if(d > 0) img.dir = d
- overlays -= dbg_img
- overlays += img
+ cut_overlay(dbg_img)
+ add_overlay(img)
dbg_img = img
proc/soft_assert(thing,fail)
diff --git a/code/ZAS/Phoron.dm b/code/ZAS/Phoron.dm
index e12beb900ff..4017d0a74a7 100644
--- a/code/ZAS/Phoron.dm
+++ b/code/ZAS/Phoron.dm
@@ -63,11 +63,11 @@ obj/var/contaminated = 0
else
if(!contaminated)
contaminated = 1
- overlays += contamination_overlay
+ add_overlay(contamination_overlay)
/obj/item/proc/decontaminate()
contaminated = 0
- overlays -= contamination_overlay
+ cut_overlay(contamination_overlay)
/mob/proc/contaminate()
diff --git a/code/__defines/_lists.dm b/code/__defines/_lists.dm
index 247e9dfeb0e..582c026f3c8 100644
--- a/code/__defines/_lists.dm
+++ b/code/__defines/_lists.dm
@@ -39,7 +39,7 @@
#define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null
// Null-safe L.Cut()
-#define LAZYCLEARLIST(L) if(L) L.Cut()
+#define LAZYCLEARLIST(L) if(L) { L.Cut(); L = null; }
// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression.
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index 551e94183c1..639724eca25 100644
--- a/code/__defines/_planes+layers.dm
+++ b/code/__defines/_planes+layers.dm
@@ -50,10 +50,10 @@ What is the naming convention for planes or layers?
#define PLANE_LOOKINGGLASS_IMG -77 // For the Looking Glass holodecks
// OPENSPACE_PLANE reserves all planes between OPENSPACE_PLANE_START and OPENSPACE_PLANE_END inclusive
-#define OPENSPACE_PLANE -75 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 17)
+#define OPENSPACE_PLANE -75 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 27) //VOREStation Edit
#define OPENSPACE_PLANE_START -73
-#define OPENSPACE_PLANE_END -58
-#define OVER_OPENSPACE_PLANE -57
+#define OPENSPACE_PLANE_END -48 //VOREStation Edit
+#define OVER_OPENSPACE_PLANE -47 //VOREStation Edit
// Turf Planes
#define PLATING_PLANE -44 // Plating
@@ -122,9 +122,21 @@ What is the naming convention for planes or layers?
#define PLANE_ADMIN1 3 //Purely for shenanigans (below lighting)
#define PLANE_PLANETLIGHTING 4 //Lighting on planets
+
#define PLANE_LIGHTING 5 //Where the lighting (and darkness) lives
-#define PLANE_LIGHTING_ABOVE 6 //For glowy eyes etc. that shouldn't be affected by darkness
-#define PLANE_RUNECHAT 7
+ #define LIGHTING_RENDER_TARGET "LIGHT_PLANE"
+
+#define PLANE_O_LIGHTING_VISUAL 6 //For masking the lighting plane
+ #define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE"
+
+#define PLANE_LIGHTING_ABOVE 7 //For glowy eyes etc. that shouldn't be affected by darkness
+ #define LIGHTING_ABOVE_RENDER_TARGET "LIGHTING_ABOVE_PLANE"
+
+#define PLANE_EMISSIVE 8 //Glowing lights in otherwise dark areas using overlays/sprites
+ #define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE"
+ #define EMISSIVE_LAYER_UNBLOCKABLE 9999
+
+#define PLANE_RUNECHAT 9
#define PLANE_GHOSTS 10 //Spooooooooky ghooooooosts
#define PLANE_AI_EYE 11 //The AI eye lives here
diff --git a/code/__defines/color.dm b/code/__defines/color.dm
index c3db40eefb3..af112ef4d63 100644
--- a/code/__defines/color.dm
+++ b/code/__defines/color.dm
@@ -92,6 +92,7 @@
#define COLOR_LIGHT_VIOLET "#e7bfff"
#define COLOR_SAN_MARINO_BLUE "#4b75ab"
#define COLOR_OLIVE "#52613b" //VOREStation Addition
+#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
#define PIPE_COLOR_GREY "#808080"
#define PIPE_COLOR_RED "#ff0000"
@@ -171,4 +172,40 @@
#define COLOR_WEBHOOK_DEFAULT 0x8bbbd5 // "#8bbbd5"
#define COLOR_WEBHOOK_GOOD 0x2ECC71 // "#2ECC71"
#define COLOR_WEBHOOK_POOR 0xE67E22 // "#E67E22"
-#define COLOR_WEBHOOK_BAD 0xE74C3C // "#E74C3C"
\ No newline at end of file
+#define COLOR_WEBHOOK_BAD 0xE74C3C // "#E74C3C"
+
+//Some defines to generalise colours used in lighting.
+//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated
+#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130)
+#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100)
+#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250)
+
+#define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175)
+#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225)
+#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255)
+#define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248)
+#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225)
+#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125)
+#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50)
+#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50)
+#define LIGHT_COLOR_PURPLE "#952CF4" //Light Purple. rgb(149, 44, 244)
+#define LIGHT_COLOR_LAVENDER "#9B51FF" //Less-saturated light purple. rgb(155, 81, 255)
+
+//These ones aren't a direct colour like the ones above, because nothing would fit
+#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
+#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
+#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
+#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
+#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
+#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
+
+//Lighting values used by the station lights
+#define LIGHT_COLOR_FLUORESCENT_TUBE "#E0EFFF"
+#define LIGHT_COLOR_FLUORESCENT_FLASHLIGHT "#CDDDFF"
+#define LIGHT_COLOR_INCANDESCENT_TUBE "#fffed9"
+#define LIGHT_COLOR_INCANDESCENT_BULB "#ffe7ce"
+#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66"
+#define LIGHT_COLOR_NIGHTSHIFT "#EFCC86"
+
+//Fake ambient occlusion filter
+#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, offset=3, color="#04080F80")
diff --git a/code/__defines/dcs/flags.dm b/code/__defines/dcs/flags.dm
index 128c9f19387..84d332bd567 100644
--- a/code/__defines/dcs/flags.dm
+++ b/code/__defines/dcs/flags.dm
@@ -15,7 +15,10 @@
* Only elements created with the same arguments given after `id_arg_index` share an element instance
* The arguments are the same when the text and number values are the same and all other values have the same ref
*/
-#define ELEMENT_BESPOKE (1 << 1)
+#define ELEMENT_BESPOKE (1 << 1)
+/// Causes all detach arguments to be passed to detach instead of only being used to identify the element
+/// When this is used your Detach proc should have the same signature as your Attach proc
+#define ELEMENT_COMPLEX_DETACH (1 << 2)
// How multiple components of the exact same type are handled in the same datum
/// old component is deleted (default)
diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm
index c6edaa80e4a..7079362659d 100644
--- a/code/__defines/dcs/signals.dm
+++ b/code/__defines/dcs/signals.dm
@@ -42,6 +42,9 @@
#define COMSIG_PARENT_QDELETING "parent_qdeleting"
/// generic topic handler (usr, href_list)
#define COMSIG_TOPIC "handle_topic"
+/// from datum ui_act (usr, action)
+#define COMSIG_UI_ACT "COMSIG_UI_ACT"
+
/// fires on the target datum when an element is attached to it (/datum/element)
#define COMSIG_ELEMENT_ATTACH "element_attach"
@@ -162,6 +165,8 @@
#define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin"
///called when an atom stops orbiting another atom: (atom)
#define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop"
+///from base of atom/set_opacity(): (new_opacity)
+#define COMSIG_ATOM_SET_OPACITY "atom_set_opacity"
/////////////////
///from base of atom/attack_ghost(): (mob/dead/observer/ghost)
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost"
@@ -737,4 +742,40 @@
#define COMSIG_TRIGGERED_ALARM "ssalarm_triggered"
#define COMSIG_CANCELLED_ALARM "ssalarm_cancelled"
-#define COMSIG_REAGENTS_CRAFTING_PING "reagents_crafting_ping"
\ No newline at end of file
+#define COMSIG_REAGENTS_CRAFTING_PING "reagents_crafting_ping"
+
+// Lighting:
+///from base of [atom/proc/set_light]: (l_range, l_power, l_color, l_on)
+#define COMSIG_ATOM_SET_LIGHT "atom_set_light"
+ /// Blocks [/atom/proc/set_light], [/atom/proc/set_light_power], [/atom/proc/set_light_range], [/atom/proc/set_light_color], [/atom/proc/set_light_on], and [/atom/proc/set_light_flags].
+ #define COMPONENT_BLOCK_LIGHT_UPDATE (1<<0)
+///Called right before the atom changes the value of light_power to a different one, from base [atom/proc/set_light_power]: (new_power)
+#define COMSIG_ATOM_SET_LIGHT_POWER "atom_set_light_power"
+///Called right after the atom changes the value of light_power to a different one, from base of [/atom/proc/set_light_power]: (old_power)
+#define COMSIG_ATOM_UPDATE_LIGHT_POWER "atom_update_light_power"
+///Called right before the atom changes the value of light_range to a different one, from base [atom/proc/set_light_range]: (new_range)
+#define COMSIG_ATOM_SET_LIGHT_RANGE "atom_set_light_range"
+///Called right after the atom changes the value of light_range to a different one, from base of [/atom/proc/set_light_range]: (old_range)
+#define COMSIG_ATOM_UPDATE_LIGHT_RANGE "atom_update_light_range"
+///Called right before the atom changes the value of light_color to a different one, from base [atom/proc/set_light_color]: (new_color)
+#define COMSIG_ATOM_SET_LIGHT_COLOR "atom_set_light_color"
+///Called right after the atom changes the value of light_color to a different one, from base of [/atom/proc/set_light_color]: (old_color)
+#define COMSIG_ATOM_UPDATE_LIGHT_COLOR "atom_update_light_color"
+///Called right before the atom changes the value of light_on to a different one, from base [atom/proc/set_light_on]: (new_value)
+#define COMSIG_ATOM_SET_LIGHT_ON "atom_set_light_on"
+///Called right after the atom changes the value of light_on to a different one, from base of [/atom/proc/set_light_on]: (old_value)
+#define COMSIG_ATOM_UPDATE_LIGHT_ON "atom_update_light_on"
+///Called right before the atom changes the value of light_flags to a different one, from base [atom/proc/set_light_flags]: (new_flags)
+#define COMSIG_ATOM_SET_LIGHT_FLAGS "atom_set_light_flags"
+///Called right after the atom changes the value of light_flags to a different one, from base of [/atom/proc/set_light_flags]: (old_flags)
+#define COMSIG_ATOM_UPDATE_LIGHT_FLAGS "atom_update_light_flags"
+
+// /datum/element/light_eater
+///from base of [/datum/element/light_eater/proc/table_buffet]: (list/light_queue, datum/light_eater)
+#define COMSIG_LIGHT_EATER_QUEUE "light_eater_queue"
+///from base of [/datum/element/light_eater/proc/devour]: (datum/light_eater)
+#define COMSIG_LIGHT_EATER_ACT "light_eater_act"
+ ///Prevents the default light eater behavior from running in case of immunity or custom behavior
+ #define COMPONENT_BLOCK_LIGHT_EATER (1<<0)
+///from base of [/datum/element/light_eater/proc/devour]: (atom/eaten_light)
+#define COMSIG_LIGHT_EATER_DEVOUR "light_eater_devour"
diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm
index 2ff8f44dbab..8ac15ebc535 100644
--- a/code/__defines/flags.dm
+++ b/code/__defines/flags.dm
@@ -13,6 +13,10 @@
GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
+/* Directions */
+///All the cardinal direction bitflags.
+#define ALL_CARDINALS (NORTH|SOUTH|EAST|WEST)
+
// datum_flags
#define DF_VAR_EDITED (1<<0)
#define DF_ISPROCESSING (1<<1)
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
index 999bb7473ad..bf854548760 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -1,88 +1,119 @@
-#define FOR_DVIEW(type, range, center, invis_flags) \
- dview_mob.loc = center; \
- dview_mob.see_invisible = invis_flags; \
- for(type in view(range, dview_mob))
+///Object doesn't use any of the light systems. Should be changed to add a light source to the object.
+#define NO_LIGHT_SUPPORT 0
+///Light made with the lighting datums, applying a matrix.
+#define STATIC_LIGHT 1
+///Light made by masking the lighting darkness plane.
+#define MOVABLE_LIGHT 2
+///Light made by masking the lighting darkness plane, and is directional.
+#define MOVABLE_LIGHT_DIRECTIONAL 3
-#define END_FOR_DVIEW dview_mob.loc = null
+///Is a movable light source attached to another movable (its loc), meaning that the lighting component should go one level deeper.
+#define LIGHT_ATTACHED (1<<0)
-#define LIGHTING_FALLOFF 1 // type of falloff to use for lighting; 1 for circular, 2 for square
-#define LIGHTING_LAMBERTIAN 0 // use lambertian shading for light sources
-#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
+//Bay lighting engine shit, not in /code/modules/lighting because BYOND is being shit about it
+/// frequency, in 1/10ths of a second, of the lighting process
+#define LIGHTING_INTERVAL 5
-#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
-#define LIGHTING_ICON_STATE_DARK "soft_dark" // Change between "soft_dark" and "dark" to swap soft darkvision
+#define MINIMUM_USEFUL_LIGHT_RANGE 1.4
-#define LIGHTING_ROUND_VALUE (1 / 64) // Value used to round lumcounts, values smaller than 1/69 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
+/// type of falloff to use for lighting; 1 for circular, 2 for square
+#define LIGHTING_FALLOFF 1
+/// use lambertian shading for light sources
+#define LIGHTING_LAMBERTIAN 0
+/// height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
+#define LIGHTING_HEIGHT 1
+/// Value used to round lumcounts, values smaller than 1/129 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
+#define LIGHTING_ROUND_VALUE (1 / 64)
-#define LIGHTING_SOFT_THRESHOLD 0.05 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays. This also should be the transparancy of the "soft_dark" icon state.
+/// icon used for lighting shading effects
+#define LIGHTING_ICON 'icons/effects/lighting_object.dmi'
-#define LIGHTING_MULT_FACTOR 0.5
+/// If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting objects.
+/// Set to zero to disable soft lighting. Luminosity changes then work if it's lit at all.
+#define LIGHTING_SOFT_THRESHOLD 0
-// If I were you I'd leave this alone.
+/// If I were you I'd leave this alone.
#define LIGHTING_BASE_MATRIX \
list \
( \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
0, 0, 0, 1 \
) \
-// Helpers so we can (more easily) control the colour matrices.
-#define CL_MATRIX_RR 1
-#define CL_MATRIX_RG 2
-#define CL_MATRIX_RB 3
-#define CL_MATRIX_RA 4
-#define CL_MATRIX_GR 5
-#define CL_MATRIX_GG 6
-#define CL_MATRIX_GB 7
-#define CL_MATRIX_GA 8
-#define CL_MATRIX_BR 9
-#define CL_MATRIX_BG 10
-#define CL_MATRIX_BB 11
-#define CL_MATRIX_BA 12
-#define CL_MATRIX_AR 13
-#define CL_MATRIX_AG 14
-#define CL_MATRIX_AB 15
-#define CL_MATRIX_AA 16
-#define CL_MATRIX_CR 17
-#define CL_MATRIX_CG 18
-#define CL_MATRIX_CB 19
-#define CL_MATRIX_CA 20
+///How many tiles standard fires glow.
+#define LIGHT_RANGE_FIRE 3
-//Some defines to generalise colours used in lighting.
-//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated
-#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130)
-#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100)
-#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250)
+#define LIGHTING_PLANE_ALPHA_VISIBLE 255
+#define LIGHTING_PLANE_ALPHA_NV_TRAIT 245
+#define LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE 192
+/// For lighting alpha, small amounts lead to big changes. even at 128 its hard to figure out what is dark and what is light, at 64 you almost can't even tell.
+#define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 128
+#define LIGHTING_PLANE_ALPHA_INVISIBLE 0
-#define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175)
-#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225)
-#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255)
-#define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248)
-#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225)
-#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125)
-#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50)
-#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50)
-#define LIGHT_COLOR_PURPLE "#952CF4" //Light Purple. rgb(149, 44, 244)
-#define LIGHT_COLOR_LAVENDER "#9B51FF" //Less-saturated light purple. rgb(155, 81, 255)
+//lighting area defines
+/// dynamic lighting disabled (area stays at full brightness)
+#define DYNAMIC_LIGHTING_DISABLED 0
+/// dynamic lighting enabled
+#define DYNAMIC_LIGHTING_ENABLED 1
+/// dynamic lighting enabled even if the area doesn't require power
+#define DYNAMIC_LIGHTING_FORCED 2
+/// dynamic lighting enabled only if starlight is.
+#define DYNAMIC_LIGHTING_IFSTARLIGHT 3
+#define IS_DYNAMIC_LIGHTING(A) A.dynamic_lighting
-//These ones aren't a direct colour like the ones above, because nothing would fit
-#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
-#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
-#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
-#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
-#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
-#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
-//Lighting values used by the station lights
-#define LIGHT_COLOR_FLUORESCENT_TUBE "#E0EFFF"
-#define LIGHT_COLOR_FLUORESCENT_FLASHLIGHT "#CDDDFF"
-#define LIGHT_COLOR_INCANDESCENT_TUBE "#FFFEB8"
-#define LIGHT_COLOR_INCANDESCENT_BULB "#FFDDBB"
-#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66"
-#define LIGHT_COLOR_NIGHTSHIFT "#EFCC86"
+//code assumes higher numbers override lower numbers.
+#define LIGHTING_NO_UPDATE 0
+#define LIGHTING_VIS_UPDATE 1
+#define LIGHTING_CHECK_UPDATE 2
+#define LIGHTING_FORCE_UPDATE 3
-//Fake ambient occlusion filter
-#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-1, size=2, offset=2, color="#04080F55") //VOREStation Edit for prettier visuals.
+#define FLASH_LIGHT_DURATION 2
+#define FLASH_LIGHT_POWER 3
+#define FLASH_LIGHT_RANGE 3.8
+
+// Emissive blocking.
+/// Uses vis_overlays to leverage caching so that very few new items need to be made for the overlay. For anything that doesn't change outline or opaque area much or at all.
+#define EMISSIVE_BLOCK_GENERIC 1
+/// Uses a dedicated render_target object to copy the entire appearance in real time to the blocking layer. For things that can change in appearance a lot from the base state, like humans.
+#define EMISSIVE_BLOCK_UNIQUE 2
+
+/// The color matrix applied to all emissive overlays. Should be solely dependent on alpha and not have RGB overlap with [EM_BLOCK_COLOR].
+#define EMISSIVE_COLOR list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,1,0)
+/// A globaly cached version of [EMISSIVE_COLOR] for quick access.
+GLOBAL_LIST_INIT(emissive_color, EMISSIVE_COLOR)
+/// The color matrix applied to all emissive blockers. Should be solely dependent on alpha and not have RGB overlap with [EMISSIVE_COLOR].
+#define EM_BLOCK_COLOR list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
+/// A globaly cached version of [EM_BLOCK_COLOR] for quick access.
+GLOBAL_LIST_INIT(em_block_color, EM_BLOCK_COLOR)
+/// The color matrix used to mask out emissive blockers on the emissive plane. Alpha should default to zero, be solely dependent on the RGB value of [EMISSIVE_COLOR], and be independant of the RGB value of [EM_BLOCK_COLOR].
+#define EM_MASK_MATRIX list(0,0,0,1/3, 0,0,0,1/3, 0,0,0,1/3, 0,0,0,0, 1,1,1,0)
+/// A globaly cached version of [EM_MASK_MATRIX] for quick access.
+GLOBAL_LIST_INIT(em_mask_matrix, EM_MASK_MATRIX)
+
+/// Returns the red part of a #RRGGBB hex sequence as number
+#define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4))
+
+/// Returns the green part of a #RRGGBB hex sequence as number
+#define GETGREENPART(hexa) hex2num(copytext(hexa, 4, 6))
+
+/// Returns the blue part of a #RRGGBB hex sequence as number
+#define GETBLUEPART(hexa) hex2num(copytext(hexa, 6, 8))
+
+/// Parse the hexadecimal color into lumcounts of each perspective.
+#define PARSE_LIGHT_COLOR(source) \
+do { \
+ if (source.light_color != COLOR_WHITE) { \
+ var/__light_color = source.light_color; \
+ source.lum_r = GETREDPART(__light_color) / 255; \
+ source.lum_g = GETGREENPART(__light_color) / 255; \
+ source.lum_b = GETBLUEPART(__light_color) / 255; \
+ } else { \
+ source.lum_r = 1; \
+ source.lum_g = 1; \
+ source.lum_b = 1; \
+ }; \
+} while (FALSE)
diff --git a/code/__defines/lighting_vr.dm b/code/__defines/lighting_vr.dm
index 0cd6b060a17..a7f51e8bbc2 100644
--- a/code/__defines/lighting_vr.dm
+++ b/code/__defines/lighting_vr.dm
@@ -1,2 +1,4 @@
#define LIGHT_COLOR_INCANDESCENT_TUBE "#E0EFF0"
-#define LIGHT_COLOR_INCANDESCENT_BULB "#FFFEB8"
\ No newline at end of file
+#define LIGHT_COLOR_INCANDESCENT_BULB "#FFFEB8"
+//Fake ambient occlusion filter
+#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-1, size=2, offset=2, color="#04080F55") //VOREStation Edit for prettier visuals.
\ No newline at end of file
diff --git a/code/__defines/map.dm b/code/__defines/map.dm
index 9b8856c70ea..9bb14692125 100644
--- a/code/__defines/map.dm
+++ b/code/__defines/map.dm
@@ -8,7 +8,7 @@
#define MAP_LEVEL_CONSOLES 0x040 // Z-levels available to various consoles, such as the crew monitor (when that gets coded in). Defaults to station_levels if unset.
#define MAP_LEVEL_XENOARCH_EXEMPT 0x080 // Z-levels exempt from xenoarch digsite generation.
#define MAP_LEVEL_PERSIST 0x100 // Z-levels where SSpersistence should persist between rounds
-#define MAP_LEVEL_MAPPABLE 0x200 // Z-levels where SSpersistence should persist between rounds
+#define MAP_LEVEL_MAPPABLE 0x200 // Z-levels where mapping units will work fully
// Misc map defines.
-#define SUBMAP_MAP_EDGE_PAD 8 // Automatically created submaps are forbidden from being this close to the main map's edge. //VOREStation Edit
\ No newline at end of file
+#define SUBMAP_MAP_EDGE_PAD 8 // Automatically created submaps are forbidden from being this close to the main map's edge. //VOREStation Edit
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 824155f93eb..b853f4e9b55 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -20,6 +20,7 @@
#define SEE_INVISIBLE_MINIMUM 5
#define INVISIBILITY_MAXIMUM 100
+#define INVISIBILITY_ABSTRACT 101 //only used for abstract objects, things that are not really there.
// Pseudo-Invis, like Ninja, Ling, Etc.
#define EFFECTIVE_INVIS 50 // Below this, can't be examined, may as well be invisible to the game
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 7513ab3c006..b70001cbd61 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -377,37 +377,40 @@
//Vision flags, for dealing with plane visibility
#define VIS_FULLBRIGHT 1
#define VIS_LIGHTING 2
-#define VIS_GHOSTS 3
-#define VIS_AI_EYE 4
+#define VIS_O_LIGHT 3
+#define VIS_EMISSIVE 4
-#define VIS_CH_STATUS 5
-#define VIS_CH_HEALTH 6
-#define VIS_CH_LIFE 7
-#define VIS_CH_ID 8
-#define VIS_CH_WANTED 9
-#define VIS_CH_IMPLOYAL 10
-#define VIS_CH_IMPTRACK 11
-#define VIS_CH_IMPCHEM 12
-#define VIS_CH_SPECIAL 13
-#define VIS_CH_STATUS_OOC 14
+#define VIS_GHOSTS 5
+#define VIS_AI_EYE 6
-#define VIS_ADMIN1 15
-#define VIS_ADMIN2 16
-#define VIS_ADMIN3 17
+#define VIS_CH_STATUS 7
+#define VIS_CH_HEALTH 8
+#define VIS_CH_LIFE 9
+#define VIS_CH_ID 10
+#define VIS_CH_WANTED 11
+#define VIS_CH_IMPLOYAL 12
+#define VIS_CH_IMPTRACK 13
+#define VIS_CH_IMPCHEM 14
+#define VIS_CH_SPECIAL 15
+#define VIS_CH_STATUS_OOC 16
-#define VIS_MESONS 18
+#define VIS_ADMIN1 17
+#define VIS_ADMIN2 18
+#define VIS_ADMIN3 19
-#define VIS_TURFS 19
-#define VIS_OBJS 20
-#define VIS_MOBS 21
+#define VIS_MESONS 20
-#define VIS_BUILDMODE 22
+#define VIS_TURFS 21
+#define VIS_OBJS 22
+#define VIS_MOBS 23
-#define VIS_CLOAKED 23
+#define VIS_BUILDMODE 24
-#define VIS_STATUS 24
+#define VIS_CLOAKED 25
-#define VIS_COUNT 24 //Must be highest number from above.
+#define VIS_STATUS 26
+
+#define VIS_COUNT 26 //Must be highest number from above.
//Some mob icon layering defines
#define BODY_LAYER -100
diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm
index dbd66d90620..116358e5779 100644
--- a/code/__defines/mobs_vr.dm
+++ b/code/__defines/mobs_vr.dm
@@ -1,13 +1,13 @@
#undef VIS_COUNT
-#define VIS_CH_STATUS_R 24
-#define VIS_CH_HEALTH_VR 25
-#define VIS_CH_BACKUP 26
-#define VIS_CH_VANTAG 27
+#define VIS_CH_STATUS_R 27
+#define VIS_CH_HEALTH_VR 28
+#define VIS_CH_BACKUP 29
+#define VIS_CH_VANTAG 30
-#define VIS_AUGMENTED 28
+#define VIS_AUGMENTED 31
-#define VIS_COUNT 28
+#define VIS_COUNT 31
//Protean organs
#define O_ORCH "orchestrator"
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
index 0847e447dbb..9ad2af05047 100644
--- a/code/__defines/subsystems.dm
+++ b/code/__defines/subsystems.dm
@@ -56,6 +56,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_SQLITE 40
#define INIT_ORDER_MEDIA_TRACKS 38 // Gotta get that lobby music up, yo
#define INIT_ORDER_CHEMISTRY 35
+#define INIT_ORDER_VIS 32
#define INIT_ORDER_SKYBOX 30
#define INIT_ORDER_MAPPING 25
#define INIT_ORDER_SOUNDS 23
@@ -94,6 +95,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_SUPPLY 5
#define FIRE_PRIORITY_NIGHTSHIFT 5
#define FIRE_PRIORITY_PLANTS 5
+#define FIRE_PRIORITY_VIS 5
#define FIRE_PRIORITY_ORBIT 7
#define FIRE_PRIORITY_VOTE 8
#define FIRE_PRIORITY_INSTRUMENTS 9
diff --git a/code/__defines/tgui.dm b/code/__defines/tgui.dm
index 3d706a4e0fa..c261e5ecdcf 100644
--- a/code/__defines/tgui.dm
+++ b/code/__defines/tgui.dm
@@ -18,6 +18,14 @@
/// Get a pool index of the provided window id
#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13))
+/// Creates a message packet for sending via output()
+// This is {"type":type,"payload":payload}, but pre-encoded. This is much faster
+// than doing it the normal way.
+// To ensure this is correct, this is unit tested in tgui_create_message.
+#define TGUI_CREATE_MESSAGE(type, payload) ( \
+ "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \
+)
+
/// Max length for Modal Input
#define TGUI_MODAL_INPUT_MAX_LENGTH 1024
/// Max length for Modal Input for names
diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm
index 64593f6e114..770d58573f8 100644
--- a/code/__defines/turfs.dm
+++ b/code/__defines/turfs.dm
@@ -17,4 +17,6 @@
#define SMOOTH_GREYLIST 4 // Use a whitelist and a blacklist at the same time. atom smoothing only
#define isCardinal(x) (x == NORTH || x == SOUTH || x == EAST || x == WEST)
-#define isDiagonal(x) (x == NORTHEAST || x == SOUTHEAST || x == NORTHWEST || x == SOUTHWEST)
\ No newline at end of file
+#define isDiagonal(x) (x == NORTHEAST || x == SOUTHEAST || x == NORTHWEST || x == SOUTHWEST)
+
+#define IS_OPAQUE_TURF(turf) (turf.directional_opacity == ALL_CARDINALS)
diff --git a/code/_global_vars/bitfields.dm b/code/_global_vars/bitfields.dm
index 891c50ce88b..be3de4adeb5 100644
--- a/code/_global_vars/bitfields.dm
+++ b/code/_global_vars/bitfields.dm
@@ -2,6 +2,38 @@ GLOBAL_LIST_INIT(bitfields, list(
"datum_flags" = list(
"DF_VAR_EDITED" = DF_VAR_EDITED,
"DF_ISPROCESSING" = DF_ISPROCESSING
- )
-
+ ),
+ "appearance_flags" = list(
+ "KEEP_APART" = KEEP_APART,
+ "KEEP_TOGETHER" = KEEP_TOGETHER,
+ "LONG_GLIDE" = LONG_GLIDE,
+ "NO_CLIENT_COLOR" = NO_CLIENT_COLOR,
+ "PIXEL_SCALE" = PIXEL_SCALE,
+ "PLANE_MASTER" = PLANE_MASTER,
+ "RESET_ALPHA" = RESET_ALPHA,
+ "RESET_COLOR" = RESET_COLOR,
+ "RESET_TRANSFORM" = RESET_TRANSFORM,
+ "TILE_BOUND" = TILE_BOUND,
+ ),
+ "vis_flags" = list(
+ "VIS_HIDE" = VIS_HIDE,
+ "VIS_INHERIT_DIR" = VIS_INHERIT_DIR,
+ "VIS_INHERIT_ICON" = VIS_INHERIT_ICON,
+ "VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE,
+ "VIS_INHERIT_ID" = VIS_INHERIT_ID,
+ "VIS_INHERIT_LAYER" = VIS_INHERIT_LAYER,
+ "VIS_INHERIT_PLANE" = VIS_INHERIT_PLANE,
+ "VIS_UNDERLAY" = VIS_UNDERLAY,
+ ),
+ "sight" = list(
+ "BLIND" = BLIND,
+ "SEE_BLACKNESS" = SEE_BLACKNESS,
+ "SEE_INFRA" = SEE_INFRA,
+ "SEE_MOBS" = SEE_MOBS,
+ "SEE_OBJS" = SEE_OBJS,
+ "SEE_PIXELS" = SEE_PIXELS,
+ "SEE_SELF" = SEE_SELF,
+ "SEE_THRU" = SEE_THRU,
+ "SEE_TURFS" = SEE_TURFS,
+ ),
))
diff --git a/code/_helpers/atom_movables.dm b/code/_helpers/atom_movables.dm
index b838f868e64..fbe2ab2a021 100644
--- a/code/_helpers/atom_movables.dm
+++ b/code/_helpers/atom_movables.dm
@@ -21,6 +21,8 @@
//Find coordinates
var/turf/T = get_turf(AM) //use AM's turfs, as it's coords are the same as AM's AND AM's coords are lost if it is inside another atom
+ if(!T)
+ return null
var/final_x = T.x + rough_x
var/final_y = T.y + rough_y
diff --git a/code/_helpers/global_lists_vr.dm b/code/_helpers/global_lists_vr.dm
index 6c1fd9d261e..0d2ed5e5d63 100644
--- a/code/_helpers/global_lists_vr.dm
+++ b/code/_helpers/global_lists_vr.dm
@@ -232,6 +232,7 @@ var/global/list/contamination_flavors = list(
"Dirty" = contamination_flavors_dirty,
"Musky" = contamination_flavors_musky,
"Smelly" = contamination_flavors_smelly,
+ "Slimy" = contamination_flavors_slimy,
"Wet" = contamination_flavors_wet)
var/global/list/contamination_flavors_generic = list("acrid",
@@ -435,6 +436,21 @@ var/global/list/contamination_flavors_musky = list("drenched",
"sticky",
"tainted")
+var/global/list/contamination_flavors_slimy = list("slimy",
+ "sloppy",
+ "drippy",
+ "glistening",
+ "dripping",
+ "gunky",
+ "slimed",
+ "mucky",
+ "viscous",
+ "dank",
+ "glutinous",
+ "syrupy",
+ "slippery",
+ "gelatinous")
+
var/global/list/contamination_colors = list("green",
"white",
"black",
@@ -522,4 +538,4 @@ var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
return 1 // Hooks must return 1
var/global/list/weavable_structures = list()
-var/global/list/weavable_items = list()
\ No newline at end of file
+var/global/list/weavable_items = list()
diff --git a/code/_helpers/lighting.dm b/code/_helpers/lighting.dm
new file mode 100644
index 00000000000..7cfd434e699
--- /dev/null
+++ b/code/_helpers/lighting.dm
@@ -0,0 +1,10 @@
+/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR].
+/proc/emissive_appearance(icon, icon_state = "", layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE)
+ var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, PLANE_EMISSIVE, alpha, appearance_flags)
+ appearance.color = GLOB.emissive_color
+ return appearance
+
+/proc/em_block_image_generic(var/image/I)
+ var/mutable_appearance/em_overlay = mutable_appearance(I.icon, I.icon_state, plane = PLANE_EMISSIVE, alpha = I.alpha, appearance_flags = KEEP_APART)
+ em_overlay.color = GLOB.em_block_color
+ return em_overlay
diff --git a/code/_helpers/sorts/comparators.dm b/code/_helpers/sorts/comparators.dm
index de64ad26f7a..b1980d6da14 100644
--- a/code/_helpers/sorts/comparators.dm
+++ b/code/_helpers/sorts/comparators.dm
@@ -88,3 +88,6 @@
/proc/cmp_media_track_asc(datum/track/A, datum/track/B)
var/genre_sort = sorttext(B.genre || "Uncategorized", A.genre || "Uncategorized")
return genre_sort || sorttext(B.title, A.title)
+
+/proc/cmp_filter_data_priority(list/A, list/B)
+ return A["priority"] - B["priority"]
diff --git a/code/_helpers/visual_filters.dm b/code/_helpers/visual_filters.dm
index 6cafa5a04d2..96f68710000 100644
--- a/code/_helpers/visual_filters.dm
+++ b/code/_helpers/visual_filters.dm
@@ -1,20 +1,306 @@
-// These involve BYOND's built in filters that do visual effects, and not stuff that distinguishes between things.
+#define ICON_NOT_SET "Not Set"
+//This is stored as a nested list instead of datums or whatever because it json encodes nicely for usage in tgui
+GLOBAL_LIST_INIT(master_filter_info, list(
+ "alpha" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "icon" = ICON_NOT_SET,
+ "render_source" = "",
+ "flags" = 0
+ ),
+ "flags" = list(
+ "MASK_INVERSE" = MASK_INVERSE,
+ "MASK_SWAP" = MASK_SWAP
+ )
+ ),
+ "angular_blur" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 1
+ )
+ ),
+ /* Not supported because making a proper matrix editor on the frontend would be a huge dick pain.
+ Uncomment if you ever implement it
+ "color" = list(
+ "defaults" = list(
+ "color" = matrix(),
+ "space" = FILTER_COLOR_RGB
+ )
+ ),
+ */
+ "displace" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = null,
+ "icon" = ICON_NOT_SET,
+ "render_source" = ""
+ )
+ ),
+ "drop_shadow" = list(
+ "defaults" = list(
+ "x" = 1,
+ "y" = -1,
+ "size" = 1,
+ "offset" = 0,
+ "color" = COLOR_HALF_TRANSPARENT_BLACK
+ )
+ ),
+ "blur" = list(
+ "defaults" = list(
+ "size" = 1
+ )
+ ),
+ "layer" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "icon" = ICON_NOT_SET,
+ "render_source" = "",
+ "flags" = FILTER_OVERLAY,
+ "color" = "",
+ "transform" = null,
+ "blend_mode" = BLEND_DEFAULT
+ )
+ ),
+ "motion_blur" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0
+ )
+ ),
+ "outline" = list(
+ "defaults" = list(
+ "size" = 0,
+ "color" = COLOR_BLACK,
+ "flags" = NONE
+ ),
+ "flags" = list(
+ "OUTLINE_SHARP" = OUTLINE_SHARP,
+ "OUTLINE_SQUARE" = OUTLINE_SQUARE
+ )
+ ),
+ "radial_blur" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 0.01
+ )
+ ),
+ "rays" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 16,
+ "color" = COLOR_WHITE,
+ "offset" = 0,
+ "density" = 10,
+ "threshold" = 0.5,
+ "factor" = 0,
+ "flags" = FILTER_OVERLAY | FILTER_UNDERLAY
+ ),
+ "flags" = list(
+ "FILTER_OVERLAY" = FILTER_OVERLAY,
+ "FILTER_UNDERLAY" = FILTER_UNDERLAY
+ )
+ ),
+ "ripple" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 1,
+ "repeat" = 2,
+ "radius" = 0,
+ "falloff" = 1,
+ "flags" = NONE
+ ),
+ "flags" = list(
+ "WAVE_BOUNDED" = WAVE_BOUNDED
+ )
+ ),
+ "wave" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 1,
+ "offset" = 0,
+ "flags" = NONE
+ ),
+ "flags" = list(
+ "WAVE_SIDEWAYS" = WAVE_SIDEWAYS,
+ "WAVE_BOUNDED" = WAVE_BOUNDED
+ )
+ )
+))
-// All of this ported from TG.
-/atom/movable
- var/list/filter_data // For handling persistent filters
+#undef ICON_NOT_SET
-/proc/cmp_filter_data_priority(list/A, list/B)
- return A["priority"] - B["priority"]
+//Helpers to generate lists for filter helpers
+//This is the only practical way of writing these that actually produces sane lists
+/proc/alpha_mask_filter(x, y, icon/icon, render_source, flags)
+ . = list("type" = "alpha")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(icon))
+ .["icon"] = icon
+ if(!isnull(render_source))
+ .["render_source"] = render_source
+ if(!isnull(flags))
+ .["flags"] = flags
-/atom/movable/proc/add_filter(filter_name, priority, list/params)
+/proc/angular_blur_filter(x, y, size)
+ . = list("type" = "angular_blur")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(size))
+ .["size"] = size
+
+/proc/color_matrix_filter(matrix/in_matrix, space)
+ . = list("type" = "color")
+ .["color"] = in_matrix
+ if(!isnull(space))
+ .["space"] = space
+
+/proc/displacement_map_filter(icon, render_source, x, y, size = 32)
+ . = list("type" = "displace")
+ if(!isnull(icon))
+ .["icon"] = icon
+ if(!isnull(render_source))
+ .["render_source"] = render_source
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(size))
+ .["size"] = size
+
+/proc/drop_shadow_filter(x, y, size, offset, color)
+ . = list("type" = "drop_shadow")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(offset))
+ .["offset"] = offset
+ if(!isnull(color))
+ .["color"] = color
+
+/proc/gauss_blur_filter(size)
+ . = list("type" = "blur")
+ if(!isnull(size))
+ .["size"] = size
+
+/proc/layering_filter(icon, render_source, x, y, flags, color, transform, blend_mode)
+ . = list("type" = "layer")
+ if(!isnull(icon))
+ .["icon"] = icon
+ if(!isnull(render_source))
+ .["render_source"] = render_source
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(color))
+ .["color"] = color
+ if(!isnull(flags))
+ .["flags"] = flags
+ if(!isnull(transform))
+ .["transform"] = transform
+ if(!isnull(blend_mode))
+ .["blend_mode"] = blend_mode
+
+/proc/motion_blur_filter(x, y)
+ . = list("type" = "motion_blur")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+
+/proc/outline_filter(size, color, flags)
+ . = list("type" = "outline")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(color))
+ .["color"] = color
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/proc/radial_blur_filter(size, x, y)
+ . = list("type" = "radial_blur")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+
+/proc/rays_filter(size, color, offset, density, threshold, factor, x, y, flags)
+ . = list("type" = "rays")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(color))
+ .["color"] = color
+ if(!isnull(offset))
+ .["offset"] = offset
+ if(!isnull(density))
+ .["density"] = density
+ if(!isnull(threshold))
+ .["threshold"] = threshold
+ if(!isnull(factor))
+ .["factor"] = factor
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/proc/ripple_filter(radius, size, falloff, repeat, x, y, flags)
+ . = list("type" = "ripple")
+ if(!isnull(radius))
+ .["radius"] = radius
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(falloff))
+ .["falloff"] = falloff
+ if(!isnull(repeat))
+ .["repeat"] = repeat
+ if(!isnull(flags))
+ .["flags"] = flags
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+
+/proc/wave_filter(x, y, size, offset, flags)
+ . = list("type" = "wave")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(offset))
+ .["offset"] = offset
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/atom/proc/add_filter(name,priority,list/params)
LAZYINITLIST(filter_data)
var/list/p = params.Copy()
p["priority"] = priority
- filter_data[filter_name] = p
+ filter_data[name] = p
update_filters()
-/atom/movable/proc/update_filters()
+/atom/proc/update_filters()
filters = null
filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
for(var/f in filter_data)
@@ -22,15 +308,77 @@
var/list/arguments = data.Copy()
arguments -= "priority"
filters += filter(arglist(arguments))
+ UNSETEMPTY(filter_data)
-/atom/movable/proc/get_filter(filter_name)
- if(filter_data && filter_data[filter_name])
- return filters[filter_data.Find(filter_name)]
+/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
+ var/filter = get_filter(name)
+ if(!filter)
+ return
-// Polaris Extensions
-/atom/movable/proc/remove_filter(filter_name)
- var/thing = get_filter(filter_name)
- if(thing)
- LAZYREMOVE(filter_data, filter_name)
- filters -= thing
- update_filters()
\ No newline at end of file
+ var/list/old_filter_data = filter_data[name]
+
+ var/list/params = old_filter_data.Copy()
+ for(var/thing in new_params)
+ params[thing] = new_params[thing]
+
+ animate(filter, new_params, time = time, easing = easing, loop = loop)
+ for(var/param in params)
+ filter_data[name][param] = params[param]
+
+/atom/proc/change_filter_priority(name, new_priority)
+ if(!filter_data || !filter_data[name])
+ return
+
+ filter_data[name]["priority"] = new_priority
+ update_filters()
+
+/obj/item/update_filters()
+ . = ..()
+ /* Will port this from TG
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+ */
+
+/atom/proc/get_filter(name)
+ if(filter_data && filter_data[name])
+ return filters[filter_data.Find(name)]
+
+/atom/proc/remove_filter(name_or_names)
+ if(!filter_data)
+ return
+
+ var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)
+
+ for(var/name in names)
+ if(filter_data[name])
+ filter_data -= name
+ update_filters()
+
+/atom/proc/clear_filters()
+ filter_data = null
+ filters = null
+
+/proc/apply_wibbly_filters(atom/in_atom, length)
+ for(var/i in 1 to 7)
+ //This is a very baffling and strange way of doing this but I am just preserving old functionality
+ var/X
+ var/Y
+ var/rsq
+ do
+ X = 60*rand() - 30
+ Y = 60*rand() - 30
+ rsq = X*X + Y*Y
+ while(rsq<100 || rsq>900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen?
+ var/random_roll = rand()
+ in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll))
+ var/filter = in_atom.get_filter("wibbly-[i]")
+ animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL)
+ animate(offset = random_roll - 1, time = rand() * 20 + 10)
+
+/proc/remove_wibbly_filters(atom/in_atom)
+ var/filter
+ for(var/i in 1 to 7)
+ filter = in_atom.get_filter("wibbly-[i]")
+ animate(filter)
+ in_atom.remove_filter("wibbly-[i]")
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 076a0d740c2..c9fe06d47c1 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -355,7 +355,7 @@
facedir(direction)
/obj/screen/click_catcher
- name = "Darkness"
+ name = "" // Empty string names don't show up in context menu clicks
icon = 'icons/mob/screen_gen.dmi'
icon_state = "click_catcher"
plane = CLICKCATCHER_PLANE
diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm
index 23a29367c0b..cb500b4fe3a 100644
--- a/code/_onclick/hud/ability_screen_objects.dm
+++ b/code/_onclick/hud/ability_screen_objects.dm
@@ -218,7 +218,7 @@
// if((last_charge == spell.charge_counter || !handle_icon_updates) && !forced_update)
// return //nothing to see here
-// overlays -= spell.hud_state
+// cut_overlay(spell.hud_state)
// if(spell.charge_type == Sp_RECHARGE || spell.charge_type == Sp_CHARGES)
// if(spell.charge_counter < spell.charge_max)
@@ -228,27 +228,27 @@
// partial_charge.Crop(1, 1, partial_charge.Width(), round(partial_charge.Height() * spell.charge_counter / spell.charge_max))
// overlays += partial_charge
// if(last_charged_icon)
-// overlays -= last_charged_icon
+// cut_overlay(last_charged_icon)
// last_charged_icon = partial_charge
// else if(last_charged_icon)
-// overlays -= last_charged_icon
+// cut_overlay(last_charged_icon)
// last_charged_icon = null
// else
// icon_state = "[spell_base]_spell_ready"
// if(last_charged_icon)
-// overlays -= last_charged_icon
+// cut_overlay(last_charged_icon)
// else
// icon_state = "[spell_base]_spell_ready"
- overlays.Cut()
+ cut_overlays()
icon_state = "[background_base_state]_spell_base"
overlays += ability_icon_state
// last_charge = spell.charge_counter
-// overlays -= "silence"
+// cut_overlay("silence")
// if(spell.silenced)
-// overlays += "silence"
+// add_overlay("silence")
/obj/screen/ability/Click()
if(!usr)
diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm
index 160413135b0..d725fb8064e 100644
--- a/code/_onclick/hud/action.dm
+++ b/code/_onclick/hud/action.dm
@@ -134,7 +134,7 @@
icon = owner.button_icon
icon_state = owner.background_icon_state
- overlays.Cut()
+ cut_overlays()
var/image/img
if(owner.action_type == AB_ITEM && owner.target)
var/obj/item/I = owner.target
@@ -143,7 +143,7 @@
img = image(owner.button_icon,src,owner.button_icon_state)
img.pixel_x = 0
img.pixel_y = 0
- overlays += img
+ add_overlay(img)
if(!owner.IsAvailable())
color = rgb(128,0,0,128)
@@ -178,9 +178,9 @@
return
/obj/screen/movable/action_button/hide_toggle/UpdateIcon()
- overlays.Cut()
+ cut_overlays()
var/image/img = image(icon,src,hidden?"show":"hide")
- overlays += img
+ add_overlay(img)
return
//This is the proc used to update all the action buttons. Properly defined in /mob/living/
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index ddd7ac5dcc6..38646ccbc33 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -5,25 +5,22 @@
condition ? overlay_fullscreen(screen_name, screen_type, arg) : clear_fullscreen(screen_name)
/mob/proc/overlay_fullscreen(category, type, severity)
- var/obj/screen/fullscreen/screen = screens[category]
+ var/obj/screen/fullscreen/screen = screens[category]
+ if (!screen || screen.type != type)
+ // needs to be recreated
+ clear_fullscreen(category, FALSE)
+ screens[category] = screen = new type()
+ else if ((!severity || severity == screen.severity) && (!client || screen.screen_loc != "CENTER-7,CENTER-7" || screen.view == client.view))
+ // doesn't need to be updated
+ return screen
- if(screen)
- if(screen.type != type)
- clear_fullscreen(category, FALSE)
- screen = null
- else if(!severity || severity == screen.severity)
- return screen
+ screen.icon_state = "[initial(screen.icon_state)][severity]"
+ screen.severity = severity
+ if (client && screen.should_show_to(src))
+ screen.update_for_view(client.view)
+ client.screen += screen
- if(!screen)
- screen = new type()
-
- screen.icon_state = "[initial(screen.icon_state)][severity]"
- screen.severity = severity
-
- screens[category] = screen
- if(client && stat != DEAD)
- client.screen += screen
- return screen
+ return screen
/mob/proc/clear_fullscreen(category, animated = 10)
var/obj/screen/fullscreen/screen = screens[category]
@@ -64,13 +61,26 @@
screen_loc = "CENTER-7,CENTER-7"
layer = FULLSCREEN_LAYER
plane = PLANE_FULLSCREEN
- mouse_opacity = 0
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ var/view = 7
var/severity = 0
+ var/show_when_dead = FALSE
/obj/screen/fullscreen/Destroy()
severity = 0
return ..()
+/obj/screen/fullscreen/proc/update_for_view(client_view)
+ if (screen_loc == "CENTER-7,CENTER-7" && view != client_view)
+ var/list/actualview = getviewsize(client_view)
+ view = client_view
+ transform = matrix(actualview[1]/15, 0, 0, 0, actualview[2]/15, 0)
+
+/obj/screen/fullscreen/proc/should_show_to(mob/mymob)
+ if(!show_when_dead && mymob.stat == DEAD)
+ return FALSE
+ return TRUE
+
/obj/screen/fullscreen/brute
icon_state = "brutedamageoverlay"
layer = DAMAGE_LAYER
@@ -123,3 +133,21 @@
/obj/screen/fullscreen/fishbed
icon_state = "fishbed"
+
+/obj/screen/fullscreen/lighting_backdrop
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "flash"
+ transform = matrix(200, 0, 0, 0, 200, 0)
+ plane = PLANE_LIGHTING
+ blend_mode = BLEND_OVERLAY
+ show_when_dead = TRUE
+
+//Provides darkness to the back of the lighting plane
+/obj/screen/fullscreen/lighting_backdrop/lit
+ invisibility = INVISIBILITY_LIGHTING
+ layer = BACKGROUND_LAYER+21
+ color = "#000"
+
+//Provides whiteness in case you don't see lights so everything is still visible
+/obj/screen/fullscreen/lighting_backdrop/unlit
+ layer = BACKGROUND_LAYER+20
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 22e8e459fc5..45c94e9fcfd 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -291,8 +291,8 @@
zone_sel.icon = HUD.ui_style
zone_sel.color = HUD.ui_color
zone_sel.alpha = HUD.ui_alpha
- zone_sel.overlays.Cut()
- zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]")
+ zone_sel.cut_overlays()
+ zone_sel.add_overlay(image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]"))
hud_elements |= zone_sel
//Handle the gun settings buttons
diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/picture_in_picture.dm
index 3df659a6873..4f9450db289 100644
--- a/code/_onclick/hud/picture_in_picture.dm
+++ b/code/_onclick/hud/picture_in_picture.dm
@@ -139,7 +139,7 @@
y_off = -height * world.icon_size - 16
- overlays.Cut()
+ cut_overlays()
add_background()
add_buttons()
if(do_refresh)
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index 95ff6e1104f..22ea9bf5628 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -141,8 +141,8 @@ var/obj/screen/robot_inventory
zone_sel = new /obj/screen/zone_sel()
zone_sel.icon = HUD.ui_style
zone_sel.alpha = HUD.ui_alpha
- zone_sel.overlays.Cut()
- zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]")
+ zone_sel.cut_overlays()
+ zone_sel.add_overlay(image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]"))
//Handle the gun settings buttons
gun_setting_icon = new /obj/screen/gun/mode(null)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index f3568b3e40a..06b51def249 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -602,11 +602,11 @@
if(!handcuff_overlay)
var/state = (hud.l_hand_hud_object == src) ? "l_hand_hud_handcuffs" : "r_hand_hud_handcuffs"
handcuff_overlay = image("icon"='icons/mob/screen_gen.dmi', "icon_state"=state)
- overlays.Cut()
+ cut_overlays()
if(hud.mymob && iscarbon(hud.mymob))
var/mob/living/carbon/C = hud.mymob
if(C.handcuffed)
- overlays |= handcuff_overlay
+ add_overlay(handcuff_overlay)
// PIP stuff
/obj/screen/component_button
@@ -630,6 +630,13 @@
return ..()
// Background 'floor'
+/obj/screen/setup_preview/pm_helper
+ icon = null
+ icon_state = null
+ appearance_flags = PLANE_MASTER
+ plane = PLANE_EMISSIVE
+ alpha = 0
+
/obj/screen/setup_preview/bg
mouse_over_pointer = MOUSE_HAND_POINTER
@@ -711,7 +718,7 @@
var/obj/item/device/mapping_unit/owner
var/obj/screen/mapper/extras_holder/extras_holder
-/obj/screen/movable/mapper_holder/New(newloc, newowner)
+/obj/screen/movable/mapper_holder/Initialize(mapload, newowner)
owner = newowner
mask_full = new(src) // Full white square mask
@@ -849,15 +856,15 @@
/obj/screen/mapper/powbutton/Click()
if(!usr.checkClickCooldown())
- return 1
+ return TRUE
if(usr.stat || usr.paralysis || usr.stunned || usr.weakened)
- return 1
+ return TRUE
if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
- return 1
+ return TRUE
parent.powerClick()
flick("powClick",src)
usr << get_sfx("button")
- return 1
+ return TRUE
/obj/screen/mapper/mapbutton
icon = 'icons/effects/gpshud.dmi'
@@ -867,15 +874,15 @@
/obj/screen/mapper/mapbutton/Click()
if(!usr.checkClickCooldown())
- return 1
+ return TRUE
if(usr.stat || usr.paralysis || usr.stunned || usr.weakened)
- return 1
+ return TRUE
if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
- return 1
+ return TRUE
parent.mapClick()
flick("mapClick",src)
usr << get_sfx("button")
- return 1
+ return TRUE
// Markers are 16x16, people have apparently settled on centering them on the 8,8 pixel
/obj/screen/mapper/marker
diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm
index 92d9487401b..1215218ebe1 100644
--- a/code/_onclick/hud/spell_screen_objects.dm
+++ b/code/_onclick/hud/spell_screen_objects.dm
@@ -181,7 +181,7 @@
if((last_charge == spell.charge_counter || !handle_icon_updates) && !forced_update)
return //nothing to see here
- overlays -= spell.hud_state
+ cut_overlay(spell.hud_state)
if(spell.charge_type == Sp_RECHARGE || spell.charge_type == Sp_CHARGES)
if(spell.charge_counter < spell.charge_max)
@@ -191,23 +191,23 @@
partial_charge.Crop(1, 1, partial_charge.Width(), round(partial_charge.Height() * spell.charge_counter / spell.charge_max))
overlays += partial_charge
if(last_charged_icon)
- overlays -= last_charged_icon
+ cut_overlay(last_charged_icon)
last_charged_icon = partial_charge
else if(last_charged_icon)
- overlays -= last_charged_icon
+ cut_overlay(last_charged_icon)
last_charged_icon = null
else
icon_state = "[spell_base]_spell_ready"
if(last_charged_icon)
- overlays -= last_charged_icon
+ cut_overlay(last_charged_icon)
else
icon_state = "[spell_base]_spell_ready"
- overlays += spell.hud_state
+ add_overlay(spell.hud_state)
last_charge = spell.charge_counter
- overlays -= "silence"
+ cut_overlay("silence")
if(spell.silenced)
overlays += "silence"
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index bb31527126b..bf1b337e770 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -41,11 +41,6 @@ avoid code duplication. This includes items that may sometimes act as a standard
return TRUE
return FALSE
-/atom/movable/attackby(obj/item/W, mob/user, var/attack_modifier, var/click_parameters)
- . = ..()
- if(!. && !(W.flags & NOBLUDGEON))
- visible_message("[src] has been hit by [user] with [W].")
-
/mob/living/attackby(obj/item/I, mob/user, var/attack_modifier, var/click_parameters)
if(!ismob(user))
return 0
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
index 4398dbf7e60..049db78c3af 100644
--- a/code/_onclick/telekinesis.dm
+++ b/code/_onclick/telekinesis.dm
@@ -163,7 +163,7 @@ var/const/tk_maxrange = 15
return
/obj/item/tk_grab/update_icon()
- overlays.Cut()
+ cut_overlays()
if(focus && focus.icon && focus.icon_state)
- overlays += icon(focus.icon,focus.icon_state)
+ add_overlay(icon(focus.icon, focus.icon_state))
return
diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm
index 548e0bdb5c4..fa091ca5257 100644
--- a/code/controllers/subsystems/air.dm
+++ b/code/controllers/subsystems/air.dm
@@ -57,9 +57,44 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
if(active_edges.len)
var/list/edge_log = list()
for(var/connection_edge/E in active_edges)
+
+ var/a_temp = E.A.air.temperature
+ var/a_moles = E.A.air.total_moles
+ var/a_vol = E.A.air.volume
+ var/a_gas = ""
+ for(var/gas in E.A.air.gas)
+ a_gas += "[gas]=[E.A.air.gas[gas]]"
+
+ var/b_temp
+ var/b_moles
+ var/b_vol
+ var/b_gas = ""
+
+ // Two zones mixing
+ if(istype(E, /connection_edge/zone))
+ var/connection_edge/zone/Z = E
+ b_temp = Z.B.air.temperature
+ b_moles = Z.B.air.total_moles
+ b_vol = Z.B.air.volume
+ for(var/gas in Z.B.air.gas)
+ b_gas += "[gas]=[Z.B.air.gas[gas]]"
+
+ // Zone and unsimulated turfs mixing
+ if(istype(E, /connection_edge/unsimulated))
+ var/connection_edge/unsimulated/U = E
+ b_temp = U.B.temperature
+ b_moles = "Unsim"
+ b_vol = "Unsim"
+ for(var/gas in U.air.gas)
+ b_gas += "[gas]=[U.air.gas[gas]]"
+
edge_log += "Active Edge [E] ([E.type])"
+ edge_log += "Edge side A: T:[a_temp], Mol:[a_moles], Vol:[a_vol], Gas:[a_gas]"
+ edge_log += "Edge side B: T:[b_temp], Mol:[b_moles], Vol:[b_vol], Gas:[b_gas]"
+
for(var/turf/T in E.connecting_turfs)
edge_log += "+--- Connecting Turf [T] ([T.type]) @ [T.x], [T.y], [T.z] ([T.loc])"
+
log_debug("Active Edges on ZAS Startup\n" + edge_log.Join("\n"))
startup_active_edge_log = edge_log.Copy()
@@ -124,7 +159,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
T.post_update_air_properties()
T.needs_air_update = 0
#ifdef ZASDBG
- T.overlays -= mark
+ T.cut_overlay(mark)
#endif
if(MC_TICK_CHECK)
return
@@ -139,7 +174,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
T.post_update_air_properties()
T.needs_air_update = 0
#ifdef ZASDBG
- T.overlays -= mark
+ T.cut_overlay(mark)
#endif
if(MC_TICK_CHECK)
return
diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm
index 5c7b15d8985..f851e3edf2d 100644
--- a/code/controllers/subsystems/lighting.dm
+++ b/code/controllers/subsystems/lighting.dm
@@ -1,171 +1,91 @@
-/*
-** Lighting Subsystem - Process the lighting! Do it!
-*/
-
-#define SSLIGHTING_STAGE_LIGHTS 1
-#define SSLIGHTING_STAGE_CORNERS 2
-#define SSLIGHTING_STAGE_OVERLAYS 3
-#define SSLIGHTING_STAGE_DONE 4
-// This subsystem's fire() method also gets called once during Master.Initialize().
-// During this fire we need to use CHECK_TICK to sleep and continue, but in all other fires we need to use MC_CHECK_TICK to pause and return.
-// This leads us to a rather annoying little tidbit of code that I have stuffed into this macro so I don't have to see it.
-#define DUAL_TICK_CHECK if (init_tick_checks) { CHECK_TICK; } else if (MC_TICK_CHECK) { return; }
-
-// Globals
-/var/lighting_overlays_initialised = FALSE
-/var/list/lighting_update_lights = list() // List of lighting sources queued for update.
-/var/list/lighting_update_corners = list() // List of lighting corners queued for update.
-/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update.
-
SUBSYSTEM_DEF(lighting)
name = "Lighting"
- wait = 2 // Ticks, not deciseconds
+ wait = 2
init_order = INIT_ORDER_LIGHTING
flags = SS_TICKER
+ var/static/list/sources_queue = list() // List of lighting sources queued for update.
+ var/static/list/corners_queue = list() // List of lighting corners queued for update.
+ var/static/list/objects_queue = list() // List of lighting objects queued for update.
- var/list/currentrun = list()
- var/stage = null
-
- var/cost_lights = 0
- var/cost_corners = 0
- var/cost_overlays = 0
-
-/datum/controller/subsystem/lighting/Initialize(timeofday)
- if(!lighting_overlays_initialised)
- // TODO - TG initializes starlight here.
- create_all_lighting_overlays()
- lighting_overlays_initialised = TRUE
-
- // Pre-process lighting once before the round starts.
- internal_process_lights(FALSE, TRUE)
- internal_process_corners(FALSE, TRUE)
- internal_process_overlays(FALSE, TRUE)
+/datum/controller/subsystem/lighting/stat_entry(msg)
+ msg = "L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]"
return ..()
-/datum/controller/subsystem/lighting/fire(resumed = FALSE)
- var/timer
- if(!resumed)
- // Santity checks to make sure we don't somehow have items left over from last cycle
- // Or somehow didn't finish all the steps from last cycle
- if(LAZYLEN(currentrun) || stage)
- log_and_message_admins("SSlighting: Was told to start a new run, but the previous run wasn't finished! currentrun.len=[currentrun.len], stage=[stage]")
- resumed = TRUE
- else
- stage = SSLIGHTING_STAGE_LIGHTS // Start with Step 1 of course
- if(stage == SSLIGHTING_STAGE_LIGHTS)
- timer = TICK_USAGE
- internal_process_lights(resumed)
- cost_lights = MC_AVERAGE(cost_lights, TICK_DELTA_TO_MS(TICK_USAGE - timer))
- if(state != SS_RUNNING)
- return
- resumed = 0
- stage = SSLIGHTING_STAGE_CORNERS
+/datum/controller/subsystem/lighting/Initialize(timeofday)
+ if(!subsystem_initialized)
+ if (config.starlight)
+ for(var/area/A in world)
+ if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
+ A.luminosity = 0
- if(stage == SSLIGHTING_STAGE_CORNERS)
- timer = TICK_USAGE
- internal_process_corners(resumed)
- cost_corners = MC_AVERAGE(cost_corners, TICK_DELTA_TO_MS(TICK_USAGE - timer))
- if(state != SS_RUNNING)
- return
- resumed = 0
- stage = SSLIGHTING_STAGE_OVERLAYS
+ subsystem_initialized = TRUE
+ create_all_lighting_objects()
- if(stage == SSLIGHTING_STAGE_OVERLAYS)
- timer = TICK_USAGE
- internal_process_overlays(resumed)
- cost_overlays = MC_AVERAGE(cost_overlays, TICK_DELTA_TO_MS(TICK_USAGE - timer))
- if(state != SS_RUNNING)
- return
- resumed = 0
- stage = SSLIGHTING_STAGE_DONE
+ fire(FALSE, TRUE)
- // Okay, we're done! Woo! Got thru a whole air_master cycle!
- if(LAZYLEN(currentrun) || stage != SSLIGHTING_STAGE_DONE)
- log_and_message_admins("SSlighting: Was not able to complete a full lighting cycle despite reaching the end of fire(). This shouldn't happen.")
- else
- currentrun = null
- stage = null
+ return ..()
-/datum/controller/subsystem/lighting/proc/internal_process_lights(resumed = FALSE, init_tick_checks = FALSE)
- if (!resumed)
- // We swap out the lists so any additions to the global list during a pause don't make things wierd.
- src.currentrun = global.lighting_update_lights
- global.lighting_update_lights = list()
+/datum/controller/subsystem/lighting/fire(resumed, init_tick_checks)
+ MC_SPLIT_TICK_INIT(3)
+ if(!init_tick_checks)
+ MC_SPLIT_TICK
+ var/list/queue = sources_queue
+ var/i = 0
+ for (i in 1 to length(queue))
+ var/datum/light_source/L = queue[i]
- //cache for sanic speed (lists are references anyways)
- var/list/currentrun = src.currentrun
- while(currentrun.len)
- var/datum/light_source/L = currentrun[currentrun.len]
- currentrun.len--
+ L.update_corners()
- if(!L) continue
- if(L.check() || L.destroyed || L.force_update)
- L.remove_lum()
- if(!L.destroyed)
- L.apply_lum()
+ L.needs_update = LIGHTING_NO_UPDATE
- else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
- L.smart_vis_update()
+ if(init_tick_checks)
+ CHECK_TICK
+ else if (MC_TICK_CHECK)
+ break
+ if (i)
+ queue.Cut(1, i+1)
+ i = 0
- L.vis_update = FALSE
- L.force_update = FALSE
- L.needs_update = FALSE
+ if(!init_tick_checks)
+ MC_SPLIT_TICK
- DUAL_TICK_CHECK
+ queue = corners_queue
+ for (i in 1 to length(queue))
+ var/datum/lighting_corner/C = queue[i]
-/datum/controller/subsystem/lighting/proc/internal_process_corners(resumed = FALSE, init_tick_checks = FALSE)
- if (!resumed)
- // We swap out the lists so any additions to the global list during a pause don't make things wierd.
- src.currentrun = global.lighting_update_corners
- global.lighting_update_corners = list()
+ C.needs_update = FALSE //update_objects() can call qdel if the corner is storing no data
+ C.update_objects()
+
+ if(init_tick_checks)
+ CHECK_TICK
+ else if (MC_TICK_CHECK)
+ break
+ if (i)
+ queue.Cut(1, i+1)
+ i = 0
- //cache for sanic speed (lists are references anyways)
- var/list/currentrun = src.currentrun
- while(currentrun.len)
- var/datum/lighting_corner/C = currentrun[currentrun.len]
- currentrun.len--
- if(!C) continue
- C.update_overlays()
- C.needs_update = FALSE
+ if(!init_tick_checks)
+ MC_SPLIT_TICK
- DUAL_TICK_CHECK
+ queue = objects_queue
+ for (i in 1 to length(queue))
+ var/datum/lighting_object/O = queue[i]
-/datum/controller/subsystem/lighting/proc/internal_process_overlays(resumed = FALSE, init_tick_checks = FALSE)
- if (!resumed)
- // We swap out the lists so any additions to the global list during a pause don't make things wierd.
- src.currentrun = global.lighting_update_overlays
- global.lighting_update_overlays = list()
+ if (QDELETED(O))
+ continue
- //cache for sanic speed (lists are references anyways)
- var/list/currentrun = src.currentrun
- while(currentrun.len)
- var/atom/movable/lighting_overlay/O = currentrun[currentrun.len]
- currentrun.len--
-
- if(!O) continue
- O.update_overlay()
+ O.update()
O.needs_update = FALSE
+ if(init_tick_checks)
+ CHECK_TICK
+ else if (MC_TICK_CHECK)
+ break
+ if (i)
+ queue.Cut(1, i+1)
- DUAL_TICK_CHECK
-/datum/controller/subsystem/lighting/stat_entry(msg_prefix)
- var/list/msg = list(msg_prefix)
- msg += "T:{"
- msg += "S [total_lighting_sources] | "
- msg += "C [total_lighting_corners] | "
- msg += "O [total_lighting_overlays]"
- msg += "}"
- msg += "C:{"
- msg += "S [round(cost_lights, 1)] | "
- msg += "C [round(cost_corners, 1)] | "
- msg += "O [round(cost_overlays, 1)]"
- msg += "}"
- ..(msg.Join())
-
-#undef DUAL_TICK_CHECK
-#undef SSLIGHTING_STAGE_LIGHTS
-#undef SSLIGHTING_STAGE_CORNERS
-#undef SSLIGHTING_STAGE_OVERLAYS
-#undef SSLIGHTING_STAGE_STATS
\ No newline at end of file
+/datum/controller/subsystem/lighting/Recover()
+ subsystem_initialized = SSlighting.subsystem_initialized
+ ..()
diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm
index 77c9d3ab94a..16662cc042e 100644
--- a/code/controllers/subsystems/overlays.dm
+++ b/code/controllers/subsystems/overlays.dm
@@ -224,6 +224,32 @@ var/global/image/appearance_bro = new() // Temporarily super-global because of B
else if(cut_old)
cut_overlays()
+/**
+ * Returns a list of overlays that the target atom has
+ *
+ * @param priority If true, returns priority overlays as well
+ * @param special If true, returns special overlays like emissives and em_blockers
+ */
+/proc/get_overlays(atom/other, priority, special)
+ var/list/including = list()
+ if(!other)
+ return including
+
+ for(var/image/I as anything in other.our_overlays)
+ if(!special && I.plane > 0)
+ continue
+ including += I
+
+ if(!priority)
+ return including
+
+ for(var/image/I as anything in other.priority_overlays)
+ if(!special && I.plane > 0)
+ continue
+ including += I
+
+ return including
+
#undef NOT_QUEUED_ALREADY
#undef QUEUE_FOR_COMPILE
diff --git a/code/controllers/subsystems/planets.dm b/code/controllers/subsystems/planets.dm
index d1c2de2410c..c9a4a2db43c 100644
--- a/code/controllers/subsystems/planets.dm
+++ b/code/controllers/subsystems/planets.dm
@@ -44,9 +44,8 @@ SUBSYSTEM_DEF(planets)
P.planet_walls += T
else if(istype(T, /turf/simulated) && T.outdoors)
P.planet_floors += T
- T.vis_contents |= P.weather_holder.visuals
- T.vis_contents |= P.weather_holder.special_visuals
-
+ P.weather_holder.apply_to_turf(T)
+ P.sun_holder.apply_to_turf(T)
/datum/controller/subsystem/planets/proc/removeTurf(var/turf/T,var/is_edge)
if(z_to_planet.len >= T.z)
@@ -57,8 +56,8 @@ SUBSYSTEM_DEF(planets)
P.planet_walls -= T
else
P.planet_floors -= T
- T.vis_contents -= P.weather_holder.visuals
- T.vis_contents -= P.weather_holder.special_visuals
+ P.weather_holder.remove_from_turf(T)
+ P.sun_holder.remove_from_turf(T)
/datum/controller/subsystem/planets/fire(resumed = 0)
@@ -72,7 +71,8 @@ SUBSYSTEM_DEF(planets)
updateSunlight(P)
if(MC_TICK_CHECK)
return
-
+
+ #ifndef UNIT_TEST // Don't be updating temperatures and such during unit tests
var/list/needs_temp_update = src.needs_temp_update
while(needs_temp_update.len)
var/datum/planet/P = needs_temp_update[needs_temp_update.len]
@@ -80,6 +80,7 @@ SUBSYSTEM_DEF(planets)
updateTemp(P)
if(MC_TICK_CHECK)
return
+ #endif
var/list/currentrun = src.currentrun
while(currentrun.len)
@@ -102,39 +103,11 @@ SUBSYSTEM_DEF(planets)
return
/datum/controller/subsystem/planets/proc/updateSunlight(var/datum/planet/P)
- // Remove old value from corners
- var/list/sunlit_corners = P.sunlit_corners
- var/old_lum_r = -P.sun["lum_r"]
- var/old_lum_g = -P.sun["lum_g"]
- var/old_lum_b = -P.sun["lum_b"]
- if(old_lum_r || old_lum_g || old_lum_b)
- for(var/C in sunlit_corners)
- var/datum/lighting_corner/LC = C
- LC.update_lumcount(old_lum_r, old_lum_g, old_lum_b)
- CHECK_TICK
- sunlit_corners.Cut()
-
- // Calculate new values to apply
var/new_brightness = P.sun["brightness"]
+ P.sun_holder.update_brightness(new_brightness)
+
var/new_color = P.sun["color"]
- var/lum_r = new_brightness * GetRedPart (new_color) / 255
- var/lum_g = new_brightness * GetGreenPart(new_color) / 255
- var/lum_b = new_brightness * GetBluePart (new_color) / 255
- var/static/update_gen = -1 // Used to prevent double-processing corners. Otherwise would happen when looping over adjacent turfs.
- for(var/turf/simulated/T as anything in P.planet_floors)
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
- for(var/C in T.get_corners())
- var/datum/lighting_corner/LC = C
- if(LC.update_gen != update_gen && LC.active)
- sunlit_corners += LC
- LC.update_gen = update_gen
- LC.update_lumcount(lum_r, lum_g, lum_b)
- CHECK_TICK
- update_gen--
- P.sun["lum_r"] = lum_r
- P.sun["lum_g"] = lum_g
- P.sun["lum_b"] = lum_b
+ P.sun_holder.update_color(new_color)
/datum/controller/subsystem/planets/proc/updateTemp(var/datum/planet/P)
//Set new temperatures
diff --git a/code/controllers/subsystems/skybox.dm b/code/controllers/subsystems/skybox.dm
index 6befac0b605..05053fbb0f7 100644
--- a/code/controllers/subsystems/skybox.dm
+++ b/code/controllers/subsystems/skybox.dm
@@ -37,7 +37,8 @@ SUBSYSTEM_DEF(skybox)
im.alpha = 128 //80
im.blend_mode = BLEND_ADD
- MA.overlays = list(im)
+ MA.cut_overlays()
+ MA.add_overlay(im)
dust_cache["[i]"] = MA
@@ -48,7 +49,8 @@ SUBSYSTEM_DEF(skybox)
var/image/im = image('icons/turf/space_dust_transit.dmi', "speedspace_ns_[i]")
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
- MA.overlays = list(im)
+ MA.cut_overlays()
+ MA.add_overlay(im)
speedspace_cache["NS_[i]"] = MA
// EAST/WEST
MA = new(normal_space)
@@ -56,7 +58,8 @@ SUBSYSTEM_DEF(skybox)
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
- MA.overlays = list(im)
+ MA.cut_overlays()
+ MA.add_overlay(im)
speedspace_cache["EW_[i]"] = MA
diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm
index c55208d7dfe..47a0e0e7bd4 100644
--- a/code/controllers/subsystems/supply.dm
+++ b/code/controllers/subsystems/supply.dm
@@ -205,11 +205,11 @@ SUBSYSTEM_DEF(supply)
else if(islist(SP.access) && SP.one_access)
var/list/L = SP.access // access var is a plain var, we need a list
A.req_one_access = L.Copy()
- A.req_access = null
+ LAZYCLEARLIST(A.req_access)
else if(islist(SP.access) && !SP.one_access)
var/list/L = SP.access
A.req_access = L.Copy()
- A.req_one_access = null
+ LAZYCLEARLIST(A.req_one_access)
else
log_debug("Supply pack with invalid access restriction [SP.access] encountered!")
diff --git a/code/controllers/subsystems/tgui.dm b/code/controllers/subsystems/tgui.dm
index e94830a5f03..a0d96cf80c1 100644
--- a/code/controllers/subsystems/tgui.dm
+++ b/code/controllers/subsystems/tgui.dm
@@ -22,7 +22,7 @@ SUBSYSTEM_DEF(tgui)
var/basehtml
/datum/controller/subsystem/tgui/PreInit()
- basehtml = file2text('tgui/packages/tgui/public/tgui.html')
+ basehtml = file2text('tgui/public/tgui.html')
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()
diff --git a/code/controllers/subsystems/vis_overlays.dm b/code/controllers/subsystems/vis_overlays.dm
new file mode 100644
index 00000000000..0806e4c954d
--- /dev/null
+++ b/code/controllers/subsystems/vis_overlays.dm
@@ -0,0 +1,77 @@
+SUBSYSTEM_DEF(vis_overlays)
+ name = "Vis contents overlays"
+ wait = 1 MINUTES
+ priority = FIRE_PRIORITY_VIS
+ init_order = INIT_ORDER_VIS
+
+ var/list/vis_overlay_cache
+ var/list/currentrun
+
+/datum/controller/subsystem/vis_overlays/Initialize()
+ vis_overlay_cache = list()
+ return ..()
+
+/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
+ if(!resumed)
+ currentrun = vis_overlay_cache.Copy()
+ var/list/current_run = currentrun
+
+ while(current_run.len)
+ var/key = current_run[current_run.len]
+ var/obj/effect/overlay/vis/overlay = current_run[key]
+ current_run.len--
+ if(!overlay.unused && !length(overlay.vis_locs))
+ overlay.unused = world.time
+ else if(overlay.unused && overlay.unused + overlay.cache_expiration < world.time)
+ vis_overlay_cache -= key
+ qdel(overlay)
+ if(MC_TICK_CHECK)
+ return
+
+//the "thing" var can be anything with vis_contents which includes images - in the future someone should totally allow vis overlays to be passed in as an arg instead of all this bullshit
+/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE)
+ var/obj/effect/overlay/vis/overlay
+ if(!unique)
+ . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
+ overlay = vis_overlay_cache[.]
+ if(!overlay)
+ overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ vis_overlay_cache[.] = overlay
+ else
+ overlay.unused = 0
+ else
+ overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ overlay.cache_expiration = -1
+ var/cache_id = "\ref[overlay]@{[world.time]}"
+ vis_overlay_cache[cache_id] = overlay
+ . = overlay
+ thing.vis_contents += overlay
+
+ if(!isatom(thing))
+ return overlay
+
+ if(!thing.managed_vis_overlays)
+ thing.managed_vis_overlays = list(overlay)
+ else
+ thing.managed_vis_overlays += overlay
+ return overlay
+
+/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ var/obj/effect/overlay/vis/overlay = new
+ overlay.icon = icon
+ overlay.icon_state = iconstate
+ overlay.layer = layer
+ overlay.plane = plane
+ overlay.dir = dir
+ overlay.alpha = alpha
+ overlay.appearance_flags |= add_appearance_flags
+ return overlay
+
+
+/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays)
+ thing.vis_contents -= overlays
+ if(!isatom(thing))
+ return
+ thing.managed_vis_overlays -= overlays
+ if(!length(thing.managed_vis_overlays))
+ thing.managed_vis_overlays = null
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index 58a66923c42..4a9c3b48a7c 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -4,6 +4,7 @@
// Clickable stat() button.
/obj/effect/statclick
name = "Initializing..."
+ blocks_emissive = FALSE
var/target
/obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index e78833c9580..efb4c497958 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -311,8 +311,7 @@
div_slider = "locked"
output += {"
"}
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index c4ee090ce85..c5bd07cdcbd 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -188,7 +188,11 @@
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
- stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
+ var/trace_msg = "[sig_type] overridden. Use override = TRUE to suppress this warning."
+ if(isatom(target))
+ var/atom/A = target
+ trace_msg += " [A.x],[A.y],[A.z]"
+ stack_trace(trace_msg)
procs[target][sig_type] = proctype
diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm
new file mode 100644
index 00000000000..cfc0f1e921e
--- /dev/null
+++ b/code/datums/components/overlay_lighting.dm
@@ -0,0 +1,511 @@
+///For switchable lights, is it on and currently emitting light?
+#define LIGHTING_ON (1<<0)
+///Is the parent attached to something else, its loc? Then we need to keep an eye of this.
+#define LIGHTING_ATTACHED (1<<1)
+
+#define GET_PARENT (parent_attached_to || parent)
+
+#define GET_LIGHT_SOURCE (directional_atom || current_holder)
+
+#define SHORT_CAST 2
+
+/**
+ * Movable atom overlay-based lighting component.
+ *
+ * * Component works by applying a visual object to the parent target.
+ *
+ * * The component tracks the parent's loc to determine the current_holder.
+ * * The current_holder is either the parent or its loc, whichever is on a turf. If none, then the current_holder is null and the light is not visible.
+ *
+ * * Lighting works at its base by applying a dark overlay and "cutting" said darkness with light, adding (possibly colored) transparency.
+ * * This component uses the visible_mask visual object to apply said light mask on the darkness.
+ *
+ * * The main limitation of this system is that it uses a limited number of pre-baked geometrical shapes, but for most uses it does the job.
+ *
+ * * Another limitation is for big lights: you only see the light if you see the object emiting it.
+ * * For small objects this is good (you can't see them behind a wall), but for big ones this quickly becomes prety clumsy.
+*/
+/datum/component/overlay_lighting
+ ///How far the light reaches, float.
+ var/range = 1
+ ///Ceiling of range, integer without decimal entries.
+ var/lumcount_range = 0
+ ///How much this light affects the dynamic_lumcount of turfs.
+ var/lum_power = 0.5
+ ///Transparency value.
+ var/set_alpha = 0
+ ///For light sources that can be turned on and off.
+ var/overlay_lighting_flags = NONE
+
+ ///Cache of the possible light overlays, according to size.
+ var/static/list/light_overlays = list(
+ "32" = 'icons/effects/light_overlays/light_32.dmi',
+ "64" = 'icons/effects/light_overlays/light_64.dmi',
+ "96" = 'icons/effects/light_overlays/light_96.dmi',
+ "128" = 'icons/effects/light_overlays/light_128.dmi',
+ "160" = 'icons/effects/light_overlays/light_160.dmi',
+ "192" = 'icons/effects/light_overlays/light_192.dmi',
+ "224" = 'icons/effects/light_overlays/light_224.dmi',
+ "256" = 'icons/effects/light_overlays/light_256.dmi',
+ "288" = 'icons/effects/light_overlays/light_288.dmi',
+ "320" = 'icons/effects/light_overlays/light_320.dmi',
+ "352" = 'icons/effects/light_overlays/light_352.dmi',
+ )
+
+ ///Overlay effect to cut into the darkness and provide light.
+ var/obj/effect/overlay/light_visible/visible_mask
+ ///Lazy list to track the turfs being affected by our light, to determine their visibility.
+ var/list/turf/affected_turfs
+ ///Movable atom currently holding the light. Parent might be a flashlight, for example, but that might be held by a mob or something else.
+ var/atom/movable/current_holder
+ ///Movable atom the parent is attached to. For example, a flashlight into a helmet or gun. We'll need to track the thing the parent is attached to as if it were the parent itself.
+ var/atom/movable/parent_attached_to
+ ///Whether we're a directional light
+ var/directional
+ ///Abstractional atom for directional light, we move this around to make the directional effect
+ var/obj/effect/abstract/directional_lighting/directional_atom
+ ///A cone overlay for directional light, it's alpha and color are dependant on the light
+ var/obj/effect/overlay/light_cone/cone
+ ///Current tracked direction for the directional cast behaviour
+ var/current_direction
+ ///Cast range for the directional cast (how far away the atom is moved)
+ var/cast_range = 2
+ ///Cone offset X hint from atom, used when facing south, inverted when facing north
+ var/cone_hint_x
+ ///Cone offset Y hint from atom, when facing east/west, ignored for north/south (uses 16 in those cases)
+ var/cone_hint_y
+
+
+/datum/component/overlay_lighting/Initialize(_range, _power, _color, starts_on, is_directional)
+ if(!ismovable(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ var/atom/movable/movable_parent = parent
+ if(movable_parent.light_system != MOVABLE_LIGHT && movable_parent.light_system != MOVABLE_LIGHT_DIRECTIONAL)
+ stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [MOVABLE_LIGHT] or [MOVABLE_LIGHT_DIRECTIONAL] instead.")
+ return COMPONENT_INCOMPATIBLE
+
+ . = ..()
+
+ visible_mask = new()
+ if(is_directional)
+ directional = TRUE
+ directional_atom = new()
+ cone = new()
+ cone_hint_x = movable_parent.light_cone_x_offset
+ cone_hint_y = movable_parent.light_cone_y_offset
+ cone.transform = cone.transform.Translate(-32, -32)
+ set_direction(movable_parent.dir)
+ if(!isnull(_range))
+ movable_parent.set_light_range(_range)
+ set_range(parent, movable_parent.light_range)
+ if(!isnull(_power))
+ movable_parent.set_light_power(_power)
+ set_power(parent, movable_parent.light_power)
+ if(!isnull(_color))
+ movable_parent.set_light_color(_color)
+ set_color(parent, movable_parent.light_color)
+ if(!isnull(starts_on))
+ movable_parent.set_light_on(starts_on)
+
+
+/datum/component/overlay_lighting/RegisterWithParent()
+ . = ..()
+ if(directional)
+ RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/on_parent_dir_change)
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved)
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .proc/set_range)
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_POWER, .proc/set_power)
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .proc/set_color)
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_ON, .proc/on_toggle)
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .proc/on_light_flags_change)
+ RegisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted)
+ RegisterSignal(parent, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
+ var/atom/movable/movable_parent = parent
+ if(movable_parent.light_flags & LIGHT_ATTACHED)
+ overlay_lighting_flags |= LIGHTING_ATTACHED
+ set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null)
+ check_holder()
+ if(movable_parent.light_on)
+ turn_on()
+
+
+/datum/component/overlay_lighting/UnregisterFromParent()
+ overlay_lighting_flags &= ~LIGHTING_ATTACHED
+ set_parent_attached_to(null)
+ set_holder(null)
+ clean_old_turfs()
+ UnregisterSignal(parent, list(
+ COMSIG_MOVABLE_MOVED,
+ COMSIG_ATOM_UPDATE_LIGHT_RANGE,
+ COMSIG_ATOM_UPDATE_LIGHT_POWER,
+ COMSIG_ATOM_UPDATE_LIGHT_COLOR,
+ COMSIG_ATOM_UPDATE_LIGHT_ON,
+ COMSIG_ATOM_UPDATE_LIGHT_FLAGS,
+ COMSIG_ATOM_USED_IN_CRAFT,
+ COMSIG_LIGHT_EATER_QUEUE,
+ ))
+ if(directional)
+ UnregisterSignal(parent, COMSIG_ATOM_DIR_CHANGE)
+ if(overlay_lighting_flags & LIGHTING_ON)
+ turn_off()
+ return ..()
+
+
+/datum/component/overlay_lighting/Destroy()
+ set_parent_attached_to(null)
+ set_holder(null)
+ clean_old_turfs()
+ QDEL_NULL(visible_mask)
+ if(directional)
+ QDEL_NULL(directional_atom)
+ QDEL_NULL(cone)
+ return ..()
+
+
+///Clears the affected_turfs lazylist, removing from its contents the effects of being near the light.
+/datum/component/overlay_lighting/proc/clean_old_turfs()
+ for(var/t in affected_turfs)
+ var/turf/lit_turf = t
+ lit_turf.dynamic_lumcount -= lum_power
+ affected_turfs = null
+
+
+///Populates the affected_turfs lazylist, adding to its contents the effects of being near the light.
+/datum/component/overlay_lighting/proc/get_new_turfs()
+ if(!current_holder)
+ return
+ var/atom/movable/light_source = GET_LIGHT_SOURCE
+ for(var/turf/lit_turf in view(lumcount_range, get_turf(light_source)))
+ lit_turf.dynamic_lumcount += lum_power
+ LAZYADD(affected_turfs, lit_turf)
+
+
+///Clears the old affected turfs and populates the new ones.
+/datum/component/overlay_lighting/proc/make_luminosity_update()
+ clean_old_turfs()
+ if(!isturf(current_holder?.loc))
+ return
+ if(directional)
+ cast_directional_light()
+ get_new_turfs()
+
+
+///Adds the luminosity and source for the afected movable atoms to keep track of their visibility.
+/datum/component/overlay_lighting/proc/add_dynamic_lumi()
+ var/atom/movable/light_source = GET_LIGHT_SOURCE
+ LAZYSET(light_source.affected_dynamic_lights, src, lumcount_range + 1)
+ light_source.vis_contents += visible_mask
+ light_source.update_dynamic_luminosity()
+ if(directional)
+ current_holder.vis_contents += cone
+
+///Removes the luminosity and source for the afected movable atoms to keep track of their visibility.
+/datum/component/overlay_lighting/proc/remove_dynamic_lumi()
+ var/atom/movable/light_source = GET_LIGHT_SOURCE
+ LAZYREMOVE(light_source.affected_dynamic_lights, src)
+ light_source.vis_contents -= visible_mask
+ light_source.update_dynamic_luminosity()
+ if(directional)
+ current_holder.vis_contents -= cone
+ directional_atom.moveToNullspace()
+
+///Called to change the value of parent_attached_to.
+/datum/component/overlay_lighting/proc/set_parent_attached_to(atom/movable/new_parent_attached_to)
+ if(new_parent_attached_to == parent_attached_to)
+ return
+
+ . = parent_attached_to
+ parent_attached_to = new_parent_attached_to
+ if(.)
+ var/atom/movable/old_parent_attached_to = .
+ UnregisterSignal(old_parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
+ if(old_parent_attached_to == current_holder)
+ RegisterSignal(old_parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel)
+ RegisterSignal(old_parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved)
+ RegisterSignal(old_parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
+ if(parent_attached_to)
+ if(parent_attached_to == current_holder)
+ UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
+ RegisterSignal(parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_parent_attached_to_qdel)
+ RegisterSignal(parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_parent_attached_to_moved)
+ RegisterSignal(parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
+ check_holder()
+
+
+///Called to change the value of current_holder.
+/datum/component/overlay_lighting/proc/set_holder(atom/movable/new_holder)
+ if(new_holder == current_holder)
+ return
+ if(current_holder)
+ if(current_holder != parent && current_holder != parent_attached_to)
+ UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
+ if(directional)
+ UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
+ if(overlay_lighting_flags & LIGHTING_ON)
+ remove_dynamic_lumi()
+ current_holder = new_holder
+ if(new_holder == null)
+ clean_old_turfs()
+ return
+ if(new_holder != parent && new_holder != parent_attached_to)
+ RegisterSignal(new_holder, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel)
+ RegisterSignal(new_holder, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved)
+ RegisterSignal(new_holder, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
+ if(directional)
+ RegisterSignal(new_holder, COMSIG_ATOM_DIR_CHANGE, .proc/on_holder_dir_change)
+ if(overlay_lighting_flags & LIGHTING_ON)
+ make_luminosity_update()
+ add_dynamic_lumi()
+
+
+///Used to determine the new valid current_holder from the parent's loc.
+/datum/component/overlay_lighting/proc/check_holder()
+ var/atom/movable/movable_parent = GET_PARENT
+ if(isturf(movable_parent.loc))
+ set_holder(movable_parent)
+ return
+ var/atom/inside = movable_parent.loc //Parent's loc
+ if(isnull(inside))
+ set_holder(null)
+ return
+ if(isturf(inside.loc))
+ set_holder(inside)
+ return
+ set_holder(null)
+
+
+///Called when the current_holder is qdeleted, to remove the light effect.
+/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force)
+ SIGNAL_HANDLER
+ UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
+ if(directional)
+ UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
+ set_holder(null)
+
+
+///Called when current_holder changes loc.
+/datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced)
+ SIGNAL_HANDLER
+ if(!(overlay_lighting_flags & LIGHTING_ON))
+ return
+ make_luminosity_update()
+
+
+///Called when parent changes loc.
+/datum/component/overlay_lighting/proc/on_parent_moved(atom/movable/source, OldLoc, Dir, Forced)
+ SIGNAL_HANDLER
+ var/atom/movable/movable_parent = parent
+ if(overlay_lighting_flags & LIGHTING_ATTACHED)
+ set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null)
+ check_holder()
+ if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder)
+ return
+ make_luminosity_update()
+
+
+///Called when the current_holder is qdeleted, to remove the light effect.
+/datum/component/overlay_lighting/proc/on_parent_attached_to_qdel(atom/movable/source, force)
+ SIGNAL_HANDLER
+ UnregisterSignal(parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
+ if(directional)
+ UnregisterSignal(parent_attached_to, COMSIG_ATOM_DIR_CHANGE)
+ if(parent_attached_to == current_holder)
+ set_holder(null)
+ set_parent_attached_to(null)
+
+
+///Called when parent_attached_to changes loc.
+/datum/component/overlay_lighting/proc/on_parent_attached_to_moved(atom/movable/source, OldLoc, Dir, Forced)
+ SIGNAL_HANDLER
+ check_holder()
+ if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder)
+ return
+ make_luminosity_update()
+
+
+///Changes the range which the light reaches. 0 means no light, 6 is the maximum value.
+/datum/component/overlay_lighting/proc/set_range(atom/source, old_range)
+ SIGNAL_HANDLER
+ var/new_range = source.light_range
+ if(range == new_range)
+ return
+ if(range == 0)
+ turn_off()
+ range = clamp(CEILING(new_range, 0.5), 1, 6)
+ var/pixel_bounds = ((range - 1) * 64) + 32
+ lumcount_range = CEILING(range, 1)
+ visible_mask.icon = light_overlays["[pixel_bounds]"]
+ if(pixel_bounds == 32)
+ visible_mask.transform = null
+ return
+ var/offset = (pixel_bounds - 32) * 0.5
+ var/matrix/transform = new
+ transform.Translate(-offset, -offset)
+ visible_mask.transform = transform
+ if(directional)
+ cast_range = clamp(round(new_range * 0.5), 1, 3)
+ if(overlay_lighting_flags & LIGHTING_ON)
+ make_luminosity_update()
+
+
+///Changes the intensity/brightness of the light by altering the visual object's alpha.
+/datum/component/overlay_lighting/proc/set_power(atom/source, old_power)
+ SIGNAL_HANDLER
+ var/new_power = source.light_power
+ set_lum_power(new_power >= 0 ? 0.5 : -0.5)
+ set_alpha = min(230, (abs(new_power) * 120) + 30)
+ visible_mask.alpha = set_alpha
+ if(directional)
+ cone.alpha = min(200, (abs(new_power) * 90)+20)
+
+
+///Changes the light's color, pretty straightforward.
+/datum/component/overlay_lighting/proc/set_color(atom/source, old_color)
+ SIGNAL_HANDLER
+ var/new_color = source.light_color
+ visible_mask.color = new_color
+ if(directional)
+ cone.color = new_color
+
+
+///Toggles the light on and off.
+/datum/component/overlay_lighting/proc/on_toggle(atom/source, old_value)
+ SIGNAL_HANDLER
+ var/new_value = source.light_on
+ if(new_value) //Truthy value input, turn on.
+ turn_on()
+ return
+ turn_off() //Falsey value, turn off.
+
+
+///Triggered right after the parent light flags change.
+/datum/component/overlay_lighting/proc/on_light_flags_change(atom/source, old_flags)
+ SIGNAL_HANDLER
+ var/new_flags = source.light_flags
+ var/atom/movable/movable_parent = parent
+ if(!((new_flags ^ old_flags) & LIGHT_ATTACHED))
+ return
+
+ if(new_flags & LIGHT_ATTACHED) // Gained the [LIGHT_ATTACHED] property
+ overlay_lighting_flags |= LIGHTING_ATTACHED
+ if(ismovable(movable_parent.loc))
+ set_parent_attached_to(movable_parent.loc)
+ else // Lost the [LIGHT_ATTACHED] property
+ overlay_lighting_flags &= ~LIGHTING_ATTACHED
+ set_parent_attached_to(null)
+
+
+///Toggles the light on.
+/datum/component/overlay_lighting/proc/turn_on()
+ if(overlay_lighting_flags & LIGHTING_ON)
+ return
+ if(current_holder)
+ if(directional)
+ cast_directional_light()
+ add_dynamic_lumi()
+ overlay_lighting_flags |= LIGHTING_ON
+ get_new_turfs()
+
+
+///Toggles the light off.
+/datum/component/overlay_lighting/proc/turn_off()
+ if(!(overlay_lighting_flags & LIGHTING_ON))
+ return
+ if(current_holder)
+ remove_dynamic_lumi()
+ overlay_lighting_flags &= ~LIGHTING_ON
+ clean_old_turfs()
+
+
+///Here we append the behavior associated to changing lum_power.
+/datum/component/overlay_lighting/proc/set_lum_power(new_lum_power)
+ if(lum_power == new_lum_power)
+ return
+ . = lum_power
+ lum_power = new_lum_power
+ var/difference = . - lum_power
+ for(var/t in affected_turfs)
+ var/turf/lit_turf = t
+ lit_turf.dynamic_lumcount -= difference
+
+///Here we append the behavior associated to changing lum_power.
+/datum/component/overlay_lighting/proc/cast_directional_light()
+ var/final_distance = cast_range
+ //Lower the distance by 1 if we're not looking at a cardinal direction, and we're not a short cast
+ if(final_distance > SHORT_CAST && !(ALL_CARDINALS & current_direction))
+ final_distance -= 1
+ var/turf/scanning = get_turf(current_holder)
+ for(var/i in 1 to final_distance)
+ var/turf/next_turf = get_step(scanning, current_direction)
+ if(isnull(next_turf) || IS_OPAQUE_TURF(next_turf))
+ break
+ scanning = next_turf
+ directional_atom.forceMove(scanning)
+
+///Called when current_holder changes loc.
+/datum/component/overlay_lighting/proc/on_holder_dir_change(atom/movable/source, olddir, newdir)
+ SIGNAL_HANDLER
+ set_direction(newdir)
+
+///Called when parent changes loc.
+/datum/component/overlay_lighting/proc/on_parent_dir_change(atom/movable/source, olddir, newdir)
+ SIGNAL_HANDLER
+ set_direction(newdir)
+
+///Sets a new direction for the directional cast, then updates luminosity
+/datum/component/overlay_lighting/proc/set_direction(newdir)
+ if(!newdir)
+ return
+ if(current_direction == newdir)
+ return
+ current_direction = newdir
+ cone.set_dir(newdir)
+
+ if(newdir & NORTH)
+ cone.pixel_y = 16
+ else if(newdir & SOUTH)
+ cone.pixel_y = -16
+ else
+ if(!isnull(cone_hint_y))
+ cone.pixel_y = cone_hint_y
+ else
+ cone.pixel_y = 0
+
+ if(newdir & EAST)
+ cone.pixel_x = 16
+ else if(newdir & WEST)
+ cone.pixel_x = -16
+ else
+ if(!isnull(cone_hint_x))
+ if(newdir & NORTH)
+ cone.pixel_x = -1*cone_hint_x
+ else
+ cone.pixel_x = cone_hint_x
+ else
+ cone.pixel_x = 0
+
+ if(overlay_lighting_flags & LIGHTING_ON)
+ make_luminosity_update()
+
+/datum/component/overlay_lighting/proc/on_parent_crafted(datum/source, atom/movable/new_craft)
+ SIGNAL_HANDLER
+
+ if(!istype(new_craft))
+ return
+
+ UnregisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT)
+ RegisterSignal(new_craft, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted)
+ set_parent_attached_to(new_craft)
+
+/// Handles putting the source for overlay lights into the light eater queue since we aren't tracked by [/atom/var/light_sources]
+/datum/component/overlay_lighting/proc/on_light_eater(datum/source, list/light_queue, datum/light_eater)
+ SIGNAL_HANDLER
+ light_queue[parent] = TRUE
+ return NONE
+
+#undef LIGHTING_ON
+#undef LIGHTING_ATTACHED
+#undef GET_PARENT
+#undef GET_LIGHT_SOURCE
+#undef SHORT_CAST
diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm
index 46a295f90be..30bd98a3268 100644
--- a/code/datums/elements/_element.dm
+++ b/code/datums/elements/_element.dm
@@ -1,9 +1,9 @@
/**
- * A holder for simple behaviour that can be attached to many different types
- *
- * Only one element of each type is instanced during game init.
- * Otherwise acts basically like a lightweight component.
- */
+ * A holder for simple behaviour that can be attached to many different types
+ *
+ * Only one element of each type is instanced during game init.
+ * Otherwise acts basically like a lightweight component.
+ */
/datum/element
/// Option flags for element behaviour
var/element_flags = NONE
@@ -18,17 +18,23 @@
/// Activates the functionality defined by the element on the given target datum
/datum/element/proc/Attach(datum/target)
- SHOULD_CALL_PARENT(1)
+ SHOULD_CALL_PARENT(TRUE)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
if(element_flags & ELEMENT_DETACH)
- RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/OnTargetDelete, override = TRUE)
+
+/datum/element/proc/OnTargetDelete(datum/source, force)
+ SIGNAL_HANDLER
+ Detach(source)
/// Deactivates the functionality defines by the element on the given datum
-/datum/element/proc/Detach(datum/source, force)
+/datum/element/proc/Detach(datum/source, ...)
+ SIGNAL_HANDLER
+
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
- SHOULD_CALL_PARENT(1)
+ SHOULD_CALL_PARENT(TRUE)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
/datum/element/Destroy(force)
@@ -41,15 +47,21 @@
/// Finds the singleton for the element type given and attaches it to src
/datum/proc/_AddElement(list/arguments)
+ if(QDELING(src))
+ CRASH("We just tried to add an element to a qdeleted datum, something is fucked")
var/datum/element/ele = SSdcs.GetElement(arguments)
arguments[1] = src
if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
/**
- * Finds the singleton for the element type given and detaches it from src
- * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
- */
+ * Finds the singleton for the element type given and detaches it from src
+ * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
+ */
/datum/proc/_RemoveElement(list/arguments)
var/datum/element/ele = SSdcs.GetElement(arguments)
- ele.Detach(src)
+ if(ele.element_flags & ELEMENT_COMPLEX_DETACH)
+ arguments[1] = src
+ ele.Detach(arglist(arguments))
+ else
+ ele.Detach(src)
diff --git a/code/datums/elements/light_blocking.dm b/code/datums/elements/light_blocking.dm
new file mode 100644
index 00000000000..86aac9f0758
--- /dev/null
+++ b/code/datums/elements/light_blocking.dm
@@ -0,0 +1,36 @@
+/**
+ * Attached to movable atoms with opacity. Listens to them move and updates their old and new turf loc's opacity accordingly.
+ */
+/datum/element/light_blocking
+ element_flags = ELEMENT_DETACH
+
+
+/datum/element/light_blocking/Attach(datum/target)
+ . = ..()
+ if(!ismovable(target))
+ return ELEMENT_INCOMPATIBLE
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/on_target_move)
+ var/atom/movable/movable_target = target
+ if(isturf(movable_target.loc))
+ var/turf/turf_loc = movable_target.loc
+ turf_loc.add_opacity_source(target)
+
+
+/datum/element/light_blocking/Detach(atom/movable/target)
+ . = ..()
+ UnregisterSignal(target, list(COMSIG_MOVABLE_MOVED))
+ var/atom/movable/movable_target = target
+ if(isturf(movable_target.loc))
+ var/turf/turf_loc = movable_target.loc
+ turf_loc.remove_opacity_source(target)
+
+
+///Updates old and new turf loc opacities.
+/datum/element/light_blocking/proc/on_target_move(atom/movable/source, atom/OldLoc, Dir, Forced = FALSE)
+ SIGNAL_HANDLER
+ if(isturf(OldLoc))
+ var/turf/old_turf = OldLoc
+ old_turf.remove_opacity_source(source)
+ if(isturf(source.loc))
+ var/turf/new_turf = source.loc
+ new_turf.add_opacity_source(source)
diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm
index 16d10ae0356..56faf42469f 100644
--- a/code/datums/mutable_appearance.dm
+++ b/code/datums/mutable_appearance.dm
@@ -10,10 +10,13 @@
plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE
// And yes this does have to be in the constructor, BYOND ignores it if you set it as a normal var
-// Helper similar to image()
-/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER)
+/// Helper similar to image()
+/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE)
var/mutable_appearance/MA = new()
MA.icon = icon
MA.icon_state = icon_state
MA.layer = layer
- return MA
\ No newline at end of file
+ MA.plane = plane
+ MA.alpha = alpha
+ MA.appearance_flags |= appearance_flags
+ return MA
diff --git a/code/datums/supplypacks/munitions_vr.dm b/code/datums/supplypacks/munitions_vr.dm
index 75f2124c962..fb0f0f90484 100644
--- a/code/datums/supplypacks/munitions_vr.dm
+++ b/code/datums/supplypacks/munitions_vr.dm
@@ -7,4 +7,14 @@
cost = 35
containertype = /obj/structure/closet/crate/secure
containername = "frontier phaser crate"
- access = access_explorer
\ No newline at end of file
+ access = access_explorer
+
+/datum/supply_pack/munitions/expeditionbows
+ name = "Frontier bows (station-locked) crate"
+ contains = list(
+ /obj/item/weapon/gun/energy/locked/frontier/handbow=2
+ )
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "frontier phaser crate"
+ access = access_explorer
diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm
index 32c847ece2e..33f30174fb1 100644
--- a/code/datums/supplypacks/security.dm
+++ b/code/datums/supplypacks/security.dm
@@ -421,7 +421,8 @@
/obj/item/clothing/accessory/holster,
/obj/item/clothing/accessory/holster/armpit,
/obj/item/clothing/accessory/holster/waist,
- /obj/item/clothing/accessory/holster/hip
+ /obj/item/clothing/accessory/holster/hip,
+ /obj/item/clothing/accessory/holster/leg
)
cost = 15
containertype = /obj/structure/closet/crate/hedberg
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 9c46ab200e7..90d43a7c36c 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -80,7 +80,7 @@
A.contents.Add(T)
if(old_area)
// Handle dynamic lighting update if
- if(T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting)
+ if(SSlighting.subsystem_initialized && T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting)
if(A.dynamic_lighting)
T.lighting_build_overlay()
else
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index daf2596ced3..186a156ba52 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -26,9 +26,16 @@
///Chemistry.
// Overlays
- var/list/our_overlays //our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate
- var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
+ ///Our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate
+ var/list/our_overlays
+ ///Overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
+ var/list/priority_overlays
+ ///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
+ var/list/managed_vis_overlays
+ ///Our local copy of filter data so we can add/remove it
+ var/list/filter_data
+
//Detective Work, used for the duplicate data points kept in the scanners
var/list/original_atom
// Track if we are already had initialize() called to prevent double-initialization.
@@ -82,6 +89,13 @@
initialized = TRUE
return INITIALIZE_HINT_NORMAL
+/atom/Destroy()
+ if(reagents)
+ QDEL_NULL(reagents)
+ if(light)
+ QDEL_NULL(light)
+ return ..()
+
// Called after all object's normal initialize() if initialize() returns INITIALIZE_HINT_LATELOAD
/atom/proc/LateInitialize()
return
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 645194543fb..728859eee76 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -30,37 +30,46 @@
var/cloaked = FALSE //If we're cloaked or not
var/image/cloaked_selfimage //The image we use for our client to let them see where we are
+/atom/movable/Initialize(mapload)
+ . = ..()
+ switch(blocks_emissive)
+ if(EMISSIVE_BLOCK_GENERIC)
+ var/mutable_appearance/gen_emissive_blocker = mutable_appearance(icon, icon_state, plane = PLANE_EMISSIVE, alpha = src.alpha)
+ gen_emissive_blocker.color = GLOB.em_block_color
+ gen_emissive_blocker.dir = dir
+ gen_emissive_blocker.appearance_flags |= appearance_flags
+ add_overlay(list(gen_emissive_blocker), TRUE)
+ if(EMISSIVE_BLOCK_UNIQUE)
+ render_target = ref(src)
+ em_block = new(src, render_target)
+ add_overlay(list(em_block), TRUE)
+ if(opacity)
+ AddElement(/datum/element/light_blocking)
+ switch(light_system)
+ if(STATIC_LIGHT)
+ update_light()
+ if(MOVABLE_LIGHT)
+ AddComponent(/datum/component/overlay_lighting, starts_on = light_on)
+ if(MOVABLE_LIGHT_DIRECTIONAL)
+ AddComponent(/datum/component/overlay_lighting, is_directional = TRUE, starts_on = light_on)
+
/atom/movable/Destroy()
. = ..()
- if(reagents)
- qdel(reagents)
- reagents = null
for(var/atom/movable/AM in contents)
qdel(AM)
- var/turf/un_opaque
- if(opacity && isturf(loc))
- un_opaque = loc
+
+ if(opacity)
+ RemoveElement(/datum/element/light_blocking)
moveToNullspace()
- if(un_opaque)
- un_opaque.recalc_atom_opacity()
- if (pulledby)
- if (pulledby.pulling == src)
- pulledby.pulling = null
- pulledby = null
+
+ if(pulledby)
+ pulledby.stop_pulling()
+
+ if(orbiting)
+ stop_orbit()
QDEL_NULL(riding_datum) //VOREStation Add
-
-/atom/movable/vv_get_dropdown()
- . = ..()
- VV_DROPDOWN_OPTION("move_atom", "Move To Coordinate")
-
-/atom/vv_do_topic(list/href_list)
- . = ..()
- IF_VV_OPTION("move_atom")
- usr.client.cmd_admin_move_atom(src)
- href_list["datumrefresh"] = "\ref[src]"
-
/atom/movable/vv_edit_var(var_name, var_value)
if(var_name in GLOB.VVpixelmovement) //Pixel movement is not yet implemented, changing this will break everything irreversibly.
return FALSE
@@ -211,12 +220,15 @@
//Called after a successful Move(). By this point, we've already moved
/atom/movable/proc/Moved(atom/old_loc, direction, forced = FALSE, movetime)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, direction, forced, movetime)
// Handle any buckled mobs on this movable
if(has_buckled_mobs())
handle_buckled_mob_movement(old_loc, direction, movetime)
if(riding_datum)
riding_datum.handle_vehicle_layer()
riding_datum.handle_vehicle_offsets()
+ for (var/datum/light_source/light as anything in light_sources) // Cycle through the light sources on this atom and tell them to update.
+ light.source_atom.update_light()
return TRUE
/atom/movable/set_dir(newdir)
diff --git a/code/game/atoms_movable_vr.dm b/code/game/atoms_movable_vr.dm
index d5291220290..94f01d7b7f4 100644
--- a/code/game/atoms_movable_vr.dm
+++ b/code/game/atoms_movable_vr.dm
@@ -1,2 +1,12 @@
/atom/movable/proc/Bump_vr(var/atom/A, yes)
return
+
+/atom/movable/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION("move_atom", "Move To Coordinate")
+
+/atom/vv_do_topic(list/href_list)
+ . = ..()
+ IF_VV_OPTION("move_atom")
+ usr.client.cmd_admin_move_atom(src)
+ href_list["datumrefresh"] = "\ref[src]"
diff --git a/code/game/gamemodes/changeling/powers/lesser_form.dm b/code/game/gamemodes/changeling/powers/lesser_form.dm
index d7b9cb0489c..ef82337d521 100644
--- a/code/game/gamemodes/changeling/powers/lesser_form.dm
+++ b/code/game/gamemodes/changeling/powers/lesser_form.dm
@@ -67,7 +67,7 @@
C.transforming = 1
C.canmove = 0
C.icon = null
- C.overlays.Cut()
+ C.cut_overlays()
C.invisibility = 101
var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc )
animation.icon_state = "blank"
diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm
index 954361fb9f7..aea5270f959 100644
--- a/code/game/gamemodes/cult/construct_spells.dm
+++ b/code/game/gamemodes/cult/construct_spells.dm
@@ -629,6 +629,7 @@ proc/findNullRod(var/atom/target)
light_range = 4
light_power = 5
light_color = "#FF0000"
+ light_on = TRUE
pulses_remaining = 10
pulse_delay = 1 SECOND
@@ -650,6 +651,7 @@ proc/findNullRod(var/atom/target)
aspect = ASPECT_UNHOLY
light_color = "#FF5C5C"
light_power = -2
+ light_on = TRUE
/obj/item/weapon/spell/construct/mend_occult/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
if(isliving(hit_atom))
@@ -666,6 +668,7 @@ proc/findNullRod(var/atom/target)
aspect = ASPECT_UNHOLY
light_color = "#FF5C5C"
light_power = -2
+ light_on = TRUE
cooldown = 15
/obj/item/weapon/spell/construct/slam/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm
index 310a7a9ae70..280d2ed6bd5 100644
--- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm
+++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm
@@ -91,6 +91,8 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked
A.updateicon()
/datum/universal_state/supermatter_cascade/OverlayAndAmbientSet()
+ return
+ /* TODO
spawn(0)
for(var/datum/lighting_corner/L in world)
if(L.z in using_map.admin_levels)
@@ -100,7 +102,7 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked
for(var/turf/space/T in world)
OnTurfChange(T)
-
+ */
/datum/universal_state/supermatter_cascade/proc/MiscSet()
for (var/obj/machinery/firealarm/alm in machines)
if (!(alm.stat & BROKEN))
diff --git a/code/game/gamemodes/technomancer/instability.dm b/code/game/gamemodes/technomancer/instability.dm
index 8b4e1f27676..a7cf71b8f0b 100644
--- a/code/game/gamemodes/technomancer/instability.dm
+++ b/code/game/gamemodes/technomancer/instability.dm
@@ -90,9 +90,9 @@
last_instability_event = world.time
spawn(1)
var/image/instability_flash = image('icons/obj/spells.dmi',"instability")
- overlays |= instability_flash
+ add_overlay(instability_flash)
sleep(4)
- overlays.Remove(instability_flash)
+ cut_overlay(instability_flash)
qdel(instability_flash)
/mob/living/silicon/instability_effects()
diff --git a/code/game/gamemodes/technomancer/spell_objs.dm b/code/game/gamemodes/technomancer/spell_objs.dm
index 2c80ac39fd9..a9eb862ee93 100644
--- a/code/game/gamemodes/technomancer/spell_objs.dm
+++ b/code/game/gamemodes/technomancer/spell_objs.dm
@@ -168,9 +168,9 @@
/obj/item/weapon/spell/update_icon()
if(toggled)
var/image/new_overlay = image('icons/obj/spells.dmi',"toggled")
- overlays |= new_overlay
+ add_overlay(new_overlay)
else
- overlays.Cut()
+ cut_overlays()
..()
// Proc: run_checks()
diff --git a/code/game/gamemodes/technomancer/spells/illusion.dm b/code/game/gamemodes/technomancer/spells/illusion.dm
index 2d33f6e9260..5d626f7c479 100644
--- a/code/game/gamemodes/technomancer/spells/illusion.dm
+++ b/code/game/gamemodes/technomancer/spells/illusion.dm
@@ -65,11 +65,11 @@
// Makes a tiny overlay of the thing the player has copied, so they can easily tell what they currently have.
/obj/item/weapon/spell/illusion/update_icon()
- overlays.Cut()
+ cut_overlays()
if(copied)
var/image/temp_image = image(copied)
var/matrix/M = matrix()
M.Scale(0.5, 0.5)
temp_image.transform = M
// temp_image.pixel_y = 8
- src.overlays.Add(temp_image)
+ add_overlay(temp_image)
diff --git a/code/game/gamemodes/technomancer/spells/spawner/darkness.dm b/code/game/gamemodes/technomancer/spells/spawner/darkness.dm
index d83602aa68b..f54f9b75025 100644
--- a/code/game/gamemodes/technomancer/spells/spawner/darkness.dm
+++ b/code/game/gamemodes/technomancer/spells/spawner/darkness.dm
@@ -27,4 +27,5 @@
time_to_die = 2 MINUTES
invisibility = 101
light_range = 6
- light_power = -20
\ No newline at end of file
+ light_power = -20
+ light_on = TRUE
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/spawner/destablize.dm b/code/game/gamemodes/technomancer/spells/spawner/destablize.dm
index aee8d2557b9..9bf6b072812 100644
--- a/code/game/gamemodes/technomancer/spells/spawner/destablize.dm
+++ b/code/game/gamemodes/technomancer/spells/spawner/destablize.dm
@@ -31,6 +31,7 @@
light_range = 6
light_power = 20
light_color = "#C26DDE"
+ light_on = TRUE
var/pulses_remaining = 40 // Lasts 20 seconds.
var/instability_power = 5
var/instability_range = 6
diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm
index b7b1ab3aed5..e53fa62935b 100644
--- a/code/game/jobs/access.dm
+++ b/code/game/jobs/access.dm
@@ -28,32 +28,21 @@
return has_access(req_access, req_one_access, L)
/proc/has_access(var/list/req_access, var/list/req_one_access, var/list/accesses)
- // Doesn't have access lists, always works
- if(!LAZYLEN(req_access) && !LAZYLEN(req_one_access))
- return TRUE
-
- // Didn't pass anything to compare
- if(!LAZYLEN(accesses))
- return FALSE
-
// req_access list has priority if set
// Requires at least every access in list
- if(LAZYLEN(req_access))
- for(var/req in req_access)
- if(!(req in accesses))
- return FALSE
- // Wasn't missing any accesses
- return TRUE
+ for(var/req in req_access)
+ if(!(req in accesses))
+ return FALSE
// req_one_access is secondary if set
// Requires at least one access in list
- for(var/req in req_one_access)
- if(req in accesses)
- // Found at least one
- return TRUE
+ if(LAZYLEN(req_one_access))
+ for(var/req in req_one_access)
+ if(req in accesses)
+ return TRUE
+ return FALSE
- // Didn't find anything that matched
- return FALSE
+ return TRUE
/proc/get_centcom_access(job)
switch(job)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index e0ff3a6086c..46f6710aafb 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -80,7 +80,7 @@
/obj/machinery/sleep_console/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
if(sleeper)
return sleeper.tgui_act(action, params, ui, state)
- return FALSE
+ return ..()
/obj/machinery/sleeper
name = "sleeper"
diff --git a/code/game/machinery/airconditioner_vr.dm b/code/game/machinery/airconditioner_vr.dm
index 892c6b4929b..1aa25160858 100644
--- a/code/game/machinery/airconditioner_vr.dm
+++ b/code/game/machinery/airconditioner_vr.dm
@@ -109,14 +109,14 @@
env.merge(removed)
/obj/machinery/power/thermoregulator/update_icon()
- overlays.Cut()
+ cut_overlays()
if(on)
- overlays += "lasergen-on"
+ add_overlay("lasergen-on")
switch(mode)
if(MODE_HEATING)
- overlays += "lasergen-heat"
+ add_overlay("lasergen-heat")
if(MODE_COOLING)
- overlays += "lasergen-cool"
+ add_overlay("lasergen-cool")
/obj/machinery/power/thermoregulator/proc/turn_off()
on = 0
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 2d5e39b1b71..8895844b008 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -141,20 +141,20 @@ update_flag
if(check_change()) //Returns 1 if no change needed to icons.
return
- src.overlays = 0
+ cut_overlays()
if(update_flag & 1)
- overlays += "can-open"
+ add_overlay("can-open")
if(update_flag & 2)
- overlays += "can-connector"
+ add_overlay("can-connector")
if(update_flag & 4)
- overlays += "can-o0"
+ add_overlay("can-o0")
if(update_flag & 8)
- overlays += "can-o1"
+ add_overlay("can-o1")
else if(update_flag & 16)
- overlays += "can-o2"
+ add_overlay("can-o2")
else if(update_flag & 32)
- overlays += "can-o3"
+ add_overlay("can-o3")
return
/obj/machinery/portable_atmospherics/canister/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm
index 74e48046613..f97a66bd78b 100644
--- a/code/game/machinery/atmoalter/pump.dm
+++ b/code/game/machinery/atmoalter/pump.dm
@@ -29,7 +29,7 @@
src.air_contents.adjust_multi("oxygen", air_mix["oxygen"], "nitrogen", air_mix["nitrogen"])
/obj/machinery/portable_atmospherics/powered/pump/update_icon()
- src.overlays = 0
+ cut_overlays()
if(on && cell && cell.charge)
icon_state = "psiphon:1"
@@ -37,10 +37,10 @@
icon_state = "psiphon:0"
if(holding)
- overlays += "siphon-open"
+ add_overlay("siphon-open")
if(connected_port)
- overlays += "siphon-connector"
+ add_overlay("siphon-connector")
return
diff --git a/code/game/machinery/atmoalter/pump_vr.dm b/code/game/machinery/atmoalter/pump_vr.dm
index 69be9208a1c..e056086baf8 100644
--- a/code/game/machinery/atmoalter/pump_vr.dm
+++ b/code/game/machinery/atmoalter/pump_vr.dm
@@ -26,7 +26,7 @@
to_chat(user, "You can't directly interact with this machine. Use the pump control console.")
/obj/machinery/portable_atmospherics/powered/pump/huge/update_icon()
- overlays.Cut()
+ cut_overlays()
if(on && !(stat & (NOPOWER|BROKEN)))
icon_state = "siphon:1"
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index 1f9d1908003..f154e64d896 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -36,7 +36,7 @@
..(severity)
/obj/machinery/portable_atmospherics/powered/scrubber/update_icon()
- src.overlays = 0
+ cut_overlays()
if(on && cell && cell.charge)
icon_state = "pscrubber:1"
@@ -44,10 +44,10 @@
icon_state = "pscrubber:0"
if(holding)
- overlays += "scrubber-open"
+ add_overlay("scrubber-open")
if(connected_port)
- overlays += "scrubber-connector"
+ add_overlay("scrubber-connector")
return
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 80fba122b42..8fa51418392 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -241,12 +241,12 @@
return FALSE
/obj/machinery/autolathe/update_icon()
- overlays.Cut()
+ cut_overlays()
icon_state = initial(icon_state)
if(panel_open)
- overlays.Add(image(icon, "[icon_state]_panel"))
+ add_overlay("[icon_state]_panel")
if(stat & NOPOWER)
return
if(busy)
diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester_vr.dm
index e3a36435262..ea9add72ceb 100644
--- a/code/game/machinery/bomb_tester_vr.dm
+++ b/code/game/machinery/bomb_tester_vr.dm
@@ -62,11 +62,11 @@
simulation_finish()
/obj/machinery/bomb_tester/update_icon()
- overlays.Cut()
+ cut_overlays()
if(tank1)
- overlays += image(icon, "[icon_name]-tank1")
+ add_overlay("[icon_name]-tank1")
if(tank2)
- overlays += image(icon, "[icon_name]-tank2")
+ add_overlay("[icon_name]-tank2")
if(stat & NOPOWER)
icon_state = "[icon_name]-p"
else
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index 2b768fb3e64..4cfdb16dd06 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -27,12 +27,12 @@
if(chargelevel != newlevel)
- overlays.Cut()
- overlays += "ccharger-o[newlevel]"
+ cut_overlays()
+ add_overlay("ccharger-o[newlevel]")
chargelevel = newlevel
else
- overlays.Cut()
+ cut_overlays()
/obj/machinery/cell_charger/examine(mob/user)
. = ..()
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index 9b230cc3d2e..110b70ab8c4 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -7,6 +7,7 @@
use_power = USE_POWER_IDLE
idle_power_usage = 300
active_power_usage = 300
+ blocks_emissive = FALSE
var/processing = 0
var/icon_keyboard = "generic_key"
@@ -62,29 +63,32 @@
/obj/machinery/computer/update_icon()
cut_overlays()
- // No power
- if(stat & NOPOWER)
- set_light(0)
- if(icon_keyboard)
- add_overlay("[icon_keyboard]_off")
- playsound(src, 'sound/machines/terminal_off.ogg', 50, 1)
- // Yes power
- else
- if(icon_keyboard)
- add_overlay(icon_keyboard)
- set_light(light_range_on, light_power_on)
- playsound(src, 'sound/machines/terminal_on.ogg', 50, 1)
+
+ . = list()
- // Broken
- if(stat & BROKEN)
- add_overlay("[icon_state]_broken")
- // Not broken
- else
- add_overlay(icon_screen)
+ if(icon_keyboard)
+ if(stat & NOPOWER)
+ playsound(src, 'sound/machines/terminal_off.ogg', 50, 1)
+ return add_overlay("[icon_keyboard]_off")
+ . += icon_keyboard
+
+ // This whole block lets screens ignore lighting and be visible even in the darkest room
+ var/overlay_state = icon_screen
+ if(stat & BROKEN)
+ overlay_state = "[icon_state]_broken"
+ . += mutable_appearance(icon, overlay_state)
+ . += emissive_appearance(icon, overlay_state)
+ playsound(src, 'sound/machines/terminal_on.ogg', 50, 1)
+
+ add_overlay(.)
/obj/machinery/computer/power_change()
..()
update_icon()
+ if(stat & NOPOWER)
+ set_light(0)
+ else
+ set_light(light_range_on, light_power_on)
/obj/machinery/computer/proc/set_broken()
stat |= BROKEN
diff --git a/code/game/machinery/doorbell_vr.dm b/code/game/machinery/doorbell_vr.dm
index 3dd029631ea..1b6174a2ca2 100644
--- a/code/game/machinery/doorbell_vr.dm
+++ b/code/game/machinery/doorbell_vr.dm
@@ -33,9 +33,9 @@
update_icon()
/obj/machinery/doorbell_chime/update_icon()
- overlays.Cut()
+ cut_overlays()
if(panel_open)
- overlays += "dbchime-open"
+ add_overlay("dbchime-open")
if(inoperable())
icon_state = "dbchime-off"
if(!id_tag)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 97558066e96..6288de28b24 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -13,6 +13,8 @@
power_channel = ENVIRON
explosion_resistance = 10
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC // Not quite as nice as /tg/'s custom masks. We should make those sometime
+
var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
var/hackProof = 0 // if 1, this door can't be hacked by the AI
var/electrified_until = 0 //World time when the door is no longer electrified. -1 if it is permanently electrified until someone fixes it.
@@ -791,35 +793,34 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/update_icon()
- if(overlays) overlays.Cut()
+ cut_overlays()
if(density)
if(locked && lights && src.arePowerSystemsOn())
icon_state = "door_locked"
else
icon_state = "door_closed"
if(p_open || welded)
- overlays = list()
if(p_open)
- overlays += image(icon, "panel_open")
+ add_overlay("panel_open")
if (!(stat & NOPOWER))
if(stat & BROKEN)
- overlays += image(icon, "sparks_broken")
+ add_overlay("sparks_broken")
else if (health < maxhealth * 3/4)
- overlays += image(icon, "sparks_damaged")
+ add_overlay("sparks_damaged")
if(welded)
- overlays += image(icon, "welded")
+ add_overlay("welded")
else if (health < maxhealth * 3/4 && !(stat & NOPOWER))
- overlays += image(icon, "sparks_damaged")
+ add_overlay("sparks_damaged")
else
icon_state = "door_open"
if((stat & BROKEN) && !(stat & NOPOWER))
- overlays += image(icon, "sparks_open")
+ add_overlay("sparks_open")
return
/obj/machinery/door/airlock/do_animate(animation)
switch(animation)
if("opening")
- if(overlays) overlays.Cut()
+ cut_overlay()
if(p_open)
spawn(2) // The only work around that works. Downside is that the door will be gone for a millisecond.
flick("o_door_opening", src) //can not use flick due to BYOND bug updating overlays right before flicking
@@ -828,7 +829,7 @@ About the new airlock wires panel:
flick("door_opening", src)//[stat ? "_stat":]
update_icon()
if("closing")
- if(overlays) overlays.Cut()
+ cut_overlay()
if(p_open)
spawn(2)
flick("o_door_closing", src)
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index 6834bc550c1..2d399b81aa5 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -388,24 +388,13 @@ obj/machinery/door/blast/gate/open
. = ..()
apply_opacity_to_my_turfs(opacity)
-/obj/machinery/door/blast/multi_tile/open()
- if((. = ..()))
- apply_opacity_to_my_turfs(opacity)
+/obj/machinery/door/blast/multi_tile/set_opacity()
+ . = ..()
+ apply_opacity_to_my_turfs(opacity)
-/obj/machinery/door/blast/multi_tile/close()
- if((. = ..()))
- apply_opacity_to_my_turfs(opacity)
-
-/obj/machinery/door/blast/multi_tile/Destroy()
- apply_opacity_to_my_turfs(0)
- return ..()
-
-//Multi-tile poddoors don't turn invisible automatically, so we change the opacity of the turfs below instead one by one.
/obj/machinery/door/blast/multi_tile/proc/apply_opacity_to_my_turfs(new_opacity)
for(var/turf/T in locs)
- T.opacity = new_opacity
- T.has_opaque_atom = new_opacity
- T.reconsider_lights()
+ T.set_opacity(new_opacity)
update_nearby_tiles()
/obj/machinery/door/blast/multi_tile
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index fc03dcb8d28..616205563de 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -11,6 +11,7 @@
density = 1
can_atmos_pass = ATMOS_PASS_PROC
layer = DOOR_OPEN_LAYER
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
var/open_layer = DOOR_OPEN_LAYER
var/closed_layer = DOOR_CLOSED_LAYER
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 6cae2617fd4..e9585aa8121 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -444,29 +444,29 @@
/obj/machinery/door/firedoor/update_icon()
- overlays.Cut()
+ cut_overlays()
if(density)
icon_state = "door_closed"
if(prying)
icon_state = "prying_closed"
if(hatch_open)
- overlays += "hatch"
+ add_overlay("hatch")
if(blocked)
- overlays += "welded"
+ add_overlay("welded")
if(pdiff_alert)
- overlays += "palert"
+ add_overlay("palert")
if(dir_alerts)
for(var/d=1;d<=4;d++)
var/cdir = cardinal[d]
for(var/i=1;i<=ALERT_STATES.len;i++)
if(dir_alerts[d] & (1<<(i-1)))
- overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir)
+ add_overlay(new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir))
else
icon_state = "door_open"
if(prying)
icon_state = "prying_open"
if(blocked)
- overlays += "welded_open"
+ add_overlay("welded_open")
return
//These are playing merry hell on ZAS. Sorry fellas :(
diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm
index ec5acbea73c..23b71bdb0f1 100644
--- a/code/game/machinery/doors/multi_tile.dm
+++ b/code/game/machinery/doors/multi_tile.dm
@@ -7,41 +7,25 @@
open_sound_powered = 'sound/machines/door/WideOpen.ogg'
close_sound_powered = 'sound/machines/door/WideClose.ogg'
-/obj/machinery/door/airlock/multi_tile/New()
- ..()
+/obj/machinery/door/airlock/multi_tile/Initialize(mapload)
+ . = ..()
SetBounds()
- if(opacity)
- create_fillers()
+ RegisterSignal(src, COMSIG_MOVABLE_MOVED, .proc/SetBounds)
+ apply_opacity_to_my_turfs(opacity)
+
+/obj/machinery/door/airlock/multi_tile/set_opacity()
+ . = ..()
+ apply_opacity_to_my_turfs(opacity)
+
+/obj/machinery/door/airlock/multi_tile/proc/apply_opacity_to_my_turfs(new_opacity)
+ for(var/turf/T in locs)
+ T.set_opacity(new_opacity)
+ update_nearby_tiles()
/obj/machinery/door/airlock/multi_tile/Destroy()
- QDEL_NULL(filler1)
- QDEL_NULL(filler2)
+ UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
return ..()
-/obj/machinery/door/airlock/multi_tile/Moved(atom/old_loc, direction, forced = FALSE)
- . = ..()
- SetBounds()
-
-/obj/machinery/door/airlock/multi_tile/open()
- . = ..()
-
- if(filler1)
- filler1.set_opacity(opacity)
- if(filler2)
- filler2.set_opacity(opacity)
-
- return .
-
-/obj/machinery/door/airlock/multi_tile/close()
- . = ..()
-
- if(filler1)
- filler1.set_opacity(opacity)
- if(filler2)
- filler2.set_opacity(opacity)
-
- return .
-
/obj/machinery/door/airlock/multi_tile/proc/SetBounds()
if(dir in list(EAST, WEST))
bound_width = width * world.icon_size
@@ -50,18 +34,6 @@
bound_width = world.icon_size
bound_height = width * world.icon_size
-/obj/machinery/door/airlock/multi_tile/proc/create_fillers()
- if(src.dir > 3)
- filler1 = new/obj/machinery/filler_object (src.loc)
- filler2 = new/obj/machinery/filler_object (get_step(src,EAST))
- else
- filler1 = new/obj/machinery/filler_object (src.loc)
- filler2 = new/obj/machinery/filler_object (get_step(src,NORTH))
- filler1.density = 0
- filler2.density = 0
- filler1.set_opacity(opacity)
- filler2.set_opacity(opacity)
-
/obj/machinery/door/airlock/multi_tile/glass
name = "Glass Airlock"
icon = 'icons/obj/doors/Door2x1glass.dmi'
@@ -74,12 +46,6 @@
icon = 'icons/obj/doors/Door2x1metal.dmi'
assembly_type = /obj/structure/door_assembly/multi_tile
-/obj/machinery/filler_object
- name = ""
- icon = 'icons/obj/doors/rapid_pdoor.dmi'
- icon_state = ""
- density = 0
-
/obj/machinery/door/airlock/multi_tile/metal/mait
icon = 'icons/obj/doors/Door2x1_Maint.dmi'
//req_one_access = list(access_maint_tunnels) //VOREStaiton Edit - Maintenance is open access
diff --git a/code/game/machinery/doors/multi_tile_vr.dm b/code/game/machinery/doors/multi_tile_vr.dm
index f8a76c51ea1..1d179ca99d8 100644
--- a/code/game/machinery/doors/multi_tile_vr.dm
+++ b/code/game/machinery/doors/multi_tile_vr.dm
@@ -1,22 +1,3 @@
/obj/machinery/door/airlock/multi_tile/glass/polarized
name = "Electrochromic Glass Airlock"
icon_tinted = 'icons/obj/doors/Door2x1tinted_vr.dmi'
-
-/obj/machinery/door/airlock/multi_tile/glass/polarized/New()
- ..()
- create_fillers()
-
-/obj/machinery/door/airlock/multi_tile/glass/polarized/toggle()
- . = ..()
- if(!operating)
- if(filler1)
- filler1.set_opacity(opacity)
- if(filler2)
- filler2.set_opacity(opacity)
-
-/obj/machinery/door/airlock/multi_tile/glass/polarized/close()
- . = ..()
- if(filler1)
- filler1.set_opacity(!glass)
- if(filler2)
- filler2.set_opacity(!glass)
\ No newline at end of file
diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm
index b153437ca6f..be588976226 100644
--- a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm
+++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm
@@ -30,7 +30,7 @@
)
/obj/machinery/embedded_controller/radio/docking_port_multi/tgui_act(action, params)
- return // Apparently we swallow all input (this is corrected legacy code)
+ return ..() // Apparently we swallow all input (this is corrected legacy code)
//a docking port based on an airlock
// This is the actual controller that will be commanded by the master defined above
diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm
index 315d470432a..a1a22b80c89 100644
--- a/code/game/machinery/fire_alarm.dm
+++ b/code/game/machinery/fire_alarm.dm
@@ -5,8 +5,9 @@ FIRE ALARM
name = "fire alarm"
desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever."
icon = 'icons/obj/monitors.dmi'
- icon_state = "fire0"
+ icon_state = "fire"
layer = ABOVE_WINDOW_LAYER
+ blocks_emissive = FALSE
var/detecting = 1.0
var/working = 1.0
var/time = 10.0
@@ -45,24 +46,36 @@ FIRE ALARM
if(stat & BROKEN)
icon_state = "firex"
set_light(0)
+ return
else if(stat & NOPOWER)
icon_state = "firep"
set_light(0)
+ return
+
+ var/fire_state
+
+ . = list()
+ icon_state = "fire"
+ if(!detecting)
+ fire_state = "fire1"
+ set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000")
else
- if(!detecting)
- icon_state = "fire1"
- set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000")
- else
- icon_state = "fire0"
- switch(seclevel)
- if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00")
- if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00")
- if("violet") set_light(l_range = 2, l_power = 0.25, l_color = "#9933ff")
- if("orange") set_light(l_range = 2, l_power = 0.25, l_color = "#ff9900")
- if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9")
- if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000")
- if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633")
- add_overlay("overlay_[seclevel]")
+ fire_state = "fire0"
+ switch(seclevel)
+ if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00")
+ if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00")
+ if("violet") set_light(l_range = 2, l_power = 0.25, l_color = "#9933ff")
+ if("orange") set_light(l_range = 2, l_power = 0.25, l_color = "#ff9900")
+ if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9")
+ if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000")
+ if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633")
+
+ . += mutable_appearance(icon, fire_state)
+ . += emissive_appearance(icon, fire_state)
+ . += mutable_appearance(icon, "overlay_[seclevel]")
+ . += emissive_appearance(icon, "overlay_[seclevel]")
+
+ add_overlay(.)
/obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume)
if(detecting)
diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm
index 84aa62b1557..e4b961eebe3 100644
--- a/code/game/machinery/floodlight.dm
+++ b/code/game/machinery/floodlight.dm
@@ -16,7 +16,7 @@
..()
/obj/machinery/floodlight/update_icon()
- overlays.Cut()
+ cut_overlays()
icon_state = "flood[open ? "o" : ""][open && cell ? "b" : ""]0[on]"
/obj/machinery/floodlight/process()
diff --git a/code/game/machinery/floor_light.dm b/code/game/machinery/floor_light.dm
index 0a3f13fedcc..b1211f1fd2e 100644
--- a/code/game/machinery/floor_light.dm
+++ b/code/game/machinery/floor_light.dm
@@ -103,7 +103,7 @@ var/list/floor_light_cache = list()
update_icon()
/obj/machinery/floor_light/update_icon()
- overlays.Cut()
+ cut_overlays()
if(use_power && !broken())
if(isnull(damaged))
var/cache_key = "floorlight-[default_light_colour]"
@@ -112,7 +112,7 @@ var/list/floor_light_cache = list()
I.color = default_light_colour
I.layer = layer+0.001
floor_light_cache[cache_key] = I
- overlays |= floor_light_cache[cache_key]
+ add_overlay(floor_light_cache[cache_key])
else
if(damaged == 0) //Needs init.
damaged = rand(1,4)
@@ -122,7 +122,7 @@ var/list/floor_light_cache = list()
I.color = default_light_colour
I.layer = layer+0.001
floor_light_cache[cache_key] = I
- overlays |= floor_light_cache[cache_key]
+ add_overlay(floor_light_cache[cache_key])
/obj/machinery/floor_light/proc/broken()
return (stat & (BROKEN|NOPOWER))
diff --git a/code/game/machinery/gear_dispenser.dm b/code/game/machinery/gear_dispenser.dm
index c38e8766d13..28a7e93d969 100644
--- a/code/game/machinery/gear_dispenser.dm
+++ b/code/game/machinery/gear_dispenser.dm
@@ -6,6 +6,7 @@
#define GD_ONEITEM 2 // only one type of suit comes out of this dispenser.
#define GD_NOGREED 4 // no-one is allowed more than one item from this TYPE of dispenser unless emagged
#define GD_UNLIMITED 8 // will not deplete amount when gear is taken
+#define GD_UNIQUE 16 // each instance of this will allow people to take 1 thing
var/list/dispenser_presets = list()
@@ -86,8 +87,7 @@ var/list/dispenser_presets = list()
if(voidsuit.helmet)
error("[src] created a voidsuit [voidsuit] and wants to add a helmet but it already has one")
else
- voidhelmet = new voidhelmet_type(voidsuit)
- voidsuit.helmet = voidhelmet
+ voidsuit.attach_helmet(new voidhelmet_type())
spawned += voidhelmet
// If we're supposed to make boots
if(magboots_type)
@@ -155,6 +155,8 @@ var/list/dispenser_presets = list()
var/datum/gear_disp/one_setting
var/global/list/gear_distributed_to = list()
var/dispenser_flags = GD_NOGREED|GD_UNLIMITED
+ var/unique_dispense_list = list()
+ var/needs_power = 0
//req_one_access = list(whatever) // Note that each gear datum can have access, too.
/obj/machinery/gear_dispenser/custom/emag_act(remaining_charges, mob/user, emag_source)
@@ -199,6 +201,9 @@ var/list/dispenser_presets = list()
/obj/machinery/gear_dispenser/proc/can_use(var/mob/living/carbon/human/user)
var/list/used_by = gear_distributed_to["[type]"]
+ if(needs_power && inoperable())
+ to_chat(user,"The machine does not respond to your prodding.")
+ return 0
if(!istype(user))
to_chat(user,"You can't use this!")
return 0
@@ -208,15 +213,19 @@ var/list/dispenser_presets = list()
if((dispenser_flags & GD_ONEITEM) && !(dispenser_flags & GD_UNLIMITED) && !one_setting.amount)
to_chat(user,"There's nothing in here!")
return 0
- if ((dispenser_flags & GD_NOGREED) && (weakref(user) in used_by) && !emagged)
- to_chat(user,"You've already picked up your gear!")
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
- return 0
- if(emagged)
+ if (!emagged)
+ if ((dispenser_flags & GD_NOGREED) && (user.ckey in used_by))
+ to_chat(user,"You've already picked up your gear!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ return 0
+ if ((dispenser_flags & GD_UNIQUE) && (user.ckey in unique_dispense_list))
+ to_chat(user,"You've already picked up your gear!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ return 0
+ else
audible_message("!'^&YouVE alreaDY pIC&$!Ked UP yOU%r Ge^!ar.")
playsound(src, 'sound/machines/buzz-sigh.ogg', 100, 0)
- return 1
-
+ return 1
// And finally
if(allowed(user))
return 1
@@ -245,7 +254,10 @@ var/list/dispenser_presets = list()
else if(!(dispenser_flags & GD_UNLIMITED))
S.amount--
if((dispenser_flags & GD_NOGREED) && !emagged)
- gear_distributed_to["[type]"] |= weakref(user)
+ gear_distributed_to["[type]"] |= user.ckey
+ if((dispenser_flags & GD_UNIQUE) && !emagged)
+ unique_dispense_list |= user.ckey
+
flick("[icon_state]-scan",src)
visible_message("\The [src] scans its user.", runemessage = "hums")
sleep(30)
@@ -529,3 +541,216 @@ var/list/dispenser_presets = list()
running[option_name] = G
to_chat(usr, "[src] added [running.len] entries")
dispenses = running
+
+////////////////////////////// RANDOM SUIT AND WEAPON DISPENSERS ///////////////////////////
+
+/obj/machinery/gear_dispenser/randomvoidsuit
+ name = "Suit Dispenser"
+ desc = "An industrial U-Tak-It Dispenser unit designed to fetch voidsuits."
+ icon_state = "suitdispenserAL"
+ dispenser_flags = GD_ONEITEM|GD_NOGREED
+ one_setting = /datum/gear_disp/voidsuit/random
+
+/datum/gear_disp/voidsuit/random
+ name = "Voidsuit"
+ to_spawn = list()
+ amount = 4
+
+/datum/gear_disp/voidsuit/random/spawn_gear(var/turf/T, var/mob/living/carbon/user)
+ // I copied these from the /obj/random/multiple/voidsuit, but added the "suit" and "helmet"
+ var/list/choice = pick(
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void,
+ "helmet" = /obj/item/clothing/head/helmet/space/void
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/atmos,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/atmos
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/atmos/alt,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/atmos/alt
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/engineering,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/engineering
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/engineering/alt,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/engineering/alt
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/engineering/hazmat,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/engineering/hazmat
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/engineering/construction,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/engineering/construction
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/engineering/salvage,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/engineering/salvage
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/medical,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/medical
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/medical/alt,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/medical/alt
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/medical/bio,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/medical/bio
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/medical/emt,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/medical/emt
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/merc,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/merc
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/merc/fire,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/merc/fire
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/mining,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/mining
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/mining/alt,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/mining/alt
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/security,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/security
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/security/alt,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/security/alt
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/security/riot,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/security/riot
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/exploration,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/exploration
+ ),
+ prob(5);list(
+ "suit" = /obj/item/clothing/suit/space/void/pilot,
+ "helmet" = /obj/item/clothing/head/helmet/space/void/pilot
+ ))
+ voidsuit_type = choice["suit"]
+ voidhelmet_type = choice["helmet"]
+ return ..()
+
+/obj/machinery/gear_dispenser/randomweapons
+ name = "Weapon Dispenser"
+ desc = "An industrial U-Tak-It Dispenser unit designed to fetch weapons."
+ dispenser_flags = GD_ONEITEM|GD_NOGREED
+ one_setting = /datum/gear_disp/randomweapons
+
+/datum/gear_disp/randomweapons
+ name = "Weapon"
+ amount = 2
+
+/datum/gear_disp/randomweapons/spawn_gear(var/turf/T, var/mob/living/carbon/user)
+ var/choice = pick(
+ prob(3);/obj/random/multiple/gun/projectile/handgun,
+ prob(2);/obj/random/multiple/gun/projectile/smg,
+ prob(2);/obj/random/multiple/gun/projectile/shotgun,
+ prob(1);/obj/random/multiple/gun/projectile/rifle)
+ to_spawn = list(choice)
+ return ..()
+
+///////////////////Adventure Box//////////////////////////
+
+/obj/machinery/gear_dispenser/adventure_box
+ name = "Dispenser"
+ desc = "An industrial U-Tak-It Dispenser unit designed to fetch items that one might need in dangerous scenarios!"
+ dispenser_flags = GD_UNIQUE
+ dispenses = list(
+ /datum/gear_disp/adventure_box/awayloot,
+ /datum/gear_disp/adventure_box/food,
+ /datum/gear_disp/adventure_box/medical,
+ /datum/gear_disp/adventure_box/tools,
+ /datum/gear_disp/adventure_box/armor,
+ /datum/gear_disp/adventure_box/light
+ )
+ var/chance_to_delete = 0
+
+/obj/machinery/gear_dispenser/adventure_box/Initialize()
+ . = ..()
+ if(prob(chance_to_delete))
+ return INITIALIZE_HINT_QDEL
+
+/datum/gear_disp/adventure_box/medical
+ name = "Medkit"
+ to_spawn = list(/obj/random/firstaid)
+ amount = 2
+
+/datum/gear_disp/adventure_box/awayloot
+ name = "Curious Item"
+ to_spawn = list(/obj/random/awayloot/nofail)
+ amount = 5
+
+/datum/gear_disp/adventure_box/food
+ name = "Food Plate"
+ to_spawn = list(
+ /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar,
+ /obj/item/weapon/reagent_containers/food/snacks/no_raisin,
+ /obj/item/weapon/reagent_containers/food/drinks/tea
+ )
+ amount = 10
+
+/datum/gear_disp/adventure_box/tools
+ name = "Tools"
+ to_spawn = list(
+ /obj/random/tool,
+ /obj/random/tool,
+ /obj/random/tool,
+ /obj/item/weapon/storage/belt/utility
+ )
+ amount = 5
+
+/datum/gear_disp/adventure_box/armor
+ name = "Armor"
+ to_spawn = list(
+ /obj/item/clothing/suit/armor/vest,
+ /obj/item/clothing/head/helmet/bulletproof,
+ /obj/item/clothing/shoes/boots/jackboots
+ )
+ amount = 1
+
+/datum/gear_disp/adventure_box/light
+ name = "Flashlight"
+ to_spawn = list(/obj/item/device/flashlight/maglight)
+ amount = 2
+
+/datum/gear_disp/adventure_box/weapon
+ name = "Ranged Weapon"
+ amount = 1
+//from /obj/random/projectile/random
+/datum/gear_disp/adventure_box/weapon/spawn_gear(var/turf/T, var/mob/living/carbon/user)
+ var/choice = pick(
+ prob(3);/obj/random/multiple/gun/projectile/handgun,
+ prob(2);/obj/random/multiple/gun/projectile/smg,
+ prob(2);/obj/random/multiple/gun/projectile/shotgun,
+ prob(1);/obj/random/multiple/gun/projectile/rifle)
+ to_spawn = list(choice)
+ return ..()
+
+
+/obj/machinery/gear_dispenser/adventure_box/weapon
+ dispenses = list(
+ /datum/gear_disp/adventure_box/awayloot,
+ /datum/gear_disp/adventure_box/food,
+ /datum/gear_disp/adventure_box/medical,
+ /datum/gear_disp/adventure_box/tools,
+ /datum/gear_disp/adventure_box/armor,
+ /datum/gear_disp/adventure_box/light,
+ /datum/gear_disp/adventure_box/weapon
+ )
\ No newline at end of file
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index 0f57b816d06..5a63fd03beb 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -16,7 +16,7 @@
else
icon_state = ""
- overlays = null
+ cut_overlays()
if(beaker)
var/datum/reagents/reagents = beaker.reagents
@@ -34,7 +34,7 @@
if(91 to INFINITY) filling.icon_state = "reagent100"
filling.icon += reagents.get_color()
- overlays += filling
+ add_overlay(filling)
/obj/machinery/iv_drip/MouseDrop(over_object, src_location, over_location)
..()
diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm
index c8683e0d00c..06323a4f066 100644
--- a/code/game/machinery/jukebox.dm
+++ b/code/game/machinery/jukebox.dm
@@ -140,7 +140,7 @@
update_icon()
/obj/machinery/media/jukebox/update_icon()
- overlays.Cut()
+ cut_overlays()
if(stat & (NOPOWER|BROKEN) || !anchored)
if(stat & BROKEN)
icon_state = "[state_base]-broken"
@@ -150,11 +150,11 @@
icon_state = state_base
if(playing)
if(emagged)
- overlays += "[state_base]-emagged"
+ add_overlay("[state_base]-emagged")
else
- overlays += "[state_base]-running"
+ add_overlay("[state_base]-running")
if (panel_open)
- overlays += "panel_open"
+ add_overlay("panel_open")
/obj/machinery/media/jukebox/interact(mob/user)
if(inoperable())
diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm
index c078b854d0c..89bd996dea9 100644
--- a/code/game/machinery/lightswitch.dm
+++ b/code/game/machinery/lightswitch.dm
@@ -11,6 +11,7 @@
use_power = USE_POWER_IDLE
idle_power_usage = 10
power_channel = LIGHT
+ blocks_emissive = FALSE
var/on = 1
var/area/area = null
var/otherarea = null
@@ -36,19 +37,18 @@
return ..()
/obj/machinery/light_switch/proc/updateicon()
- if(!overlay)
- overlay = image(icon, "light1-overlay")
- overlay.plane = PLANE_LIGHTING_ABOVE
-
- overlays.Cut()
+ cut_overlays()
if(stat & NOPOWER)
icon_state = "light-p"
set_light(0)
else
icon_state = "light[on]"
- overlay.icon_state = "light[on]-overlay"
- overlays += overlay
set_light(2, 0.1, on ? "#82FF4C" : "#F86060")
+ . = list()
+ . += emissive_appearance(icon, "light[on]-overlay")
+
+ return add_overlay(.)
+
/obj/machinery/light_switch/examine(mob/user)
. = ..()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 47d26c7ab1c..1900811c8a2 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -114,6 +114,8 @@ Class Procs:
var/speed_process = FALSE //If false, SSmachines. If true, SSfastprocess.
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC
+
/obj/machinery/New(l, d=0)
..(l)
if(d)
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index df9547692e2..8cc0c56e5fe 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -186,21 +186,20 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
if(!ispowered || isbroken)
icon_state = "newscaster_off"
if(isbroken) //If the thing is smashed, add crack overlay on top of the unpowered sprite.
- overlays.Cut()
- overlays += image(icon, "crack3")
+ cut_overlays()
+ add_overlay("crack3")
return
- overlays.Cut() //reset overlays
-
+ cut_overlays() //reset overlays
if(news_network.wanted_issue) //wanted icon state, there can be no overlays on it as it's a priority message
icon_state = "newscaster_wanted"
return
if(alert) //new message alert overlay
- overlays += "newscaster_alert"
+ add_overlay("newscaster_alert")
if(hitstaken > 0) //Cosmetic damage overlay
- overlays += image(icon, "crack[hitstaken]")
+ add_overlay("crack[hitstaken]")
icon_state = "newscaster_normal"
return
diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm
index 8d6a55b3fd0..536da9fd0bd 100644
--- a/code/game/machinery/nuclear_bomb.dm
+++ b/code/game/machinery/nuclear_bomb.dm
@@ -61,19 +61,19 @@ var/bomb_set
if(auth)
if(opened == 0)
opened = 1
- overlays += image(icon, "npanel_open")
+ add_overlay("npanel_open")
to_chat(user, "You unscrew the control panel of [src].")
else
opened = 0
- overlays -= image(icon, "npanel_open")
+ cut_overlay("npanel_open")
to_chat(user, "You screw the control panel of [src] back on.")
else
if(opened == 0)
to_chat(user, "The [src] emits a buzzing noise, the panel staying locked in.")
if(opened == 1)
opened = 0
- overlays -= image(icon, "npanel_open")
+ cut_overlay("npanel_open")
to_chat(user, "You screw the control panel of [src] back on.")
flick("nuclearbombc", src)
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index d4068974ae3..6af917ad035 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -45,6 +45,7 @@
active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power
power_channel = EQUIP //drains power from the EQUIPMENT channel
req_one_access = list(access_security, access_heads)
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
var/raised = FALSE //if the turret cover is "open" and the turret is raised
var/raising= FALSE //if the turret is currently opening or closing its cover
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index 34d988e4837..cf2d4a978d5 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -197,20 +197,20 @@
desc += " It is capable of repairing burn damage."
/obj/machinery/recharge_station/proc/build_overlays()
- overlays.Cut()
+ cut_overlay()
switch(round(chargepercentage()))
if(1 to 20)
- overlays += image('icons/obj/objects.dmi', "statn_c0")
+ add_overlay("statn_c0")
if(21 to 40)
- overlays += image('icons/obj/objects.dmi', "statn_c20")
+ add_overlay("statn_c20")
if(41 to 60)
- overlays += image('icons/obj/objects.dmi', "statn_c40")
+ add_overlay("statn_c40")
if(61 to 80)
- overlays += image('icons/obj/objects.dmi', "statn_c60")
+ add_overlay("statn_c60")
if(81 to 98)
- overlays += image('icons/obj/objects.dmi', "statn_c80")
+ add_overlay("statn_c80")
if(99 to 110)
- overlays += image('icons/obj/objects.dmi', "statn_c100")
+ add_overlay("statn_c100")
/obj/machinery/recharge_station/update_icon()
..()
diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm
index 5bbb4ac6be0..109e17d6a16 100644
--- a/code/game/machinery/robot_fabricator.dm
+++ b/code/game/machinery/robot_fabricator.dm
@@ -16,7 +16,7 @@
var/obj/item/stack/M = O
if(metal_amount < 150000.0)
var/count = 0
- overlays += "fab-load-metal"
+ add_overlay("fab-load-metal")
spawn(15)
if(M)
if(!M.get_amount())
@@ -27,7 +27,7 @@
count++
to_chat(user, "You insert [count] metal sheet\s into the fabricator.")
- overlays -= "fab-load-metal"
+ cut_overlay("fab-load-metal")
updateDialog()
else
to_chat(user, "The robot part maker is full. Please remove metal from the robot part maker in order to insert more.")
@@ -121,7 +121,7 @@ Please wait until completion...
being_built = new building(src)
- overlays += "fab-active"
+ add_overlay("fab-active")
updateUsrDialog()
spawn (build_time)
@@ -130,7 +130,7 @@ Please wait until completion...
being_built = null
update_use_power(USE_POWER_IDLE)
operating = 0
- overlays -= "fab-active"
+ cut_overlay("fab-active")
return
for (var/mob/M in viewers(1, src))
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index 54aac0a5ffb..6497d8a2178 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -20,10 +20,10 @@
update_icon()
/obj/machinery/space_heater/update_icon()
- overlays.Cut()
+ cut_overlays()
icon_state = "sheater[on]"
if(panel_open)
- overlays += "sheater-open"
+ add_overlay("sheater-open")
if(on)
set_light(3, 3, "#FFCC00")
else
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index 949b8a4df6e..819774d0e30 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -198,7 +198,7 @@
if(!picture || picture_state != state)
picture_state = state
picture = image('icons/obj/status_display.dmi', icon_state=picture_state)
- overlays |= picture
+ add_overlay(picture)
/obj/machinery/status_display/proc/update_display(line1, line2)
var/new_text = {"
[line1] [line2]
"}
@@ -234,8 +234,7 @@
return ""
/obj/machinery/status_display/proc/remove_display()
- if(overlays.len)
- overlays.Cut()
+ cut_overlays()
if(maptext)
maptext = ""
diff --git a/code/game/machinery/status_display_ai.dm b/code/game/machinery/status_display_ai.dm
index 4a88b7248b7..4f8d9f89547 100644
--- a/code/game/machinery/status_display_ai.dm
+++ b/code/game/machinery/status_display_ai.dm
@@ -90,7 +90,7 @@ var/list/ai_status_emotions = list(
/obj/machinery/ai_status_display/proc/update()
if(mode==0) //Blank
- overlays.Cut()
+ cut_overlays()
return
if(mode==1) // AI emoticon
@@ -104,14 +104,12 @@ var/list/ai_status_emotions = list(
/obj/machinery/ai_status_display/proc/set_picture(var/state)
picture_state = state
- if(overlays.len)
- overlays.Cut()
- overlays += image('icons/obj/status_display.dmi', icon_state=picture_state)
+ cut_overlays()
+ add_overlay(picture_state)
/obj/machinery/ai_status_display/power_change()
..()
if(stat & NOPOWER)
- if(overlays.len)
- overlays.Cut()
+ cut_overlays()
else
update()
diff --git a/code/game/machinery/suit_storage_unit_vr.dm b/code/game/machinery/suit_storage_unit_vr.dm
index f373f20a9d7..3a7a9b5b8b3 100644
--- a/code/game/machinery/suit_storage_unit_vr.dm
+++ b/code/game/machinery/suit_storage_unit_vr.dm
@@ -6,7 +6,7 @@
/obj/machinery/suit_cycler/exploration
req_access = null
req_one_access = list(access_explorer,access_medical_equip)
- departments = list("Exploration","Expedition Medic","No Change")
+ departments = list("Exploration","Field Medic","No Change")
/obj/machinery/suit_cycler/pilot
req_access = list(access_pilot)
diff --git a/code/game/mecha/equipment/tools/shield.dm b/code/game/mecha/equipment/tools/shield.dm
index 497d670313a..8ee94b162e1 100644
--- a/code/game/mecha/equipment/tools/shield.dm
+++ b/code/game/mecha/equipment/tools/shield.dm
@@ -28,7 +28,7 @@
return
/obj/item/mecha_parts/mecha_equipment/combat_shield/Destroy()
- chassis.overlays -= drone_overlay
+ chassis.cut_overlay(drone_overlay)
my_shield.forceMove(src)
my_shield.destroy_shields()
my_shield.my_tool = null
@@ -41,7 +41,7 @@
..()
if(!drone_overlay)
drone_overlay = new(src.icon, icon_state = "shield_droid")
- M.overlays += drone_overlay
+ M.add_overlay(drone_overlay)
return
/obj/item/mecha_parts/mecha_equipment/combat_shield/attach(obj/mecha/M as obj)
@@ -53,7 +53,7 @@
return
/obj/item/mecha_parts/mecha_equipment/combat_shield/detach()
- chassis.overlays -= drone_overlay
+ chassis.cut_overlay(drone_overlay)
..()
my_shield.destroy_shields()
my_shield.my_mecha = null
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 4a3a105e9af..92215b3963b 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -630,9 +630,9 @@
flick("[loading_icon_state]", src)
// yess hacky but whatever
if(loading_icon_state == "mechfab-idle")
- overlays += "mechfab-load-metal"
+ add_overlay("mechfab-load-metal")
spawn(10)
- overlays -= "mechfab-load-metal"
+ cut_overlays("mechfab-load-metal")
while(materials[S.material.name] + amnt <= res_max_amount && S.get_amount() >= 1)
materials[S.material.name] += amnt
S.use(1)
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index e345013e3d1..467145309bc 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -79,7 +79,7 @@
/datum/construction/mecha/ripley_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
@@ -291,7 +291,7 @@
/datum/construction/mecha/gygax_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
@@ -575,7 +575,7 @@
/datum/construction/mecha/serenity_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
@@ -860,7 +860,7 @@
/datum/construction/mecha/firefighter_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
user.drop_item()
qdel(I)
return 1
@@ -1085,7 +1085,7 @@
/datum/construction/mecha/durand_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
@@ -1369,7 +1369,7 @@
/datum/construction/mecha/odysseus_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
@@ -1582,7 +1582,7 @@
/datum/construction/mecha/phazon_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
@@ -1864,7 +1864,7 @@
/datum/construction/mecha/janus_chassis/custom_action(step, obj/item/I, mob/user)
user.visible_message("[user] has connected [I] to [holder].", "You connect [I] to [holder]")
- holder.overlays += I.icon_state+"+o"
+ holder.add_overlay(I.icon_state+"+o")
qdel(I)
return 1
diff --git a/code/game/mecha/micro/mecha_construction_paths_vr.dm b/code/game/mecha/micro/mecha_construction_paths_vr.dm
index a63322b5a39..637a5ab36c3 100644
--- a/code/game/mecha/micro/mecha_construction_paths_vr.dm
+++ b/code/game/mecha/micro/mecha_construction_paths_vr.dm
@@ -9,7 +9,7 @@
custom_action(step, atom/used_atom, mob/user)
user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]")
- holder.overlays += used_atom.icon_state+"+o"
+ holder.add_overlay(used_atom.icon_state+"+o")
qdel(used_atom)
return 1
@@ -289,7 +289,7 @@
custom_action(step, atom/used_atom, mob/user)
user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]")
- holder.overlays += used_atom.icon_state+"+o"
+ holder.add_overlay(used_atom.icon_state+"+o")
qdel(used_atom)
return 1
@@ -497,7 +497,7 @@
custom_action(step, atom/used_atom, mob/user)
user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]")
- holder.overlays += used_atom.icon_state+"+o"
+ holder.add_overlay(used_atom.icon_state+"+o")
qdel(used_atom)
return 1
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index 4e92f757d27..ce54008c451 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -27,6 +27,19 @@
icon_scale_x = 1.2
icon_scale_y = 1.2
+/obj/mecha/working/ripley/Move()
+ . = ..()
+ if(.)
+ collect_ore()
+
+/obj/mecha/working/ripley/proc/collect_ore()
+ if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in equipment)
+ var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in cargo
+ if(ore_box)
+ for(var/obj/item/weapon/ore/ore in range(1, src))
+ if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) //we can reach it and it's in front of us? grab it!
+ ore.forceMove(ore_box)
+
/obj/mecha/working/ripley/Destroy()
for(var/atom/movable/A in src.cargo)
A.loc = loc
diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm
index 836e277872f..91aea937fff 100644
--- a/code/game/objects/effects/alien/aliens.dm
+++ b/code/game/objects/effects/alien/aliens.dm
@@ -203,6 +203,7 @@
desc = "Weird glowing organic growth."
layer = ABOVE_TURF_LAYER+0.01
light_range = NODERANGE
+ light_on = TRUE
var/node_range = NODERANGE
var/set_color = "#321D37"
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index 2a37edf7088..c9ae326bf2f 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -87,10 +87,10 @@ var/global/list/image/splatter_cache=list()
if(!S.blood_DNA)
S.blood_DNA = list()
S.blood_overlay.color = basecolor
- S.overlays += S.blood_overlay
+ S.add_overlay(S.blood_overlay)
if(S.blood_overlay && S.blood_overlay.color != basecolor)
S.blood_overlay.color = basecolor
- S.overlays += S.blood_overlay
+ S.add_overlay(S.blood_overlay)
S.blood_DNA |= blood_DNA.Copy()
perp.update_inv_shoes()
@@ -191,8 +191,8 @@ var/global/list/image/splatter_cache=list()
blood.Blend(basecolor,ICON_MULTIPLY)
icon = blood
- overlays.Cut()
- overlays += giblets
+ cut_overlays()
+ add_overlay(giblets)
/obj/effect/decal/cleanable/blood/gibs/up
random_icon_states = list("gib1", "gib2", "gib3", "gib5", "gib6","gibup1","gibup1","gibup1")
diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm
index 934068f25bb..a650980779d 100644
--- a/code/game/objects/effects/decals/Cleanable/tracks.dm
+++ b/code/game/objects/effects/decals/Cleanable/tracks.dm
@@ -129,7 +129,7 @@ var/global/list/image/fluidtrack_cache=list()
update_icon()
update_icon()
- overlays.Cut()
+ cut_overlays()
color = "#FFFFFF"
var/truedir=0
@@ -150,7 +150,7 @@ var/global/list/image/fluidtrack_cache=list()
track.fresh=0
track.overlay=I
stack[stack_idx]=track
- overlays += I
+ add_overlay(I)
updatedtracks=0 // Clear our memory of updated tracks.
/obj/effect/decal/cleanable/blood/tracks/footprints
diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm
index 55bb54b8036..8ae1fd4bb0a 100644
--- a/code/game/objects/effects/decals/crayon.dm
+++ b/code/game/objects/effects/decals/crayon.dm
@@ -24,7 +24,7 @@
mainOverlay.Blend(main,ICON_ADD)
shadeOverlay.Blend(shade,ICON_ADD)
- overlays += mainOverlay
- overlays += shadeOverlay
+ add_overlay(mainOverlay)
+ add_overlay(shadeOverlay)
add_hiddenprint(usr)
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm
index 0e3d12897d8..e69c90a8d84 100644
--- a/code/game/objects/effects/decals/warning_stripes.dm
+++ b/code/game/objects/effects/decals/warning_stripes.dm
@@ -6,5 +6,5 @@
var/turf/T=get_turf(src)
var/image/I=image(icon, icon_state = icon_state, dir = dir)
I.color=color
- T.overlays += I
+ T.add_overlay(I)
return INITIALIZE_HINT_QDEL
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index 7033648deaa..f18eb727ebf 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -4,7 +4,8 @@ defined, then set up when it is created with New(). Then this same system can ju
it needs to create more trails.A beaker could have a steam_trail_follow system set up, then the steam
would spawn and follow the beaker, even if it is carried or thrown.
*/
-
+/obj/effect
+ light_on = TRUE
/obj/effect/effect
name = "effect"
@@ -12,6 +13,8 @@ would spawn and follow the beaker, even if it is carried or thrown.
mouse_opacity = 0
unacidable = 1//So effect are not targeted by alien acid.
pass_flags = PASSTABLE | PASSGRILLE
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC
+ light_on = TRUE
/datum/effect/effect/system
var/number = 3
diff --git a/code/game/objects/effects/map_effects/perma_light.dm b/code/game/objects/effects/map_effects/perma_light.dm
index a48e768fc70..35eef6d6b0b 100644
--- a/code/game/objects/effects/map_effects/perma_light.dm
+++ b/code/game/objects/effects/map_effects/perma_light.dm
@@ -7,6 +7,7 @@
light_range = 3
light_power = 1
light_color = "#FFFFFF"
+ light_on = TRUE
/obj/effect/map_effect/perma_light/brighter
name = "permanent light (bright)"
@@ -25,4 +26,14 @@
/obj/effect/map_effect/perma_light/concentrated/incandescent
name = "permanent light (concentrated incandescent)"
- light_color = LIGHT_COLOR_INCANDESCENT_TUBE
\ No newline at end of file
+ light_color = LIGHT_COLOR_INCANDESCENT_TUBE
+
+// VOREStation Addition Start
+/obj/effect/map_effect/perma_light/gateway
+ name = "permanent light (gateway)"
+ icon_state = "permalight"
+
+ light_range = 10
+ light_power = 5
+ light_color = "#b6cdff"
+// VOREStation Addition End
\ No newline at end of file
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index 5958f79d002..aac5b6ffa0e 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -61,4 +61,42 @@
/obj/effect/temporary_effect/lightning_strike/Initialize()
icon_state += "[rand(1,2)]" // To have two variants of lightning sprites.
animate(src, alpha = 0, time = time_to_die - 1)
- . = ..()
\ No newline at end of file
+ . = ..()
+
+/obj/effect/dummy/lighting_obj
+ name = "lighting fx obj"
+ desc = "Tell a coder if you're seeing this."
+ icon_state = "nothing"
+ light_system = MOVABLE_LIGHT
+ light_range = MINIMUM_USEFUL_LIGHT_RANGE
+ light_color = COLOR_WHITE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ light_on = TRUE
+ blocks_emissive = FALSE
+
+/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration)
+ . = ..()
+ if(!isnull(_range))
+ set_light_range(_range)
+ if(!isnull(_power))
+ set_light_power(_power)
+ if(!isnull(_color))
+ set_light_color(_color)
+ if(_duration)
+ QDEL_IN(src, _duration)
+
+/obj/effect/dummy/lighting_obj/moblight
+ name = "mob lighting fx"
+
+/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, _color, _range, _power, _duration)
+ . = ..()
+ if(!ismob(loc))
+ return INITIALIZE_HINT_QDEL
+
+/obj/effect/dummy/lighting_obj/moblight/fire
+ name = "fire"
+ light_color = LIGHT_COLOR_FIRE
+ light_range = LIGHT_RANGE_FIRE
+
+/obj/effect/abstract/directional_lighting
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 6c8a04143b0..3657e34604e 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -109,3 +109,48 @@
plane = PLANE_LIGHTING_ABOVE
pixel_x = -32
pixel_y = -32
+
+/obj/effect/overlay/vis
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ anchored = TRUE
+ vis_flags = VIS_INHERIT_DIR
+ ///When detected to be unused it gets set to world.time, after a while it gets removed
+ var/unused = 0
+ ///overlays which go unused for this amount of time get cleaned up
+ var/cache_expiration = 2 MINUTES
+
+/*
+/obj/effect/overlay/atmos_excited
+ name = "excited group"
+ icon = null
+ icon_state = null
+ anchored = TRUE // should only appear in vis_contents, but to be safe
+ appearance_flags = RESET_TRANSFORM | TILE_BOUND
+ invisibility = INVISIBILITY_ABSTRACT
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+
+ plane = ATMOS_GROUP_PLANE
+*/
+
+/obj/effect/overlay/light_visible
+ name = ""
+ icon = 'icons/effects/light_overlays/light_32.dmi'
+ icon_state = "light"
+ plane = PLANE_O_LIGHTING_VISUAL
+ appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ alpha = 0
+ vis_flags = NONE
+ blocks_emissive = FALSE
+
+/obj/effect/overlay/light_cone
+ name = ""
+ icon = 'icons/effects/light_overlays/light_cone.dmi'
+ icon_state = "light"
+ plane = PLANE_O_LIGHTING_VISUAL
+ appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ vis_flags = NONE
+ alpha = 110
+ blocks_emissive = FALSE
+
\ No newline at end of file
diff --git a/code/game/objects/effects/semirandom_mobs_vr.dm b/code/game/objects/effects/semirandom_mobs_vr.dm
new file mode 100644
index 00000000000..ae5230f9760
--- /dev/null
+++ b/code/game/objects/effects/semirandom_mobs_vr.dm
@@ -0,0 +1,1039 @@
+var/global/list/semirandom_mob_spawner_decisions = list()
+
+/obj/random/mob/semirandom_mob_spawner
+ name = "Semi-Random Spawner"
+ desc = "Spawns groups of mobs that are all of the same theme type/theme."
+ icon = 'icons/mob/randomlandmarks.dmi'
+ icon_state = "monster"
+ mob_returns_home = 1
+ mob_wander_distance = 7
+
+ var/list/possible_mob_types = list(
+ list(/mob/living/simple_mob/animal/goat),
+ list(
+ /mob/living/simple_mob/animal/passive/bird,
+ /mob/living/simple_mob/animal/passive/bird/azure_tit,
+ /mob/living/simple_mob/animal/passive/bird/black_bird,
+ /mob/living/simple_mob/animal/passive/bird/european_robin,
+ /mob/living/simple_mob/animal/passive/bird/goldcrest,
+ /mob/living/simple_mob/animal/passive/bird/ringneck_dove,
+ /mob/living/simple_mob/animal/passive/bird/parrot,
+ /mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique,
+ /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar,
+ /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue,
+ /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish,
+ /mob/living/simple_mob/animal/passive/bird/parrot/eclectus,
+ /mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot,
+ /mob/living/simple_mob/animal/passive/bird/parrot/kea,
+ /mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo,
+ /mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo,
+ /mob/living/simple_mob/animal/passive/bird/parrot/white_caique,
+ /mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo
+ ),
+ list(
+ /mob/living/simple_mob/animal/passive/cat,
+ /mob/living/simple_mob/animal/passive/cat/black
+ ),
+ list(/mob/living/simple_mob/animal/passive/chick),
+ list(/mob/living/simple_mob/animal/passive/cow),
+ list(/mob/living/simple_mob/animal/passive/dog/brittany),
+ list(/mob/living/simple_mob/animal/passive/dog/corgi),
+ list(/mob/living/simple_mob/animal/passive/dog/tamaskan),
+ list(/mob/living/simple_mob/animal/passive/fox),
+ list(/mob/living/simple_mob/animal/passive/hare),
+ list(/mob/living/simple_mob/animal/passive/lizard),
+ list(/mob/living/simple_mob/animal/passive/mouse),
+ list(/mob/living/simple_mob/animal/passive/mouse/jerboa),
+ list(/mob/living/simple_mob/animal/passive/opossum),
+ list(/mob/living/simple_mob/animal/passive/pillbug),
+ list(/mob/living/simple_mob/animal/passive/snake),
+ list(/mob/living/simple_mob/animal/passive/tindalos),
+ list(/mob/living/simple_mob/animal/passive/yithian),
+ list(
+ /mob/living/simple_mob/animal/wolf = 10,
+ /mob/living/simple_mob/animal/wolf/direwolf = 1
+ ),
+ list(/mob/living/simple_mob/vore/rabbit),
+ list(/mob/living/simple_mob/vore/redpanda),
+ list(/mob/living/simple_mob/vore/woof),
+ list(/mob/living/simple_mob/vore/fennec),
+ list(/mob/living/simple_mob/vore/fennix),
+ list(/mob/living/simple_mob/vore/hippo),
+ list(/mob/living/simple_mob/vore/horse),
+ list(/mob/living/simple_mob/vore/bee),
+ list(
+ /mob/living/simple_mob/animal/space/bear,
+ /mob/living/simple_mob/animal/space/bear/brown
+ ),
+ list(
+ /mob/living/simple_mob/otie/feral,
+ /mob/living/simple_mob/otie/feral/chubby,
+ /mob/living/simple_mob/otie/red,
+ /mob/living/simple_mob/otie/red/chubby
+ ),
+ list(/mob/living/simple_mob/animal/sif/diyaab),
+ list(/mob/living/simple_mob/animal/sif/duck),
+ list(/mob/living/simple_mob/animal/sif/frostfly),
+ list(
+ /mob/living/simple_mob/animal/sif/glitterfly =50,
+ /mob/living/simple_mob/animal/sif/glitterfly/rare = 1
+ ),
+ list(
+ /mob/living/simple_mob/animal/sif/kururak = 10,
+ /mob/living/simple_mob/animal/sif/kururak/leader = 1,
+ /mob/living/simple_mob/animal/sif/kururak/hibernate = 2,
+ ),
+ list(
+ /mob/living/simple_mob/animal/sif/sakimm = 10,
+ /mob/living/simple_mob/animal/sif/sakimm/intelligent = 1
+ ),
+ list(/mob/living/simple_mob/animal/sif/savik) = 5,
+ list(
+ /mob/living/simple_mob/animal/sif/shantak = 10,
+ /mob/living/simple_mob/animal/sif/shantak/leader = 1
+ ),
+ list(/mob/living/simple_mob/animal/sif/siffet),
+ list(/mob/living/simple_mob/animal/sif/tymisian),
+ list(
+ /mob/living/simple_mob/animal/giant_spider/nurse = 10,
+ /mob/living/simple_mob/animal/giant_spider/electric = 5,
+ /mob/living/simple_mob/animal/giant_spider/frost = 5,
+ /mob/living/simple_mob/animal/giant_spider/hunter = 10,
+ /mob/living/simple_mob/animal/giant_spider/ion = 5,
+ /mob/living/simple_mob/animal/giant_spider/lurker = 10,
+ /mob/living/simple_mob/animal/giant_spider/pepper = 10,
+ /mob/living/simple_mob/animal/giant_spider/phorogenic = 10,
+ /mob/living/simple_mob/animal/giant_spider/thermic = 5,
+ /mob/living/simple_mob/animal/giant_spider/tunneler = 10,
+ /mob/living/simple_mob/animal/giant_spider/webslinger = 5
+ ),
+ list(
+ /mob/living/simple_mob/animal/wolf = 10,
+ /mob/living/simple_mob/animal/wolf/direwolf = 1
+ ),
+ list(/mob/living/simple_mob/creature/strong),
+ list(/mob/living/simple_mob/faithless/strong),
+ list(/mob/living/simple_mob/animal/goat),
+ list(
+ /mob/living/simple_mob/animal/sif/shantak/leader = 1,
+ /mob/living/simple_mob/animal/sif/shantak = 10),
+ list(/mob/living/simple_mob/animal/sif/savik,),
+ list(/mob/living/simple_mob/animal/sif/hooligan_crab),
+ list(
+ /mob/living/simple_mob/animal/space/alien = 50,
+ /mob/living/simple_mob/animal/space/alien/drone = 40,
+ /mob/living/simple_mob/animal/space/alien/sentinel = 25,
+ /mob/living/simple_mob/animal/space/alien/sentinel/praetorian = 15,
+ /mob/living/simple_mob/animal/space/alien/queen = 10,
+ /mob/living/simple_mob/animal/space/alien/queen/empress = 5,
+ /mob/living/simple_mob/animal/space/alien/queen/empress/mother = 1
+ ),
+ list(/mob/living/simple_mob/animal/space/bats/cult/strong),
+ list(
+ /mob/living/simple_mob/animal/space/bear,
+ /mob/living/simple_mob/animal/space/bear/brown
+ ),
+ list(
+ /mob/living/simple_mob/animal/space/carp = 50,
+ /mob/living/simple_mob/animal/space/carp/large = 10,
+ /mob/living/simple_mob/animal/space/carp/large/huge = 5
+ ),
+ list(/mob/living/simple_mob/animal/space/goose),
+ list(/mob/living/simple_mob/animal/space/jelly),
+ list(/mob/living/simple_mob/animal/space/tree),
+ list(
+ /mob/living/simple_mob/vore/aggressive/corrupthound = 10,
+ /mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi = 1,
+ ),
+ list(/mob/living/simple_mob/vore/aggressive/deathclaw),
+ list(/mob/living/simple_mob/vore/aggressive/dino),
+ list(/mob/living/simple_mob/vore/aggressive/dragon),
+ list(/mob/living/simple_mob/vore/aggressive/dragon/virgo3b),
+ list(/mob/living/simple_mob/vore/aggressive/frog),
+ list(/mob/living/simple_mob/vore/aggressive/giant_snake),
+ list(/mob/living/simple_mob/vore/aggressive/mimic),
+ list(/mob/living/simple_mob/vore/aggressive/panther),
+ list(/mob/living/simple_mob/vore/aggressive/rat),
+ list(/mob/living/simple_mob/vore/bee),
+ list(
+ /mob/living/simple_mob/vore/sect_drone = 10,
+ /mob/living/simple_mob/vore/sect_queen = 1
+ ),
+ list(/mob/living/simple_mob/vore/solargrub),
+ list(
+ /mob/living/simple_mob/vore/oregrub = 5,
+ /mob/living/simple_mob/vore/oregrub/lava = 1
+ ),
+ list(/mob/living/simple_mob/vore/catgirl),
+ list(/mob/living/simple_mob/vore/wolfgirl),
+ list(
+ /mob/living/simple_mob/vore/lamia,
+ /mob/living/simple_mob/vore/lamia/albino,
+ /mob/living/simple_mob/vore/lamia/albino/bra,
+ /mob/living/simple_mob/vore/lamia/albino/shirt,
+ /mob/living/simple_mob/vore/lamia/bra,
+ /mob/living/simple_mob/vore/lamia/cobra,
+ /mob/living/simple_mob/vore/lamia/cobra/bra,
+ /mob/living/simple_mob/vore/lamia/cobra/shirt,
+ /mob/living/simple_mob/vore/lamia/copper,
+ /mob/living/simple_mob/vore/lamia/copper/bra,
+ /mob/living/simple_mob/vore/lamia/copper/shirt,
+ /mob/living/simple_mob/vore/lamia/green,
+ /mob/living/simple_mob/vore/lamia/green/bra,
+ /mob/living/simple_mob/vore/lamia/green/shirt,
+ /mob/living/simple_mob/vore/lamia/zebra,
+ /mob/living/simple_mob/vore/lamia/zebra/bra,
+ /mob/living/simple_mob/vore/lamia/zebra/shirt
+ ),
+ list(
+ /mob/living/simple_mob/humanoid/merc = 100,
+ /mob/living/simple_mob/humanoid/merc/melee/sword = 50,
+ /mob/living/simple_mob/humanoid/merc/ranged = 25,
+ /mob/living/simple_mob/humanoid/merc/ranged/grenadier = 1,
+ /mob/living/simple_mob/humanoid/merc/ranged/ionrifle = 10,
+ /mob/living/simple_mob/humanoid/merc/ranged/laser = 5,
+ /mob/living/simple_mob/humanoid/merc/ranged/rifle = 5,
+ /mob/living/simple_mob/humanoid/merc/ranged/smg = 5,
+ /mob/living/simple_mob/humanoid/merc/ranged/sniper = 1,
+ /mob/living/simple_mob/humanoid/merc/ranged/space = 10,
+ /mob/living/simple_mob/humanoid/merc/ranged/technician = 5
+ ),
+ list(
+ /mob/living/simple_mob/humanoid/pirate = 3,
+ /mob/living/simple_mob/humanoid/pirate/ranged = 1
+ ),
+ list(/mob/living/simple_mob/mechanical/combat_drone),
+ list(/mob/living/simple_mob/mechanical/corrupt_maint_drone),
+ list(
+ /mob/living/simple_mob/mechanical/hivebot = 100,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage = 20,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/backline = 10,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/basic = 20,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/dot = 5,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/ion = 20,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/laser = 10,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/rapid = 2,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege = 1,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege/emp = 5,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege/fragmentation = 1,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege/radiation = 1,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong = 3,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong/guard = 3,
+ /mob/living/simple_mob/mechanical/hivebot/support = 8,
+ /mob/living/simple_mob/mechanical/hivebot/support/commander = 5,
+ /mob/living/simple_mob/mechanical/hivebot/support/commander/autofollow = 10,
+ /mob/living/simple_mob/mechanical/hivebot/swarm = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored/anti_bullet = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored/anti_laser = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored/anti_melee = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/meatshield = 20
+ ),
+ list(/mob/living/simple_mob/mechanical/infectionbot),
+ list(/mob/living/simple_mob/mechanical/mining_drone),
+ list(/mob/living/simple_mob/mechanical/technomancer_golem),
+ list(
+ /mob/living/simple_mob/mechanical/viscerator,
+ /mob/living/simple_mob/mechanical/viscerator/piercing
+ ),
+ list(/mob/living/simple_mob/mechanical/wahlem),
+ list(/mob/living/simple_mob/animal/passive/fox/syndicate),
+ list(/mob/living/simple_mob/animal/passive/fox),
+ list(/mob/living/simple_mob/animal/wolf/direwolf),
+ list(/mob/living/simple_mob/animal/space/jelly),
+ list(
+ /mob/living/simple_mob/otie/feral,
+ /mob/living/simple_mob/otie/feral/chubby,
+ /mob/living/simple_mob/otie/red,
+ /mob/living/simple_mob/otie/red/chubby
+ ),
+ list(
+ /mob/living/simple_mob/shadekin/blue/ai = 100,
+ /mob/living/simple_mob/shadekin/green/ai = 50,
+ /mob/living/simple_mob/shadekin/orange/ai = 20,
+ /mob/living/simple_mob/shadekin/purple/ai = 60,
+ /mob/living/simple_mob/shadekin/red/ai = 40,
+ /mob/living/simple_mob/shadekin/yellow/ai = 1
+ ),
+ list(
+ /mob/living/simple_mob/vore/aggressive/corrupthound,
+ /mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi
+ ),
+ list(/mob/living/simple_mob/vore/aggressive/deathclaw),
+ list(/mob/living/simple_mob/vore/aggressive/dino),
+ list(/mob/living/simple_mob/vore/aggressive/dragon),
+ list(/mob/living/simple_mob/vore/aggressive/dragon/virgo3b),
+ list(/mob/living/simple_mob/vore/aggressive/frog),
+ list(/mob/living/simple_mob/vore/aggressive/giant_snake),
+ list(/mob/living/simple_mob/vore/aggressive/mimic),
+ list(/mob/living/simple_mob/vore/aggressive/panther),
+ list(/mob/living/simple_mob/vore/aggressive/rat),
+ list(/mob/living/simple_mob/vore/bee),
+ list(/mob/living/simple_mob/vore/catgirl),
+ list(/mob/living/simple_mob/vore/cookiegirl),
+ list(/mob/living/simple_mob/vore/fennec),
+ list(/mob/living/simple_mob/vore/fennix),
+ list(/mob/living/simple_mob/vore/hippo),
+ list(/mob/living/simple_mob/vore/horse),
+ list(/mob/living/simple_mob/vore/oregrub),
+ list(/mob/living/simple_mob/vore/rabbit),
+ list(
+ /mob/living/simple_mob/vore/redpanda = 50,
+ /mob/living/simple_mob/vore/redpanda/fae = 1
+ ),
+ list(
+ /mob/living/simple_mob/vore/sect_drone = 10,
+ /mob/living/simple_mob/vore/sect_queen = 1
+ ),
+ list(/mob/living/simple_mob/vore/solargrub),
+ list(/mob/living/simple_mob/vore/woof)
+ )
+
+/obj/random/mob/semirandom_mob_spawner/item_to_spawn()
+ var/list/choice = semirandom_mob_spawner_decisions[type]
+
+ if(!choice)
+ choice = pickweight(possible_mob_types)
+ semirandom_mob_spawner_decisions[type] = choice
+
+ return pickweight(choice)
+
+/obj/random/mob/semirandom_mob_spawner/animal
+ name = "Semi-Random Animal"
+ desc = "Spawns groups of non-hostile mobs that are all of the same theme type/theme."
+ icon_state = "animal"
+ mob_faction = "animal"
+ overwrite_hostility = 1
+ mob_hostile = 0
+
+ possible_mob_types = list(
+ list(/mob/living/simple_mob/animal/goat) = 25,
+ list(
+ /mob/living/simple_mob/animal/passive/bird,
+ /mob/living/simple_mob/animal/passive/bird/azure_tit,
+ /mob/living/simple_mob/animal/passive/bird/black_bird,
+ /mob/living/simple_mob/animal/passive/bird/european_robin,
+ /mob/living/simple_mob/animal/passive/bird/goldcrest,
+ /mob/living/simple_mob/animal/passive/bird/ringneck_dove,
+ /mob/living/simple_mob/animal/passive/bird/parrot,
+ /mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique,
+ /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar,
+ /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue,
+ /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white,
+ /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish,
+ /mob/living/simple_mob/animal/passive/bird/parrot/eclectus,
+ /mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot,
+ /mob/living/simple_mob/animal/passive/bird/parrot/kea,
+ /mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo,
+ /mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo,
+ /mob/living/simple_mob/animal/passive/bird/parrot/white_caique,
+ /mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo,
+ /mob/living/simple_mob/animal/space/goose
+ ) = 25,
+ list(
+ /mob/living/simple_mob/animal/passive/cat,
+ /mob/living/simple_mob/animal/passive/cat/black
+ ) = 25,
+ list(
+ /mob/living/simple_mob/animal/passive/chick,
+ /mob/living/simple_mob/animal/passive/chicken
+ ) = 25,
+ list(/mob/living/simple_mob/animal/passive/cow) = 25,
+ list(/mob/living/simple_mob/animal/passive/dog/brittany) = 10,
+ list(/mob/living/simple_mob/animal/passive/dog/corgi) = 10,
+ list(/mob/living/simple_mob/animal/passive/dog/tamaskan) = 10,
+ list(/mob/living/simple_mob/animal/passive/fox) = 25,
+ list(/mob/living/simple_mob/animal/passive/hare) = 25,
+ list(/mob/living/simple_mob/animal/passive/lizard) = 10,
+ list(/mob/living/simple_mob/animal/passive/mouse) = 15,
+ list(/mob/living/simple_mob/animal/passive/mouse/jerboa) = 5,
+ list(/mob/living/simple_mob/animal/passive/opossum) = 10,
+ list(/mob/living/simple_mob/animal/passive/pillbug) = 10,
+ list(/mob/living/simple_mob/animal/passive/snake) = 10,
+ list(/mob/living/simple_mob/animal/passive/tindalos) = 10,
+ list(/mob/living/simple_mob/animal/passive/yithian) = 10,
+ list(
+ /mob/living/simple_mob/animal/wolf = 10,
+ /mob/living/simple_mob/animal/wolf/direwolf = 1
+ ) = 10,
+ list(/mob/living/simple_mob/vore/rabbit) = 10,
+ list(/mob/living/simple_mob/vore/redpanda) = 10,
+ list(/mob/living/simple_mob/vore/woof) = 1,
+ list(/mob/living/simple_mob/vore/fennec) = 10,
+ list(/mob/living/simple_mob/vore/fennix) = 1,
+ list(/mob/living/simple_mob/vore/hippo) = 5,
+ list(/mob/living/simple_mob/vore/horse) = 25,
+ list(/mob/living/simple_mob/vore/bee) = 10,
+ list(
+ /mob/living/simple_mob/animal/space/bear,
+ /mob/living/simple_mob/animal/space/bear/brown
+ ) = 1,
+ list(
+ /mob/living/simple_mob/otie/feral = 50,
+ /mob/living/simple_mob/otie/feral/chubby = 10,
+ /mob/living/simple_mob/otie/red = 5,
+ /mob/living/simple_mob/otie/red/chubby = 1
+ ) = 5,
+ list(/mob/living/simple_mob/vore/aggressive/rat) = 15,
+ list(/mob/living/simple_mob/animal/sif/diyaab) = 5,
+ list(/mob/living/simple_mob/animal/sif/duck) = 5,
+ list(/mob/living/simple_mob/animal/sif/frostfly) = 5,
+ list(
+ /mob/living/simple_mob/animal/sif/glitterfly = 50,
+ /mob/living/simple_mob/animal/sif/glitterfly/rare = 1
+ ) = 5,
+ list(
+ /mob/living/simple_mob/animal/sif/kururak = 10,
+ /mob/living/simple_mob/animal/sif/kururak/leader = 1,
+ /mob/living/simple_mob/animal/sif/kururak/hibernate = 2,
+ ) = 5,
+ list(
+ /mob/living/simple_mob/animal/sif/sakimm = 10,
+ /mob/living/simple_mob/animal/sif/sakimm/intelligent = 1
+ ) = 5,
+ list(/mob/living/simple_mob/animal/sif/savik) = 5,
+ list(
+ /mob/living/simple_mob/animal/sif/shantak = 10,
+ /mob/living/simple_mob/animal/sif/shantak/leader = 1
+ ) = 5,
+ list(/mob/living/simple_mob/animal/sif/siffet) = 5,
+ list(/mob/living/simple_mob/animal/sif/tymisian) = 5
+
+ )
+
+/obj/random/mob/semirandom_mob_spawner/monster
+ name = "Semi-Random Monster"
+ desc = "Spawns groups of hostile mobs that are all of the same theme type/theme."
+ overwrite_hostility = 1
+ mob_faction = "monster"
+ mob_hostile = 1
+ mob_retaliate = 1
+
+ possible_mob_types = list(
+ list(
+ /mob/living/simple_mob/animal/giant_spider/nurse = 10,
+ /mob/living/simple_mob/animal/giant_spider/electric = 5,
+ /mob/living/simple_mob/animal/giant_spider/frost = 5,
+ /mob/living/simple_mob/animal/giant_spider/hunter = 10,
+ /mob/living/simple_mob/animal/giant_spider/ion = 5,
+ /mob/living/simple_mob/animal/giant_spider/lurker = 10,
+ /mob/living/simple_mob/animal/giant_spider/pepper = 10,
+ /mob/living/simple_mob/animal/giant_spider/phorogenic = 10,
+ /mob/living/simple_mob/animal/giant_spider/thermic = 5,
+ /mob/living/simple_mob/animal/giant_spider/tunneler = 10,
+ /mob/living/simple_mob/animal/giant_spider/webslinger = 5
+ ) = 100,
+ list(
+ /mob/living/simple_mob/shadekin/red/ai = 5,
+ /mob/living/simple_mob/shadekin/orange/ai = 1,
+ /mob/living/simple_mob/shadekin/purple/ai = 10
+ ) = 1,
+ list(
+ /mob/living/simple_mob/animal/wolf = 10,
+ /mob/living/simple_mob/animal/wolf/direwolf = 1,
+ ) = 80,
+ list(/mob/living/simple_mob/creature/strong) = 40,
+ list(/mob/living/simple_mob/faithless/strong) = 20,
+ list(/mob/living/simple_mob/animal/goat) = 1,
+ list(
+ /mob/living/simple_mob/animal/sif/shantak/leader = 1,
+ /mob/living/simple_mob/animal/sif/shantak = 10
+ ) = 50,
+ list(/mob/living/simple_mob/animal/sif/savik,) = 20,
+ list(/mob/living/simple_mob/animal/sif/hooligan_crab) = 10,
+ list(
+ /mob/living/simple_mob/animal/space/alien = 50,
+ /mob/living/simple_mob/animal/space/alien/drone = 40,
+ /mob/living/simple_mob/animal/space/alien/sentinel = 25,
+ /mob/living/simple_mob/animal/space/alien/sentinel/praetorian = 15,
+ /mob/living/simple_mob/animal/space/alien/queen = 10,
+ /mob/living/simple_mob/animal/space/alien/queen/empress = 5,
+ /mob/living/simple_mob/animal/space/alien/queen/empress/mother = 1,
+ ) = 40,
+ list(/mob/living/simple_mob/animal/space/bats/cult/strong) = 40,
+ list(
+ /mob/living/simple_mob/animal/space/bear,
+ /mob/living/simple_mob/animal/space/bear/brown
+ ) = 40,
+ list(
+ /mob/living/simple_mob/animal/space/carp = 50,
+ /mob/living/simple_mob/animal/space/carp/large = 10,
+ /mob/living/simple_mob/animal/space/carp/large/huge = 5
+ ) = 50,
+ list(/mob/living/simple_mob/animal/space/goose) = 50,
+ list(/mob/living/simple_mob/animal/space/jelly) = 40,
+ list(/mob/living/simple_mob/animal/space/tree) = 15,
+ list(
+ /mob/living/simple_mob/otie/feral = 50,
+ /mob/living/simple_mob/otie/feral/chubby = 10,
+ /mob/living/simple_mob/otie/red = 5,
+ /mob/living/simple_mob/otie/red/chubby = 1
+ ) = 40,
+ list(
+ /mob/living/simple_mob/vore/aggressive/corrupthound = 10,
+ /mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi = 1,
+ ) = 50,
+ list(/mob/living/simple_mob/vore/aggressive/deathclaw) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/dino) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/dragon) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/dragon/virgo3b) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/frog) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/giant_snake) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/mimic) = 40,
+ list(/mob/living/simple_mob/vore/aggressive/panther) = 25,
+ list(/mob/living/simple_mob/vore/aggressive/rat) = 50,
+ list(/mob/living/simple_mob/vore/bee) = 40,
+ list(
+ /mob/living/simple_mob/vore/sect_drone = 10,
+ /mob/living/simple_mob/vore/sect_queen = 1
+ ) = 20,
+ list(/mob/living/simple_mob/vore/solargrub) = 15,
+ list(
+ /mob/living/simple_mob/vore/oregrub = 5,
+ /mob/living/simple_mob/vore/oregrub/lava = 1
+ ) = 15
+ )
+
+/obj/random/mob/semirandom_mob_spawner/humanoid
+ name = "Semi-Random Humanoid"
+ desc = "Spawns groups of humanoid mobs that may or may not be hostile, all of the same theme type/theme."
+ icon_state = "humanoid"
+ mob_faction = "humanoid"
+
+ possible_mob_types = list(
+ list(
+ /mob/living/simple_mob/shadekin/blue/ai = 25,
+ /mob/living/simple_mob/shadekin/green/ai = 10,
+ /mob/living/simple_mob/shadekin/purple/ai = 1,
+ ) = 1,
+ list(/mob/living/simple_mob/vore/catgirl) = 100,
+ list(/mob/living/simple_mob/vore/wolfgirl) = 100,
+ list(
+ /mob/living/simple_mob/vore/lamia,
+ /mob/living/simple_mob/vore/lamia/albino,
+ /mob/living/simple_mob/vore/lamia/albino/bra,
+ /mob/living/simple_mob/vore/lamia/albino/shirt,
+ /mob/living/simple_mob/vore/lamia/bra,
+ /mob/living/simple_mob/vore/lamia/cobra,
+ /mob/living/simple_mob/vore/lamia/cobra/bra,
+ /mob/living/simple_mob/vore/lamia/cobra/shirt,
+ /mob/living/simple_mob/vore/lamia/copper,
+ /mob/living/simple_mob/vore/lamia/copper/bra,
+ /mob/living/simple_mob/vore/lamia/copper/shirt,
+ /mob/living/simple_mob/vore/lamia/green,
+ /mob/living/simple_mob/vore/lamia/green/bra,
+ /mob/living/simple_mob/vore/lamia/green/shirt,
+ /mob/living/simple_mob/vore/lamia/zebra,
+ /mob/living/simple_mob/vore/lamia/zebra/bra,
+ /mob/living/simple_mob/vore/lamia/zebra/shirt
+ ) = 100,
+// LOOK OKAY MERCS ARE HUMANOIDS SO THEY ARE HERE, but they are also kind of bullshit so they probably shouldn't be able to spawn in the same place as catgirls.
+// I want some better potentially hostile humanoids that aren't stupid to fight. If they become a big issue I'll comment them out.
+// For now they are just rare, and the ranged ones are way more rare than the melee ones, which I think will help balance them out.
+ list(
+ /mob/living/simple_mob/humanoid/merc = 100,
+ /mob/living/simple_mob/humanoid/merc/melee/sword = 50,
+ /mob/living/simple_mob/humanoid/merc/ranged = 25,
+ /mob/living/simple_mob/humanoid/merc/ranged/grenadier = 1,
+ /mob/living/simple_mob/humanoid/merc/ranged/ionrifle = 10,
+ /mob/living/simple_mob/humanoid/merc/ranged/laser = 5,
+ /mob/living/simple_mob/humanoid/merc/ranged/rifle = 5,
+ /mob/living/simple_mob/humanoid/merc/ranged/smg = 5,
+ /mob/living/simple_mob/humanoid/merc/ranged/sniper = 1,
+ /mob/living/simple_mob/humanoid/merc/ranged/space = 10,
+ /mob/living/simple_mob/humanoid/merc/ranged/technician = 5
+ ) = 5,
+// PIRATES are okay though. They can be kind of a pain but you can kind of slap them around. Also it's not like. A crime. To fight and blow up pirates so it's fine.
+ list(
+ /mob/living/simple_mob/humanoid/pirate = 3,
+ /mob/living/simple_mob/humanoid/pirate/ranged = 1
+ ) = 50
+ )
+
+// I am not familiar enough with robots to know which ones are fun to fight so this list isn't weighted at all SO YOU KNOW. Be careful.
+/obj/random/mob/semirandom_mob_spawner/robot
+ name = "Semi-Random Robot"
+ desc = "Spawns groups of robotic mobs that are probably hostile, all of the same theme type/theme."
+ icon_state = "robot"
+ mob_faction = "robot"
+
+ possible_mob_types = list(
+ list(/mob/living/simple_mob/mechanical/combat_drone),
+ list(/mob/living/simple_mob/mechanical/corrupt_maint_drone),
+ list(
+ /mob/living/simple_mob/mechanical/hivebot = 100,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage = 20,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/backline = 10,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/basic = 20,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/dot = 5,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/ion = 20,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/laser = 10,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/rapid = 2,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege = 1,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege/emp = 5,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege/fragmentation = 1,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/siege/radiation = 1,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong = 3,
+ /mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong/guard = 3,
+ /mob/living/simple_mob/mechanical/hivebot/support = 8,
+ /mob/living/simple_mob/mechanical/hivebot/support/commander = 5,
+ /mob/living/simple_mob/mechanical/hivebot/support/commander/autofollow = 10,
+ /mob/living/simple_mob/mechanical/hivebot/swarm = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored/anti_bullet = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored/anti_laser = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/armored/anti_melee = 20,
+ /mob/living/simple_mob/mechanical/hivebot/tank/meatshield = 20
+ ),
+ list(/mob/living/simple_mob/mechanical/infectionbot),
+ list(/mob/living/simple_mob/mechanical/mining_drone),
+ list(/mob/living/simple_mob/mechanical/technomancer_golem),
+ list(
+ /mob/living/simple_mob/mechanical/viscerator,
+ /mob/living/simple_mob/mechanical/viscerator/piercing
+ ),
+ list(/mob/living/simple_mob/mechanical/wahlem),
+ list(/mob/living/simple_mob/animal/passive/fox/syndicate)
+ )
+
+/obj/random/mob/semirandom_mob_spawner/fish
+ name = "Semi-Random Fish"
+ desc = "Spawns groups of fish, all of the same theme type/theme."
+ icon_state = "fish"
+ mob_faction = "fish"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 0
+
+
+ possible_mob_types = list(
+ list(/mob/living/simple_mob/animal/passive/fish/bass) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/icebass) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/javelin) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/koi) = 10,
+ list(/mob/living/simple_mob/animal/passive/fish/measelshark) = 5,
+ list(/mob/living/simple_mob/animal/passive/fish/murkin) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/perch) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/pike) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/rockfish) = 10,
+ list(/mob/living/simple_mob/animal/passive/fish/salmon) = 20,
+ list(/mob/living/simple_mob/animal/passive/fish/solarfish) = 5,
+ list(/mob/living/simple_mob/animal/passive/fish/trout) = 20,
+ list(/mob/living/simple_mob/animal/passive/crab) = 10,
+ list(/mob/living/simple_mob/animal/sif/hooligan_crab) = 1
+ )
+
+/obj/random/mob/semirandom_mob_spawner/bird
+ name = "Semi-Random Bird"
+ desc = "Spawns groups of bird, all of the same theme type/theme."
+ icon_state = "bird"
+ mob_faction = "bird"
+
+ possible_mob_types = list(
+ list(/mob/living/simple_mob/animal/passive/bird),
+ list(/mob/living/simple_mob/animal/passive/bird/azure_tit),
+ list(/mob/living/simple_mob/animal/passive/bird/black_bird),
+ list(/mob/living/simple_mob/animal/passive/bird/european_robin),
+ list(/mob/living/simple_mob/animal/passive/bird/goldcrest),
+ list(/mob/living/simple_mob/animal/passive/bird/ringneck_dove),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/eclectus),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/kea),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/white_caique),
+ list(/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo),
+ list(/mob/living/simple_mob/animal/space/goose),
+ list(/mob/living/simple_mob/animal/passive/chicken),
+ list(/mob/living/simple_mob/animal/passive/penguin)
+ )
+
+/obj/random/mob/semirandom_mob_spawner/vore
+ name = "Semi-Random Voremob"
+ desc = "Spawns groups of voremobs, all of the same theme type/theme."
+ icon_state = "vore"
+ mob_faction = "vore"
+
+ possible_mob_types = list(
+ list(/mob/living/simple_mob/animal/wolf/direwolf) = 100,
+ list(/mob/living/simple_mob/animal/space/jelly) = 70,
+ list(
+ /mob/living/simple_mob/otie/feral,
+ /mob/living/simple_mob/otie/feral/chubby,
+ /mob/living/simple_mob/otie/red,
+ /mob/living/simple_mob/otie/red/chubby
+ ) = 50,
+ list(
+ /mob/living/simple_mob/shadekin/blue/ai = 100,
+ /mob/living/simple_mob/shadekin/green/ai = 50,
+ /mob/living/simple_mob/shadekin/orange/ai = 20,
+ /mob/living/simple_mob/shadekin/purple/ai = 60,
+ /mob/living/simple_mob/shadekin/red/ai = 40,
+ /mob/living/simple_mob/shadekin/yellow/ai = 1
+ ) = 1,
+ list(
+ /mob/living/simple_mob/vore/aggressive/corrupthound,
+ /mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi
+ ) = 70,
+ list(/mob/living/simple_mob/vore/aggressive/deathclaw) = 70,
+ list(/mob/living/simple_mob/vore/aggressive/dino) = 100,
+ list(/mob/living/simple_mob/vore/aggressive/dragon) = 100,
+ list(/mob/living/simple_mob/vore/aggressive/dragon/virgo3b) = 100,
+ list(/mob/living/simple_mob/vore/aggressive/frog) = 100,
+ list(/mob/living/simple_mob/vore/aggressive/giant_snake) = 100,
+ list(/mob/living/simple_mob/vore/aggressive/mimic) = 50,
+ list(/mob/living/simple_mob/vore/aggressive/panther) = 70,
+ list(/mob/living/simple_mob/vore/aggressive/rat) = 100,
+ list(/mob/living/simple_mob/vore/bee) = 100,
+ list(/mob/living/simple_mob/vore/catgirl) = 100,
+ list(/mob/living/simple_mob/vore/cookiegirl) = 100,
+ list(/mob/living/simple_mob/vore/fennec) = 100,
+ list(/mob/living/simple_mob/vore/fennix) = 50,
+ list(/mob/living/simple_mob/vore/hippo) = 70,
+ list(/mob/living/simple_mob/vore/horse) = 100,
+ list(
+ /mob/living/simple_mob/vore/lamia,
+ /mob/living/simple_mob/vore/lamia/albino,
+ /mob/living/simple_mob/vore/lamia/albino/bra,
+ /mob/living/simple_mob/vore/lamia/albino/shirt,
+ /mob/living/simple_mob/vore/lamia/bra,
+ /mob/living/simple_mob/vore/lamia/cobra,
+ /mob/living/simple_mob/vore/lamia/cobra/bra,
+ /mob/living/simple_mob/vore/lamia/cobra/shirt,
+ /mob/living/simple_mob/vore/lamia/copper,
+ /mob/living/simple_mob/vore/lamia/copper/bra,
+ /mob/living/simple_mob/vore/lamia/copper/shirt,
+ /mob/living/simple_mob/vore/lamia/green,
+ /mob/living/simple_mob/vore/lamia/green/bra,
+ /mob/living/simple_mob/vore/lamia/green/shirt,
+ /mob/living/simple_mob/vore/lamia/zebra,
+ /mob/living/simple_mob/vore/lamia/zebra/bra,
+ /mob/living/simple_mob/vore/lamia/zebra/shirt
+ ) = 100,
+ list(/mob/living/simple_mob/vore/rabbit) = 100,
+ list(
+ /mob/living/simple_mob/vore/redpanda = 50,
+ /mob/living/simple_mob/vore/redpanda/fae = 1
+ ) = 100,
+ list(
+ /mob/living/simple_mob/vore/sect_drone = 10,
+ /mob/living/simple_mob/vore/sect_queen = 1
+ ) = 50,
+ list(/mob/living/simple_mob/vore/solargrub) = 100,
+ list(/mob/living/simple_mob/vore/woof) = 1
+ )
+
+/obj/random/mob/semirandom_mob_spawner/sus
+ name = "Weird shit"
+ desc = "Spawns groups of weird stuff, all of the same theme type/theme. Don't put this on normal maps."
+ icon_state = "sus"
+ mob_faction = "sus"
+
+ possible_mob_types = list(
+ list(
+ /mob/living/simple_mob/vore/woof/hostile/melee = 100,
+ /mob/living/simple_mob/vore/woof/hostile/ranged = 20,
+ /mob/living/simple_mob/vore/woof/hostile/horrible = 10,
+ /mob/living/simple_mob/vore/woof/hostile/terrible = 5,
+ /mob/living/simple_mob/vore/woof/cass = 1
+ ),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/recursive)
+ )
+
+/obj/random/mob/semirandom_mob_spawner/mecha
+ name = "Semi-Random Mecha"
+ desc = "Spawns groups of mechs, all of the same theme type/theme. Don't put this on normal maps."
+ icon_state = "mecha"
+ mob_faction = "mecha"
+
+ possible_mob_types = list(
+ list(/mob/living/simple_mob/mechanical/mecha/combat/durand),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/durand/defensive),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/durand/defensive/mercenary),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/gygax),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/gygax/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/gygax/medgax),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/marauder),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/marauder/mauler),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/marauder/seraph),
+ list(/mob/living/simple_mob/mechanical/mecha/combat/phazon),
+ list(/mob/living/simple_mob/mechanical/mecha/hoverpod),
+ list(/mob/living/simple_mob/mechanical/mecha/hoverpod/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/odysseus),
+ list(/mob/living/simple_mob/mechanical/mecha/odysseus/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/odysseus/murdysseus),
+ list(/mob/living/simple_mob/mechanical/mecha/odysseus/murdysseus/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/blue_flames),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/deathripley),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/deathripley/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/firefighter),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/firefighter/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/manned),
+ list(/mob/living/simple_mob/mechanical/mecha/ripley/red_flames)
+ )
+
+
+/obj/random/mob/semirandom_mob_spawner/monster/b
+ mob_faction = "monsterb"
+
+/obj/random/mob/semirandom_mob_spawner/monster/c
+ mob_faction = "monsterc"
+
+/obj/random/mob/semirandom_mob_spawner/monster/d
+ mob_faction = "monsterd"
+
+/obj/random/mob/semirandom_mob_spawner/monster/e
+ mob_faction = "monstere"
+
+/obj/random/mob/semirandom_mob_spawner/monster/f
+ mob_faction = "monsterf"
+
+/obj/random/mob/semirandom_mob_spawner/animal/b
+ mob_faction = "animalb"
+
+/obj/random/mob/semirandom_mob_spawner/animal/c
+ mob_faction = "animalc"
+
+/obj/random/mob/semirandom_mob_spawner/animal/d
+ mob_faction = "animald"
+
+/obj/random/mob/semirandom_mob_spawner/animal/e
+ mob_faction = "animale"
+
+/obj/random/mob/semirandom_mob_spawner/animal/f
+ mob_faction = "animalf"
+
+/obj/random/mob/semirandom_mob_spawner/animal/retaliate
+ mob_faction = "retanimala"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/animal/retaliate/b
+ mob_faction = "retanimalb"
+
+/obj/random/mob/semirandom_mob_spawner/animal/retaliate/c
+ mob_faction = "retanimalc"
+
+/obj/random/mob/semirandom_mob_spawner/animal/hostile
+ mob_faction = "hosanimala"
+ overwrite_hostility = 1
+ mob_hostile = 1
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/animal/hostile/b
+ mob_faction = "hosanimalb"
+
+/obj/random/mob/semirandom_mob_spawner/animal/hostile/c
+ mob_faction = "hosanimalc"
+
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/b
+ mob_faction = "humanoidb"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/c
+ mob_faction = "humanoidc"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/d
+ mob_faction = "humanoidd"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/e
+ mob_faction = "humanoide"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/f
+ mob_faction = "humanoidf"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/retaliate
+ mob_faction = "rethumanoida"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/retaliate/b
+ mob_faction = "rethumanoidb"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/retaliate/c
+ mob_faction = "rethumanoidc"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/hostile
+ mob_faction = "hoshumanoida"
+ overwrite_hostility = 1
+ mob_hostile = 1
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/hostile/b
+ mob_faction = "hoshumanoidb"
+
+/obj/random/mob/semirandom_mob_spawner/humanoid/hostile/c
+ mob_faction = "hoshumanoidc"
+
+/obj/random/mob/semirandom_mob_spawner/robot/b
+ mob_faction = "robotb"
+
+/obj/random/mob/semirandom_mob_spawner/robot/c
+ mob_faction = "robotc"
+
+/obj/random/mob/semirandom_mob_spawner/robot/d
+ mob_faction = "robotd"
+
+/obj/random/mob/semirandom_mob_spawner/robot/e
+ mob_faction = "robote"
+
+/obj/random/mob/semirandom_mob_spawner/robot/f
+ mob_faction = "robotf"
+
+/obj/random/mob/semirandom_mob_spawner/robot/retaliate
+ mob_faction = "retrobota"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/robot/retaliate/b
+ mob_faction = "retrobotb"
+
+/obj/random/mob/semirandom_mob_spawner/robot/retaliate/c
+ mob_faction = "retrobotc"
+
+/obj/random/mob/semirandom_mob_spawner/bird/b
+ mob_faction = "birdb"
+
+/obj/random/mob/semirandom_mob_spawner/bird/c
+ mob_faction = "birdc"
+
+/obj/random/mob/semirandom_mob_spawner/bird/d
+ mob_faction = "birdd"
+
+/obj/random/mob/semirandom_mob_spawner/bird/e
+ mob_faction = "birde"
+
+/obj/random/mob/semirandom_mob_spawner/bird/f
+ mob_faction = "birdf"
+
+/obj/random/mob/semirandom_mob_spawner/fish/b
+ mob_faction = "fishb"
+
+/obj/random/mob/semirandom_mob_spawner/fish/c
+ mob_faction = "fishc"
+
+/obj/random/mob/semirandom_mob_spawner/fish/d
+ mob_faction = "fishd"
+
+/obj/random/mob/semirandom_mob_spawner/fish/e
+ mob_faction = "fishe"
+
+/obj/random/mob/semirandom_mob_spawner/fish/f
+ mob_faction = "fishf"
+
+/obj/random/mob/semirandom_mob_spawner/vore/b
+ mob_faction = "voreb"
+
+/obj/random/mob/semirandom_mob_spawner/vore/c
+ mob_faction = "vorec"
+
+/obj/random/mob/semirandom_mob_spawner/vore/d
+ mob_faction = "vored"
+
+/obj/random/mob/semirandom_mob_spawner/vore/e
+ mob_faction = "voree"
+
+/obj/random/mob/semirandom_mob_spawner/vore/f
+ mob_faction = "voref"
+
+/obj/random/mob/semirandom_mob_spawner/vore/passive
+ mob_faction = "pasvorea"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 0
+
+/obj/random/mob/semirandom_mob_spawner/vore/passive/b
+ mob_faction = "pasvoreb"
+
+/obj/random/mob/semirandom_mob_spawner/vore/passive/c
+ mob_faction = "pasvorec"
+
+/obj/random/mob/semirandom_mob_spawner/vore/retaliate
+ mob_faction = "retvorea"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/vore/retaliate/b
+ mob_faction = "retvoreb"
+
+/obj/random/mob/semirandom_mob_spawner/vore/retaliate/c
+ mob_faction = "retvorec"
+
+/obj/random/mob/semirandom_mob_spawner/vore/hostile
+ mob_faction = "hosvorea"
+ overwrite_hostility = 1
+ mob_hostile = 1
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/vore/hostile/b
+ mob_faction = "hosvoreb"
+
+/obj/random/mob/semirandom_mob_spawner/vore/hostile/c
+ mob_faction = "hosvorec"
+
+/obj/random/mob/semirandom_mob_spawner/sus/b
+ mob_faction = "susb"
+
+/obj/random/mob/semirandom_mob_spawner/sus/c
+ mob_faction = "susc"
+
+/obj/random/mob/semirandom_mob_spawner/sus/d
+ mob_faction = "susd"
+
+/obj/random/mob/semirandom_mob_spawner/sus/e
+ mob_faction = "suse"
+
+/obj/random/mob/semirandom_mob_spawner/sus/f
+ mob_faction = "susf"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/b
+ mob_faction = "mechab"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/c
+ mob_faction = "mechac"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/d
+ mob_faction = "mechad"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/e
+ mob_faction = "mechae"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/f
+ mob_faction = "mechaf"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/retaliate
+ mob_faction = "retmecha"
+ overwrite_hostility = 1
+ mob_hostile = 0
+ mob_retaliate = 1
+
+/obj/random/mob/semirandom_mob_spawner/mecha/retaliate/b
+ mob_faction = "retmechb"
+
+/obj/random/mob/semirandom_mob_spawner/mecha/retaliate/c
+ mob_faction = "retmechc"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 5e109aafc9e..95c24b8247c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -2,6 +2,7 @@
name = "item"
icon = 'icons/obj/items.dmi'
w_class = ITEMSIZE_NORMAL
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC
var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
var/randpixel = 6
@@ -269,6 +270,7 @@
R.hud_used.update_robot_modules_display()
/obj/item/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ . = ..()
if(istype(W, /obj/item/weapon/storage))
var/obj/item/weapon/storage/S = W
if(S.use_to_pickup)
@@ -632,7 +634,7 @@ var/list/global/slot_flags_enumeration = list(
//Make the blood_overlay have the proper color then apply it.
blood_overlay.color = blood_color
- overlays += blood_overlay
+ add_overlay(blood_overlay)
//if this blood isn't already in the list, add it
if(istype(M))
@@ -824,6 +826,9 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
if(!inhands)
apply_blood(standing) //Some items show blood when bloodied
apply_accessories(standing) //Some items sport accessories like webbing
+
+ //Apply overlays to our...overlay
+ apply_overlays(standing)
//Return our icon
return standing
@@ -905,6 +910,15 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
/obj/item/proc/apply_accessories(var/image/standing)
return standing
+/obj/item/proc/apply_overlays(var/image/standing)
+ if(!blocks_emissive)
+ return standing
+
+ var/mutable_appearance/blocker_overlay = mutable_appearance(standing.icon, standing.icon_state, plane = PLANE_EMISSIVE, appearance_flags = KEEP_APART)
+ blocker_overlay.color = GLOB.em_block_color
+ standing.add_overlay(blocker_overlay)
+ return standing
+
/obj/item/MouseEntered(location,control,params)
. = ..()
if(usr.is_preference_enabled(/datum/client_preference/inv_tooltips) && ((src in usr) || isstorage(loc))) // If in inventory or in storage we're looking at
diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm
index b49ee7a70f1..ca026e138b3 100644
--- a/code/game/objects/items/bodybag.dm
+++ b/code/game/objects/items/bodybag.dm
@@ -51,7 +51,7 @@
if (t)
src.name = "body bag - "
src.name += t
- src.overlays += image(src.icon, "bodybag_label")
+ add_overlay("bodybag_label")
else
src.name = "body bag"
//..() //Doesn't need to run the parent. Since when can fucking bodybags be welded shut? -Agouri
@@ -59,7 +59,7 @@
else if(W.is_wirecutter())
to_chat(user, "You cut the tag off the bodybag")
src.name = "body bag"
- src.overlays.Cut()
+ cut_overlays()
return
/obj/structure/closet/body_bag/store_mobs(var/stored_units)
@@ -107,10 +107,10 @@
else
icon_state = "closed_unlocked"
- src.overlays.Cut()
+ cut_overlays()
/* Ours don't have toetags
if(has_label)
- src.overlays += image(src.icon, "bodybag_label")
+ add_overlay("bodybag_label")
*/
@@ -172,11 +172,11 @@
/obj/structure/closet/body_bag/cryobag/update_icon()
..()
- overlays.Cut()
+ cut_overlays()
var/image/I = image(icon, "indicator[opened]")
I.appearance_flags = RESET_COLOR
I.color = COLOR_LIME
- overlays += I
+ add_overlay(I)
/obj/structure/closet/body_bag/cryobag/MouseDrop(over_object, src_location, over_location)
. = ..()
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index fd9767dd877..e1a295dfc4e 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -87,10 +87,10 @@
return TRUE
/obj/item/device/aicard/update_icon()
- overlays.Cut()
+ cut_overlays()
if(carded_ai)
if (!carded_ai.control_disabled)
- overlays += image('icons/obj/pda.dmi', "aicard-on")
+ add_overlay("aicard-on")
if(carded_ai.stat)
icon_state = "aicard-404"
else
diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm
index 2058395d855..6e9cff65e93 100644
--- a/code/game/objects/items/devices/defib.dm
+++ b/code/game/objects/items/devices/defib.dm
@@ -43,25 +43,23 @@
/obj/item/device/defib_kit/update_icon()
- var/list/new_overlays = list()
+ cut_overlays()
if(paddles && paddles.loc == src) //in case paddles got destroyed somehow.
- new_overlays += "[initial(icon_state)]-paddles"
+ add_overlay("[initial(icon_state)]-paddles")
if(bcell && paddles)
if(bcell.check_charge(paddles.chargecost))
if(paddles.combat)
- new_overlays += "[initial(icon_state)]-combat"
+ add_overlay("[initial(icon_state)]-combat")
else if(!paddles.safety)
- new_overlays += "[initial(icon_state)]-emagged"
+ add_overlay("[initial(icon_state)]-emagged")
else
- new_overlays += "[initial(icon_state)]-powered"
+ add_overlay("[initial(icon_state)]-powered")
var/ratio = CEILING(bcell.percent()/25, 1) * 25
- new_overlays += "[initial(icon_state)]-charge[ratio]"
+ add_overlay("[initial(icon_state)]-charge[ratio]")
else
- new_overlays += "[initial(icon_state)]-nocell"
-
- overlays = new_overlays
+ add_overlay("[initial(icon_state)]-nocell")
/obj/item/device/defib_kit/ui_action_click()
toggle_paddles()
diff --git a/code/game/objects/items/devices/denecrotizer_vr.dm b/code/game/objects/items/devices/denecrotizer_vr.dm
new file mode 100644
index 00000000000..ee48820850a
--- /dev/null
+++ b/code/game/objects/items/devices/denecrotizer_vr.dm
@@ -0,0 +1,186 @@
+/mob/living/simple_mob //makes it so that any simplemob can potentially be revived by players and joined by ghosts
+ var/ghostjoin = 0
+ var/ic_revivable = 0
+ var/revivedby = "no one"
+
+//The stuff we want to be revivable normally
+/mob/living/simple_mob/animal
+ ic_revivable = 1
+/mob/living/simple_mob/otie
+ ic_revivable = 1
+/mob/living/simple_mob/vore
+ ic_revivable = 1
+//The stuff that would be revivable but that we don't want to be revivable
+/mob/living/simple_mob/animal/giant_spider/nurse //no you can't revive the ones who can lay eggs and get webs everywhere
+ ic_revivable = 0
+/mob/living/simple_mob/animal/giant_spider/carrier //or the ones who fart babies when they die
+ ic_revivable = 0
+
+//WHEN GHOSTS ATTACK!!!!!
+/mob/living/simple_mob/attack_ghost(mob/observer/dead/user as mob)
+ if(!ghostjoin)
+ return ..()
+
+ var/reply = alert("Would you like to become [src]? It is bound to [revivedby].",,"Yes","No")
+ if(reply == "No")
+ return
+
+ if(ckey) //FIRST ONE TO CLICK YES GETS IT!!!!!! Channel your inner youtube commenter.
+ to_chat(src, "Sorry, someone else has already inhabited [src].")
+ return
+
+ log_and_message_admins("[key_name_admin(user)] joined [src] as a ghost [ADMIN_FLW(src)]")
+ active_ghost_pods -= src
+ if(user.mind)
+ user.mind.active = TRUE
+ user.mind.transfer_to(src)
+ else
+ src.ckey = user.ckey
+ qdel(user)
+ ghostjoin = 0
+ ghostjoin_icon()
+ if(revivedby != "no one")
+ to_chat(src, "Where once your life had been rough and scary, you have been assisted by [revivedby]. They seem to be the reason you are on your feet again... so perhaps you should help them out. Being as you were revived, you are allied with the station. Do not attack anyone unless they are threatening the one who revived you. And try to listen to the one who revived you within reason. Of course, you may do scenes as you like, but you must still respect preferences.")
+ visible_message("[src]'s eyes flicker with a curious intelligence.")
+
+
+/obj/item/device/denecrotizer //Away map reward. FOR TRAINED NECROMANCERS ONLY. >:C
+ name = "experimental denecrotizer"
+ desc = "It looks simple on the outside but this device radiates some unknown dread. It does not appear to be of any ordinary make, and just how it works is unclear, but this device seems to interact with dead flesh."
+ icon = 'icons/obj/device_vr.dmi'
+ icon_state = "denecrotizer"
+ w_class = ITEMSIZE_COST_NORMAL
+ var/charges = 5 //your army of minions can only be this big
+ var/last_used
+ var/cooldown = 10 MINUTES //LONG
+ var/revive_time = 30 SECONDS //Don't do this in combat
+ var/advanced = 1 //allows for ghosts to join mobs who get revived by this, and updates their faction to yours
+
+/obj/item/device/denecrotizer/examine(var/mob/user)
+ . = ..()
+ var/cooldowntime = round((cooldown - (world.time - last_used)) * 0.1)
+ if(Adjacent(user))
+ if(cooldowntime <= 0)
+ . += "The screen indicates that this device is ready to be used, and that it has enough energy for [charges] uses."
+ else
+ . += "The screen indicates that this device can be used again in [cooldowntime] seconds, and that it has enough energy for [charges] uses."
+
+/obj/item/device/denecrotizer/proc/check_target(mob/living/simple_mob/target, mob/living/user)
+ if(!target.Adjacent(user))
+ return FALSE
+ if(user.a_intent != I_HELP) //be gentle
+ user.visible_message("[user] bonks [target] with [src].", runemessage = "bonks [target]")
+ return FALSE
+ if(!istype(target))
+ to_chat(user, "[target] seems to be too complicated for [src] to interface with.")
+ return FALSE
+ if(!(world.time - last_used > cooldown))
+ to_chat(user, "[src] doesn't seem to be ready yet.")
+ return FALSE
+ if(!charges)
+ to_chat(user, "[src] doesn't seem to be active anymore.")
+ return FALSE
+ if(!target.ic_revivable)
+ to_chat(user, "[src] doesn't seem to interface with [target].")
+ return FALSE
+ if(target.stat != DEAD)
+ if(!advanced)
+ to_chat(user, "[src] doesn't seem to work on that.")
+ return FALSE
+ if(target.ai_holder.retaliate || target.ai_holder.hostile) // You can be friends with still living mobs if they are passive I GUESS
+ to_chat(user, "[src] doesn't seem to work on that.")
+ return FALSE
+ if(!target.mind)
+ user.visible_message("[user] gently presses [src] to [target]...", runemessage = "presses [src] to [target]")
+ if(do_after(user, revive_time, exclusive = 1, target = target))
+ target.faction = user.faction
+ target.revivedby = user.name
+ target.ghostjoin = 1
+ active_ghost_pods += target
+ target.ghostjoin_icon()
+ last_used = world.time
+ charges--
+ log_and_message_admins("[key_name_admin(user)] used a denecrotizer to tame/offer a simplemob to ghosts: [target]. [ADMIN_FLW(src)]")
+ target.visible_message("[target]'s eyes widen, as though in revelation as it looks at [user].", runemessage = "eyes widen")
+ if(charges == 0)
+ icon_state = "[initial(icon_state)]-o"
+ update_icon()
+ return FALSE
+ else
+ to_chat(user, "[src] doesn't seem to work on that.")
+ return FALSE
+ return TRUE
+
+/obj/item/device/denecrotizer/proc/ghostjoin_rez(mob/living/simple_mob/target, mob/living/user)
+ user.visible_message("[user] gently presses [src] to [target]...", runemessage = "presses [src] to [target]")
+ if(do_after(user, revive_time, exclusive = 1, target = target))
+ target.faction = user.faction
+ target.revivedby = user.name
+ target.revive()
+ target.sight = initial(target.sight)
+ target.see_in_dark = initial(target.see_in_dark)
+ target.see_invisible = initial(target.see_invisible)
+ target.update_icon()
+ visible_message("[target] lifts its head and looks at [user].", runemessage = "lifts its head and looks at [user]")
+ log_and_message_admins("[key_name_admin(user)] used a denecrotizer to revive a simple mob: [target]. [ADMIN_FLW(src)]")
+ if(!target.mind) //if it doesn't have a mind then no one has been playing as it, and it is safe to offer to ghosts.
+ target.ghostjoin = 1
+ active_ghost_pods += target
+ target.ghostjoin_icon()
+ last_used = world.time
+ charges--
+ if(charges == 0)
+ icon_state = "[initial(icon_state)]-o"
+ update_icon()
+ return
+
+/obj/item/device/denecrotizer/proc/basic_rez(mob/living/simple_mob/target, mob/living/user) //so medical can have a way to bring back people's pets or whatever, does not change any settings about the mob or offer it to ghosts.
+ user.visible_message("[user] presses [src] to [target]...", runemessage = "presses [src] to [target]")
+ if(do_after(user, revive_time, exclusive = 1, target = target))
+ target.revive()
+ target.sight = initial(target.sight)
+ target.see_in_dark = initial(target.see_in_dark)
+ target.see_invisible = initial(target.see_invisible)
+ target.update_icon()
+ visible_message("[target] lifts its head and looks at [user].", runemessage = "lifts its head and looks at [user]")
+ last_used = world.time
+ charges--
+ if(charges == 0)
+ icon_state = "[initial(icon_state)]-o"
+ update_icon()
+ return
+ else
+ user.visible_message("[user] bonks [target] with [src]. Nothing happened.")
+ return
+
+
+
+/obj/item/device/denecrotizer/attack(mob/living/simple_mob/target, mob/living/user)
+ if(check_target(target, user))
+ if(advanced)
+ ghostjoin_rez(target, user)
+ else
+ basic_rez(target, user)
+ else
+ return ..()
+
+/mob/living/simple_mob/proc/ghostjoin_icon() //puts an icon on mobs for ghosts, so they can see if a mob has been revived and is joinable
+ var/static/image/I
+ if(!I)
+ I = image('icons/mob/hud_vr.dmi', "ghostjoin")
+ I.invisibility = INVISIBILITY_OBSERVER
+ I.plane = PLANE_GHOSTS
+ I.appearance_flags = KEEP_APART|RESET_TRANSFORM
+
+ if(ghostjoin)
+ add_overlay(I)
+ else
+ cut_overlay(I)
+
+/obj/item/device/denecrotizer/medical //Can revive more things, but without the special ghost and faction stuff. For medical use.
+ name = "commercial denecrotizer"
+ desc = "A curious device who's purpose is reviving simpler life forms. It seems to radiate menace."
+ icon_state = "m-denecrotizer"
+ advanced = 0 //This one isn't as fancy
+ cooldown = 5 MINUTES //not as long
+ charges = 20 //in case spiders merc Ian
\ No newline at end of file
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 3dafea4ac78..62d1b4b9341 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -7,15 +7,18 @@
slot_flags = SLOT_BELT
matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20)
action_button_name = "Toggle Flashlight"
+
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
+ light_range = 4 //luminosity when on
+ light_power = 0.8 //lighting power when on
+ light_color = "#FFFFFF" //LIGHT_COLOR_INCANDESCENT_FLASHLIGHT //lighting colour when on
+ light_cone_y_offset = -7
+
var/on = 0
- var/brightness_on = 4 //luminosity when on
- var/flashlight_power = 0.8 //lighting power when on
- var/flashlight_colour = LIGHT_COLOR_INCANDESCENT_FLASHLIGHT //lighting colour when on
+
var/obj/item/weapon/cell/cell
var/cell_type = /obj/item/weapon/cell/device
- var/list/brightness_levels
- var/brightness_level = "medium"
- var/power_usage
+ var/power_usage = 1
var/power_use = 1
/obj/item/device/flashlight/Initialize()
@@ -23,12 +26,8 @@
if(power_use && cell_type)
cell = new cell_type(src)
- brightness_levels = list("low" = 0.25, "medium" = 0.5, "high" = 1)
- power_usage = brightness_levels[brightness_level]
- else
- verbs -= /obj/item/device/flashlight/verb/toggle
-
- update_icon()
+
+ update_brightness()
/obj/item/device/flashlight/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -38,63 +37,40 @@
/obj/item/device/flashlight/get_cell()
return cell
-/obj/item/device/flashlight/verb/toggle()
- set name = "Toggle Flashlight Brightness"
- set category = "Object"
- set src in usr
- set_brightness(usr)
-
-/obj/item/device/flashlight/proc/set_brightness(mob/user as mob)
- var/choice = input("Choose a brightness level.") as null|anything in brightness_levels
- if(choice)
- brightness_level = choice
- power_usage = brightness_levels[choice]
- to_chat(user, "You set the brightness level on \the [src] to [brightness_level].")
- update_icon()
-
/obj/item/device/flashlight/process()
if(!on || !cell)
return PROCESS_KILL
- if(brightness_level && power_usage)
+ if(power_usage)
if(cell.use(power_usage) != power_usage) // we weren't able to use our full power_usage amount!
visible_message("\The [src] flickers before going dull.")
- set_light(0)
- playsound(src, 'sound/effects/sparks3.ogg', 10, 1, -3) //Small cue that your light went dull in your pocket.
+ playsound(src, 'sound/effects/sparks3.ogg', 10, 1, -3) //Small cue that your light went dull in your pocket. //VOREStation Edit
on = 0
- update_icon()
+ update_brightness()
return PROCESS_KILL
-/obj/item/device/flashlight/update_icon()
+/obj/item/device/flashlight/proc/update_brightness()
if(on)
icon_state = "[initial(icon_state)]-on"
-
- if(brightness_level == "low")
- set_light(brightness_on/2, flashlight_power*0.75, flashlight_colour)
- else if(brightness_level == "high")
- set_light(brightness_on*1.5, flashlight_power*1.1, flashlight_colour)
- else
- set_light(brightness_on, flashlight_power, flashlight_colour)
-
else
- icon_state = "[initial(icon_state)]"
- set_light(0)
+ icon_state = initial(icon_state)
+ set_light_on(on)
+ if(light_system == STATIC_LIGHT)
+ update_light()
/obj/item/device/flashlight/examine(mob/user)
. = ..()
- if(power_use && brightness_level)
- . += "\The [src] is set to [brightness_level]."
- if(cell)
- . += "\The [src] has a \the [cell] attached."
+ if(power_use && cell)
+ . += "\The [src] has a \the [cell] attached."
- if(cell.charge <= cell.maxcharge*0.25)
- . += "It appears to have a low amount of power remaining."
- else if(cell.charge > cell.maxcharge*0.25 && cell.charge <= cell.maxcharge*0.5)
- . += "It appears to have an average amount of power remaining."
- else if(cell.charge > cell.maxcharge*0.5 && cell.charge <= cell.maxcharge*0.75)
- . += "It appears to have an above average amount of power remaining."
- else if(cell.charge > cell.maxcharge*0.75 && cell.charge <= cell.maxcharge)
- . += "It appears to have a high amount of power remaining."
+ if(cell.charge <= cell.maxcharge*0.25)
+ . += "It appears to have a low amount of power remaining."
+ else if(cell.charge > cell.maxcharge*0.25 && cell.charge <= cell.maxcharge*0.5)
+ . += "It appears to have an average amount of power remaining."
+ else if(cell.charge > cell.maxcharge*0.5 && cell.charge <= cell.maxcharge*0.75)
+ . += "It appears to have an above average amount of power remaining."
+ else if(cell.charge > cell.maxcharge*0.75 && cell.charge <= cell.maxcharge)
+ . += "It appears to have a high amount of power remaining."
/obj/item/device/flashlight/attack_self(mob/user)
if(power_use)
@@ -109,8 +85,8 @@
START_PROCESSING(SSobj, src)
else if(power_use)
STOP_PROCESSING(SSobj, src)
- playsound(src, 'sound/weapons/empty.ogg', 15, 1, -3)
- update_icon()
+ playsound(src, 'sound/weapons/empty.ogg', 15, 1, -3) // VOREStation Edit
+ update_brightness()
user.update_action_buttons()
return 1
@@ -177,7 +153,7 @@
to_chat(user, "You remove the cell from the [src].")
playsound(src, 'sound/machines/button.ogg', 30, 1, 0)
on = 0
- update_icon()
+ update_brightness()
return
..()
else
@@ -225,7 +201,7 @@
cell = W
to_chat(user, "You install a cell in \the [src].")
playsound(src, 'sound/machines/button.ogg', 30, 1, 0)
- update_icon()
+ update_brightness()
else
to_chat(user, "\The [src] already has a cell.")
else
@@ -242,7 +218,7 @@
drop_sound = 'sound/items/drop/accessory.ogg'
pickup_sound = 'sound/items/pickup/accessory.ogg'
slot_flags = SLOT_EARS
- brightness_on = 2
+ light_range = 2
w_class = ITEMSIZE_TINY
power_use = 0
@@ -270,7 +246,7 @@
name = "maglight"
desc = "A very, very heavy duty flashlight."
icon_state = "maglight"
- flashlight_colour = LIGHT_COLOR_FLUORESCENT_FLASHLIGHT
+ light_color = LIGHT_COLOR_FLUORESCENT_FLASHLIGHT
force = 10
slot_flags = SLOT_BELT
w_class = ITEMSIZE_SMALL
@@ -283,7 +259,7 @@
desc = "A miniature lamp, that might be used by small robots."
icon_state = "penlight"
item_state = null
- brightness_on = 2
+ light_range = 2
w_class = ITEMSIZE_TINY
power_use = 0
@@ -294,10 +270,11 @@
icon_state = "lamp"
force = 10
center_of_mass = list("x" = 13,"y" = 11)
- brightness_on = 10
+ light_range = 5
w_class = ITEMSIZE_LARGE
power_use = 0
on = 1
+ light_system = STATIC_LIGHT
// green-shaded desk lamp
@@ -305,8 +282,7 @@
desc = "A classic green-shaded desk lamp."
icon_state = "lampgreen"
center_of_mass = list("x" = 15,"y" = 11)
- brightness_on = 5
- flashlight_colour = "#FFC58F"
+ light_color = "#FFC58F"
/obj/item/device/flashlight/lamp/verb/toggle_light()
set name = "Toggle light"
@@ -322,9 +298,9 @@
name = "flare"
desc = "A red standard-issue flare. There are instructions on the side reading 'pull cord, make light'."
w_class = ITEMSIZE_SMALL
- brightness_on = 8 // Pretty bright.
- flashlight_power = 0.8
- flashlight_colour = LIGHT_COLOR_FLARE
+ light_range = 8 // Pretty bright.
+ light_power = 0.8
+ light_color = LIGHT_COLOR_FLARE
icon_state = "flare"
item_state = "flare"
action_button_name = null //just pull it manually, neckbeard.
@@ -334,6 +310,7 @@
power_use = 0
drop_sound = 'sound/items/drop/gloves.ogg'
pickup_sound = 'sound/items/pickup/gloves.ogg'
+ light_system = MOVABLE_LIGHT
/obj/item/device/flashlight/flare/New()
fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
@@ -354,7 +331,7 @@
on = 0
src.force = initial(src.force)
src.damtype = initial(src.damtype)
- update_icon()
+ update_brightness()
/obj/item/device/flashlight/flare/attack_self(mob/user)
@@ -375,7 +352,7 @@
/obj/item/device/flashlight/flare/proc/ignite() //Used for flare launchers.
on = !on
- update_icon()
+ update_brightness()
force = on_damage
damtype = "fire"
START_PROCESSING(SSobj, src)
@@ -387,9 +364,10 @@
name = "green glowstick"
desc = "A green military-grade glowstick."
w_class = ITEMSIZE_SMALL
- brightness_on = 4
- flashlight_power = 0.9
- flashlight_colour = "#49F37C"
+ light_system = MOVABLE_LIGHT
+ light_range = 4
+ light_power = 0.9
+ light_color = "#49F37C"
icon_state = "glowstick"
item_state = "glowstick"
var/fuel = 0
@@ -409,7 +387,7 @@
/obj/item/device/flashlight/glowstick/proc/turn_off()
on = 0
- update_icon()
+ update_brightness()
/obj/item/device/flashlight/glowstick/attack_self(mob/user)
@@ -427,28 +405,28 @@
/obj/item/device/flashlight/glowstick/red
name = "red glowstick"
desc = "A red military-grade glowstick."
- flashlight_colour = "#FC0F29"
+ light_color = "#FC0F29"
icon_state = "glowstick_red"
item_state = "glowstick_red"
/obj/item/device/flashlight/glowstick/blue
name = "blue glowstick"
desc = "A blue military-grade glowstick."
- flashlight_colour = "#599DFF"
+ light_color = "#599DFF"
icon_state = "glowstick_blue"
item_state = "glowstick_blue"
/obj/item/device/flashlight/glowstick/orange
name = "orange glowstick"
desc = "A orange military-grade glowstick."
- flashlight_colour = "#FA7C0B"
+ light_color = "#FA7C0B"
icon_state = "glowstick_orange"
item_state = "glowstick_orange"
/obj/item/device/flashlight/glowstick/yellow
name = "yellow glowstick"
desc = "A yellow military-grade glowstick."
- flashlight_colour = "#FEF923"
+ light_color = "#FEF923"
icon_state = "glowstick_yellow"
item_state = "glowstick_yellow"
@@ -460,17 +438,17 @@
icon = 'icons/obj/lighting.dmi'
icon_state = "floor1" //not a slime extract sprite but... something close enough!
item_state = "slime"
- flashlight_colour = "#FFF423"
+ light_color = "#FFF423"
w_class = ITEMSIZE_TINY
- brightness_on = 6
+ light_range = 6
on = 1 //Bio-luminesence has one setting, on.
power_use = 0
/obj/item/device/flashlight/slime/New()
..()
- set_light(brightness_on, flashlight_power, flashlight_colour)
+ set_light(light_range, light_power, light_color)
-/obj/item/device/flashlight/slime/update_icon()
+/obj/item/device/flashlight/slime/update_brightness()
return
/obj/item/device/flashlight/slime/attack_self(mob/user)
diff --git a/code/game/objects/items/devices/flashlight_vr.dm b/code/game/objects/items/devices/flashlight_vr.dm
index 6c505950065..876dddc76d8 100644
--- a/code/game/objects/items/devices/flashlight_vr.dm
+++ b/code/game/objects/items/devices/flashlight_vr.dm
@@ -1,8 +1,9 @@
/obj/item/device/flashlight/glowstick/radioisotope
name = "radioisotope glowstick"
desc = "A radioisotope powered glowstick. Escaping particles light up the area far brighter on similar levels to flares and for longer"
- flashlight_colour = "#599DFF"
icon_state = "glowstick_blue"
item_state = "glowstick_blue"
- flashlight_power = 0.1
- brightness_on = 8
+
+ light_range = 8
+ light_power = 0.1
+ light_color = "#599DFF"
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 837c6616f78..18fc2935429 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -29,6 +29,7 @@
var/obj/machinery/connectable //Used to connect machinery.
var/weakref_wiring //Used to store weak references for integrated circuitry. This is now the Omnitool.
toolspeed = 1
+ tool_qualities = list(TOOL_MULTITOOL)
/obj/item/device/multitool/attack_self(mob/living/user)
var/choice = alert("What do you want to do with \the [src]?","Multitool Menu", "Switch Mode", "Clear Buffers", "Cancel")
diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index c3850ad0dd8..db88469a47f 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -24,7 +24,7 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard)
/obj/item/device/paicard/New()
..()
- overlays += "pai-off"
+ add_overlay("pai-off")
/obj/item/device/paicard/Destroy()
//Will stop people throwing friend pAIs into the singularity so they can respawn
@@ -304,34 +304,34 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard)
/obj/item/device/paicard/proc/setPersonality(mob/living/silicon/pai/personality)
src.pai = personality
- src.overlays += "pai-happy"
+ add_overlay("pai-happy")
/obj/item/device/paicard/proc/removePersonality()
src.pai = null
- src.overlays.Cut()
- src.overlays += "pai-off"
+ cut_overlays()
+ add_overlay("pai-off")
/obj/item/device/paicard
var/current_emotion = 1
/obj/item/device/paicard/proc/setEmotion(var/emotion)
if(pai)
- src.overlays.Cut()
+ cut_overlays()
switch(emotion)
- if(1) src.overlays += "pai-happy"
- if(2) src.overlays += "pai-cat"
- if(3) src.overlays += "pai-extremely-happy"
- if(4) src.overlays += "pai-face"
- if(5) src.overlays += "pai-laugh"
- if(6) src.overlays += "pai-off"
- if(7) src.overlays += "pai-sad"
- if(8) src.overlays += "pai-angry"
- if(9) src.overlays += "pai-what"
- if(10) src.overlays += "pai-neutral"
- if(11) src.overlays += "pai-silly"
- if(12) src.overlays += "pai-nose"
- if(13) src.overlays += "pai-smirk"
- if(14) src.overlays += "pai-exclamation"
- if(15) src.overlays += "pai-question"
+ if(1) add_overlay("pai-happy")
+ if(2) add_overlay("pai-cat")
+ if(3) add_overlay("pai-extremely-happy")
+ if(4) add_overlay("pai-face")
+ if(5) add_overlay("pai-laugh")
+ if(6) add_overlay("pai-off")
+ if(7) add_overlay("pai-sad")
+ if(8) add_overlay("pai-angry")
+ if(9) add_overlay("pai-what")
+ if(10) add_overlay("pai-neutral")
+ if(11) add_overlay("pai-silly")
+ if(12) add_overlay("pai-nose")
+ if(13) add_overlay("pai-smirk")
+ if(14) add_overlay("pai-exclamation")
+ if(15) add_overlay("pai-question")
current_emotion = emotion
/obj/item/device/paicard/proc/alertUpdate()
diff --git a/code/game/objects/items/devices/radio/jammer.dm b/code/game/objects/items/devices/radio/jammer.dm
index b59101cc663..ed527079042 100644
--- a/code/game/objects/items/devices/radio/jammer.dm
+++ b/code/game/objects/items/devices/radio/jammer.dm
@@ -109,8 +109,7 @@ var/global/list/active_radio_jammers = list()
// Only Cut() if we need to.
if(overlay_percent != last_overlay_percent)
- overlays.Cut()
- var/image/I = image(src.icon, src, "jammer_overlay_[overlay_percent]")
- overlays += I
+ cut_overlays()
+ add_overlay("jammer_overlay_[overlay_percent]")
last_overlay_percent = overlay_percent
diff --git a/code/game/objects/items/devices/t_scanner.dm b/code/game/objects/items/devices/t_scanner.dm
index 0709429ac1b..bd96945fc64 100644
--- a/code/game/objects/items/devices/t_scanner.dm
+++ b/code/game/objects/items/devices/t_scanner.dm
@@ -28,7 +28,7 @@
/obj/item/device/t_scanner/proc/set_active(var/active)
on = active
if(on)
- START_PROCESSING(SSobj, src)
+ START_PROCESSING(SSobj, src)
flicker = 0
else
STOP_PROCESSING(SSobj, src)
@@ -87,7 +87,7 @@
if(istype(scanned, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/P = scanned
I.color = P.pipe_color
- I.overlays += P.overlays
+ I.add_overlay(P.overlays)
I.alpha = 128
I.mouse_opacity = 0
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 4e5032b6b9f..a7786526863 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -372,9 +372,9 @@
/obj/item/device/tape/update_icon()
- overlays.Cut()
+ cut_overlays()
if(ruined)
- overlays += "ribbonoverlay"
+ add_overlay("ribbonoverlay")
/obj/item/device/tape/fire_act()
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index f72c3c4d24f..dc27b39fce5 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -119,7 +119,7 @@
VARSET_IN(src, toggle, TRUE, 5 SECONDS)
/obj/item/device/transfer_valve/update_icon()
- overlays.Cut()
+ cut_overlays()
underlays = null
if(!tank_one && !tank_two && !attached_device)
@@ -128,13 +128,13 @@
icon_state = "valve"
if(tank_one)
- overlays += "[tank_one.icon_state]"
+ add_overlay("[tank_one.icon_state]")
if(tank_two)
var/icon/J = new(icon, icon_state = "[tank_two.icon_state]")
J.Shift(WEST, 13)
underlays += J
if(attached_device)
- overlays += "device"
+ add_overlay("device")
/obj/item/device/transfer_valve/proc/remove_tank(obj/item/weapon/tank/T)
if(tank_one == T)
diff --git a/code/game/objects/items/devices/translocator_vr.dm b/code/game/objects/items/devices/translocator_vr.dm
index 0b3715fa5c4..0fb898edbfa 100644
--- a/code/game/objects/items/devices/translocator_vr.dm
+++ b/code/game/objects/items/devices/translocator_vr.dm
@@ -73,9 +73,9 @@
var/obj/item/device/perfect_tele_beacon/beacon = beacons[bcn]
if(destination == beacon)
- I.overlays += radial_seton
+ I.add_overlay(radial_seton)
else
- I.overlays += radial_set
+ I.add_overlay(radial_set)
radial_images[bcn] = I
@@ -83,7 +83,7 @@
if(beacons_left)
var/image/I = image(icon = 'icons/mob/radial_vr.dmi', icon_state = "tl_[index]")
- I.overlays += radial_plus
+ I.add_overlay(radial_plus)
radial_images["New Beacon"] = I
/obj/item/device/perfect_tele/attack_hand(mob/user)
diff --git a/code/game/objects/items/glassjar.dm b/code/game/objects/items/glassjar.dm
index 9db0d88010f..1c066117a93 100644
--- a/code/game/objects/items/glassjar.dm
+++ b/code/game/objects/items/glassjar.dm
@@ -86,7 +86,7 @@
/obj/item/glass_jar/update_icon() // Also updates name and desc
underlays.Cut()
- overlays.Cut()
+ cut_overlays()
switch(contains)
if(JAR_NOTHING)
name = initial(name)
@@ -138,7 +138,7 @@
/obj/item/glass_jar/fish/update_icon() // Also updates name and desc
underlays.Cut()
- overlays.Cut()
+ cut_overlays()
if(filled)
underlays += image(icon, "[icon_state]_water")
diff --git a/code/game/objects/items/robobag.dm b/code/game/objects/items/robobag.dm
index 33c3ba89ed9..4c54a5d78fa 100644
--- a/code/game/objects/items/robobag.dm
+++ b/code/game/objects/items/robobag.dm
@@ -32,7 +32,7 @@
. += "[src] has a [corptag] attached to it."
/obj/structure/closet/body_bag/cryobag/robobag/update_icon()
- overlays.Cut()
+ cut_overlays()
..()
if(corptag)
var/corptag_icon_state = "tag_blank"
@@ -45,8 +45,7 @@
else if(istype(corptag, /obj/item/clothing/accessory/badge/corporate_tag))
corptag_icon_state = corptag.icon_state
- var/image/I = image(icon, corptag_icon_state)
- overlays += I
+ add_overlay(corptag_icon_state)
/obj/structure/closet/body_bag/cryobag/robobag/AltClick(mob/user)
if(!Adjacent(user))
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 554663727fb..87361c2e05b 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -76,19 +76,19 @@
src.updateicon()
/obj/item/robot_parts/robot_suit/proc/updateicon()
- src.overlays.Cut()
+ cut_overlays()
if(src.l_arm)
- src.overlays += "l_arm+o"
+ add_overlay("l_arm+o")
if(src.r_arm)
- src.overlays += "r_arm+o"
+ add_overlay("r_arm+o")
if(src.chest)
- src.overlays += "chest+o"
+ add_overlay("chest+o")
if(src.l_leg)
- src.overlays += "l_leg+o"
+ add_overlay("l_leg+o")
if(src.r_leg)
- src.overlays += "r_leg+o"
+ add_overlay("r_leg+o")
if(src.head)
- src.overlays += "head+o"
+ add_overlay("head+o")
/obj/item/robot_parts/robot_suit/proc/check_completion()
if(src.l_arm && src.r_arm)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 982236f43c3..d25e96f0788 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -36,7 +36,7 @@
if (istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0, user))
- overlays.Cut()
+ cut_overlays()
to_chat(usr, "You slice off [src]'s uneven chunks of aluminum and scorch marks.")
return
@@ -139,7 +139,7 @@
virtualIcon.DrawBox(null, B.b1x1, B.b1y, B.b1x2, B.b1y) // horizontal line, left to right
virtualIcon.DrawBox(null, B.b2x, B.b2y1, B.b2x, B.b2y2) // vertical line, top to bottom
- overlays += bmark // add the decal
+ add_overlay(bmark) // add the decal
icon = virtualIcon // apply bulletholes over decals
diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm
index c4d0bf657e7..d81e6e444e3 100644
--- a/code/game/objects/items/weapons/explosives.dm
+++ b/code/game/objects/items/weapons/explosives.dm
@@ -65,7 +65,7 @@
message_admins("[key_name(user, user.client)](?) planted [src.name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [timer] second fuse",0,1)
log_game("[key_name(user)] planted [src.name] on [target.name] at ([target.x],[target.y],[target.z]) with [timer] second fuse")
- target.overlays += image_overlay
+ target.add_overlay(image_overlay, TRUE)
to_chat(user, "Bomb has been planted. Timer counting down from [timer].")
spawn(timer*10)
explode(get_turf(target))
@@ -87,7 +87,7 @@
else
target.ex_act(1)
if(target)
- target.overlays -= image_overlay
+ target.cut_overlay(image_overlay, TRUE)
qdel(src)
/obj/item/weapon/plastique/attack(mob/M as mob, mob/user as mob, def_zone)
diff --git a/code/game/objects/items/weapons/explosives_vr.dm b/code/game/objects/items/weapons/explosives_vr.dm
index ce7a182fd6d..fb065b7bf93 100644
--- a/code/game/objects/items/weapons/explosives_vr.dm
+++ b/code/game/objects/items/weapons/explosives_vr.dm
@@ -10,7 +10,7 @@
var/turf/T = get_turf(target)
if(T.z in using_map.station_levels)
target.visible_message("\The [src] lets out a loud beep as safeties trigger, before imploding and falling apart.")
- target.overlays -= image_overlay
+ target.cut_overlay(image_overlay, TRUE)
qdel(src)
return 0
else
diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm
index b2e783ba69a..ad23dc4f2a2 100644
--- a/code/game/objects/items/weapons/flamethrower.dm
+++ b/code/game/objects/items/weapons/flamethrower.dm
@@ -46,13 +46,13 @@
/obj/item/weapon/flamethrower/update_icon()
- overlays.Cut()
+ cut_overlays()
if(igniter)
- overlays += "+igniter[status]"
+ add_overlay("+igniter[status]")
if(ptank)
- overlays += "+ptank"
+ add_overlay("+ptank")
if(lit)
- overlays += "+lit"
+ add_overlay("+lit")
item_state = "flamethrower_1"
else
item_state = "flamethrower_0"
diff --git a/code/game/objects/items/weapons/grenades/supermatter.dm b/code/game/objects/items/weapons/grenades/supermatter.dm
index 7eff5accd45..988c00d0b26 100644
--- a/code/game/objects/items/weapons/grenades/supermatter.dm
+++ b/code/game/objects/items/weapons/grenades/supermatter.dm
@@ -19,9 +19,9 @@
playsound(src, 'sound/weapons/wave.ogg', 100)
/obj/item/weapon/grenade/supermatter/update_icon()
- overlays.Cut()
+ cut_overlays()
if(implode_at)
- overlays += image(icon = 'icons/rust.dmi', icon_state = "emfield_s1")
+ add_overlay(image(icon = 'icons/rust.dmi', icon_state = "emfield_s1"))
/obj/item/weapon/grenade/supermatter/process()
if(!isturf(loc))
diff --git a/code/game/objects/items/weapons/material/ashtray.dm b/code/game/objects/items/weapons/material/ashtray.dm
index 95e558b36aa..a06e0afe933 100644
--- a/code/game/objects/items/weapons/material/ashtray.dm
+++ b/code/game/objects/items/weapons/material/ashtray.dm
@@ -22,23 +22,23 @@ var/global/list/ashtray_cache = list()
/obj/item/weapon/material/ashtray/update_icon()
color = null
- overlays.Cut()
+ cut_overlays()
var/cache_key = "base-[material.name]"
if(!ashtray_cache[cache_key])
var/image/I = image('icons/obj/objects.dmi',"ashtray")
I.color = material.icon_colour
ashtray_cache[cache_key] = I
- overlays |= ashtray_cache[cache_key]
+ add_overlay(ashtray_cache[cache_key])
if (contents.len == max_butts)
if(!ashtray_cache["full"])
ashtray_cache["full"] = image('icons/obj/objects.dmi',"ashtray_full")
- overlays |= ashtray_cache["full"]
+ add_overlay(ashtray_cache["full"])
desc = "It's stuffed full."
else if (contents.len > max_butts/2)
if(!ashtray_cache["half"])
ashtray_cache["half"] = image('icons/obj/objects.dmi',"ashtray_half")
- overlays |= ashtray_cache["half"]
+ add_overlay(ashtray_cache["half"])
desc = "It's half-filled."
else
desc = "An ashtray made of [material.display_name]."
diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm
index e52b2add285..909b3f0618a 100644
--- a/code/game/objects/items/weapons/material/kitchen.dm
+++ b/code/game/objects/items/weapons/material/kitchen.dm
@@ -49,7 +49,7 @@
return
M.visible_message("\The [user] feeds some [loaded] to \the [M] with \the [src].")
playsound(src,'sound/items/eatfood.ogg', rand(10,40), 1)
- overlays.Cut()
+ cut_overlays()
return
else
to_chat(user, "You don't have anything on \the [src].") //if we have help intent and no food scooped up DON'T STAB OURSELVES WITH THE FORK
diff --git a/code/game/objects/items/weapons/policetape.dm b/code/game/objects/items/weapons/policetape.dm
index 61162363ee6..9cb6f78daae 100644
--- a/code/game/objects/items/weapons/policetape.dm
+++ b/code/game/objects/items/weapons/policetape.dm
@@ -114,7 +114,7 @@ var/list/tape_roll_applications = list()
color = COLOR_DEEP_SKY_BLUE
/obj/item/taperoll/update_icon()
- overlays.Cut()
+ cut_overlays()
var/image/overlay = image(icon = src.icon)
overlay.appearance_flags = RESET_COLOR
if(ismob(loc))
@@ -122,7 +122,7 @@ var/list/tape_roll_applications = list()
overlay.icon_state = "start"
else
overlay.icon_state = "stop"
- overlays += overlay
+ add_overlay(overlay)
/obj/item/taperoll/dropped(mob/user)
@@ -303,11 +303,11 @@ var/list/tape_roll_applications = list()
if(tape_roll_applications[F] & direction) // hazard_overlay in F.overlays wouldn't work.
user.visible_message("\The [user] uses the adhesive of \the [src] to remove area markings from \the [F].", "You use the adhesive of \the [src] to remove area markings from \the [F].")
- F.overlays -= hazard_overlay
+ F.cut_overlay(hazard_overlay)
tape_roll_applications[F] &= ~direction
else
user.visible_message("\The [user] applied \the [src] on \the [F] to create area markings.", "You apply \the [src] on \the [F] to create area markings.")
- F.overlays |= hazard_overlay
+ F.add_overlay(hazard_overlay)
tape_roll_applications[F] |= direction
return
diff --git a/code/game/objects/items/weapons/storage/backpack_vr.dm b/code/game/objects/items/weapons/storage/backpack_vr.dm
index 33e6aa2b3b0..eda37941a1e 100644
--- a/code/game/objects/items/weapons/storage/backpack_vr.dm
+++ b/code/game/objects/items/weapons/storage/backpack_vr.dm
@@ -115,6 +115,38 @@
icon_override = 'icons/mob/back_vr.dmi'
icon_state = "explorer_duffle"
+///Talon Bags///
+
+/obj/item/weapon/storage/backpack/talon
+ name = "ITV backpack"
+ desc = "A backpack for carrying a large number of supplies easily."
+ icon = 'icons/obj/clothing/backpack_vr.dmi'
+ icon_override = 'icons/mob/back_vr.dmi'
+ icon_state = "talon"
+
+/obj/item/weapon/storage/backpack/satchel/talon
+ name = "ITV satchel"
+ desc = "A satchel for carrying a large number of supplies easily."
+ icon = 'icons/obj/clothing/backpack_vr.dmi'
+ icon_override = 'icons/mob/back_vr.dmi'
+ icon_state = "talon_satchel"
+ item_state_slots = null
+
+/obj/item/weapon/storage/backpack/messenger/talon
+ name = "ITV messenger bag"
+ desc = "A sturdy backpack worn over one shoulder."
+ icon = 'icons/obj/clothing/backpack_vr.dmi'
+ icon_override = 'icons/mob/back_vr.dmi'
+ icon_state = "talon_courier"
+ item_state_slots = null
+
+/obj/item/weapon/storage/backpack/dufflebag/talon
+ name = "ITV dufflebag"
+ desc = "A large dufflebag for holding extra supplies."
+ icon = 'icons/obj/clothing/backpack_vr.dmi'
+ icon_override = 'icons/mob/back_vr.dmi'
+ icon_state = "talon_duffle"
+
///Roboticist Bags///
/obj/item/weapon/storage/backpack/satchel/roboticist
diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm
index e1ff8f0ce5a..4d06d52314a 100644
--- a/code/game/objects/items/weapons/storage/fancy.dm
+++ b/code/game/objects/items/weapons/storage/fancy.dm
@@ -125,9 +125,9 @@
/obj/item/weapon/storage/fancy/crayons/update_icon()
var/mutable_appearance/ma = new(src)
- ma.overlays = list()
+ ma.cut_overlays()
for(var/obj/item/weapon/pen/crayon/crayon in contents)
- ma.overlays += image('icons/obj/crayons.dmi',crayon.colourName)
+ add_overlay(image('icons/obj/crayons.dmi',crayon.colourName))
appearance = ma
/obj/item/weapon/storage/fancy/crayons/attackby(obj/item/W as obj, mob/user as mob)
@@ -167,9 +167,9 @@
/obj/item/weapon/storage/fancy/markers/update_icon()
var/mutable_appearance/ma = new(src)
- ma.overlays = list()
+ ma.cut_overlays()
for(var/obj/item/weapon/pen/crayon/marker/marker in contents)
- ma.overlays += image('icons/obj/crayons.dmi',"m"+marker.colourName)
+ ma.add_overlay(image('icons/obj/crayons.dmi',"m"+marker.colourName))
appearance = ma
/obj/item/weapon/storage/fancy/markers/attackby(obj/item/W as obj, mob/user as mob)
@@ -398,14 +398,13 @@
/obj/item/weapon/storage/lockbox/vials/update_icon(var/itemremoved = 0)
var/total_contents = contents.len - itemremoved
icon_state = "vialbox[total_contents]"
- overlays.Cut()
+ cut_overlays()
if (!broken)
- overlays += image(icon, src, "led[locked]")
+ add_overlay("led[locked]")
if(locked)
- overlays += image(icon, src, "cover")
+ add_overlay("cover")
else
- overlays += image(icon, src, "ledb")
- return
+ add_overlay("ledb")
/obj/item/weapon/storage/lockbox/vials/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm
index 9b87ee51d39..bb6bb1032c4 100644
--- a/code/game/objects/items/weapons/storage/firstaid.dm
+++ b/code/game/objects/items/weapons/storage/firstaid.dm
@@ -200,11 +200,11 @@
update_icon()
/obj/item/weapon/storage/pill_bottle/update_icon()
- overlays.Cut()
+ cut_overlays()
if(wrapper_color)
var/image/I = image(icon, "pillbottle_wrap")
I.color = wrapper_color
- overlays += I
+ add_overlay(I)
/obj/item/weapon/storage/pill_bottle/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen))
diff --git a/code/game/objects/items/weapons/storage/misc.dm b/code/game/objects/items/weapons/storage/misc.dm
index 9f6d4929b84..5c9be66e260 100644
--- a/code/game/objects/items/weapons/storage/misc.dm
+++ b/code/game/objects/items/weapons/storage/misc.dm
@@ -18,10 +18,10 @@
update_icon()
/obj/item/weapon/storage/box/donut/update_icon()
- overlays.Cut()
+ cut_overlays()
var/i = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/donut/D in contents)
- overlays += image('icons/obj/food.dmi', "[i][D.overlay_state]")
+ add_overlay("[i][D.overlay_state]")
i++
/obj/item/weapon/storage/box/donut/empty
diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm
index 436b1da8c6f..957a3c73f68 100644
--- a/code/game/objects/items/weapons/storage/secure.dm
+++ b/code/game/objects/items/weapons/storage/secure.dm
@@ -111,15 +111,15 @@
src.l_set = 1
else if ((src.code == src.l_code) && (src.emagged == 0) && (src.l_set == 1))
src.locked = 0
- src.overlays = null
- overlays += image('icons/obj/storage.dmi', icon_opened)
+ cut_overlays()
+ add_overlay(icon_opened)
src.code = null
else
src.code = "ERROR"
else
if ((digit == "R") && (src.emagged == 0) && (!src.l_setshort))
src.locked = 1
- src.overlays = null
+ cut_overlays()
src.code = null
src.close(usr)
else
@@ -133,10 +133,10 @@
/obj/item/weapon/storage/secure/emag_act(var/remaining_charges, var/mob/user, var/feedback)
if(!emagged)
emagged = 1
- src.overlays += image('icons/obj/storage.dmi', icon_sparking)
+ src.add_overlay(icon_sparking)
sleep(6)
- src.overlays = null
- overlays += image('icons/obj/storage.dmi', icon_locking)
+ cut_overlays()
+ add_overlay(icon_locking)
locked = 0
to_chat(user, (feedback ? feedback : "You short out the lock of \the [src]."))
return 1
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 72070edf31b..66e23467d5a 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -226,7 +226,7 @@
var/stored_cap_width = 4 //length of sprite for start and end of the box representing the stored item
var/storage_width = min( round( 224 * max_storage_space/baseline_max_storage_space ,1) ,274) //length of sprite for the box representing total storage space
- storage_start.overlays.Cut()
+ storage_start.cut_overlays()
var/matrix/M = matrix()
M.Scale((storage_width-storage_cap_width*2+3)/32,1)
@@ -253,9 +253,9 @@
src.stored_start.transform = M_start
src.stored_continue.transform = M_continue
src.stored_end.transform = M_end
- storage_start.overlays += src.stored_start
- storage_start.overlays += src.stored_continue
- storage_start.overlays += src.stored_end
+ storage_start.add_overlay(stored_start)
+ storage_start.add_overlay(stored_continue)
+ storage_start.add_overlay(stored_end)
O.screen_loc = "4:[round((startpoint+endpoint)/2)+2],2:16"
O.maptext = ""
@@ -701,7 +701,7 @@
var/closed_state
/obj/item/weapon/storage/trinketbox/update_icon()
- overlays.Cut()
+ cut_overlays()
if(open)
icon_state = open_state
@@ -714,7 +714,7 @@
else if(istype(contents[1], /obj/item/clothing/accessory/medal))
contained_image = "medal_trinket"
if(contained_image)
- overlays += contained_image
+ add_overlay(contained_image)
else
icon_state = closed_state
diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm
index 90b465efaea..4161ae740b9 100644
--- a/code/game/objects/items/weapons/storage/wallets.dm
+++ b/code/game/objects/items/weapons/storage/wallets.dm
@@ -67,14 +67,14 @@
update_icon()
/obj/item/weapon/storage/wallet/update_icon()
- overlays.Cut()
+ cut_overlays()
if(front_id)
var/tiny_state = "id-generic"
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
- overlays += tiny_image
+ add_overlay(tiny_image)
/obj/item/weapon/storage/wallet/GetID()
return front_id
diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm
index ad3c856f973..6fc53235b55 100644
--- a/code/game/objects/items/weapons/swords_axes_etc.dm
+++ b/code/game/objects/items/weapons/swords_axes_etc.dm
@@ -85,14 +85,14 @@
add_fingerprint(user)
if(blood_overlay && blood_DNA && (blood_DNA.len >= 1)) //updates blood overlay, if any
- overlays.Cut()//this might delete other item overlays as well but eeeeeeeh
+ cut_overlays()
var/icon/I = new /icon(src.icon, src.icon_state)
I.Blend(new /icon('icons/effects/blood.dmi', rgb(255,255,255)),ICON_ADD)
I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY)
blood_overlay = I
- overlays += blood_overlay
+ add_overlay(blood_overlay)
return
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index abe2db0d532..bd6f3842803 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -138,7 +138,7 @@ var/list/global/tank_gauge_cache = list()
to_chat(user, "You carefully begin clipping the wires that attach to the tank.")
if(do_after(user, 100,src))
wired = 0
- src.overlays -= "bomb_assembly"
+ cut_overlay("bomb_assembly")
to_chat(user, "You cut the wire and remove the device.")
var/obj/item/device/assembly_holder/assy = src.proxyassembly.assembly
@@ -153,7 +153,7 @@ var/list/global/tank_gauge_cache = list()
assy.a_right = null
src.proxyassembly.assembly = null
qdel(assy)
- src.overlays.Cut()
+ cut_overlays()
last_gauge_pressure = 0
update_gauge()
@@ -166,7 +166,7 @@ var/list/global/tank_gauge_cache = list()
if(do_after(user, 10, src))
to_chat(user, "You quickly clip the wire from the tank.")
wired = 0
- src.overlays -= "bomb_assembly"
+ cut_overlay("bomb_assembly")
else
to_chat(user, "There are no wires to cut!")
@@ -352,12 +352,12 @@ var/list/global/tank_gauge_cache = list()
/obj/item/weapon/tank/proc/add_bomb_overlay()
if(src.wired)
- src.overlays += "bomb_assembly"
+ add_overlay("bomb_assembly")
if(src.proxyassembly.assembly)
var/icon/test = getFlatIcon(src.proxyassembly.assembly)
test.Shift(SOUTH,1)
test.Shift(WEST,3)
- overlays += test
+ add_overlay(test)
/obj/item/weapon/tank/proc/update_gauge()
@@ -373,12 +373,12 @@ var/list/global/tank_gauge_cache = list()
return
last_gauge_pressure = gauge_pressure
- overlays.Cut()
+ cut_overlays()
add_bomb_overlay()
var/indicator = "[gauge_icon][(gauge_pressure == -1) ? "overload" : gauge_pressure]"
if(!tank_gauge_cache[indicator])
tank_gauge_cache[indicator] = image(icon, indicator)
- overlays += tank_gauge_cache[indicator]
+ add_overlay(tank_gauge_cache[indicator])
@@ -562,7 +562,7 @@ var/list/global/tank_gauge_cache = list()
H.update_icon()
- src.overlays += "bomb_assembly"
+ add_overlay("bomb_assembly")
/obj/item/weapon/tank/phoron/onetankbomb/New()
@@ -658,10 +658,10 @@ var/list/global/tank_gauge_cache = list()
/obj/item/device/tankassemblyproxy/update_icon()
if(assembly)
tank.update_icon()
- tank.overlays += "bomb_assembly"
+ tank.add_overlay("bomb_assembly")
else
tank.update_icon()
- tank.overlays -= "bomb_assembly"
+ tank.cut_overlay("bomb_assembly")
/obj/item/device/tankassemblyproxy/HasProximity(turf/T, atom/movable/AM, old_loc)
assembly?.HasProximity(T, AM, old_loc)
diff --git a/code/game/objects/items/weapons/tools/weldingtool.dm b/code/game/objects/items/weapons/tools/weldingtool.dm
index af92a574545..46d2b50f13a 100644
--- a/code/game/objects/items/weapons/tools/weldingtool.dm
+++ b/code/game/objects/items/weapons/tools/weldingtool.dm
@@ -208,11 +208,10 @@
/obj/item/weapon/weldingtool/update_icon()
..()
- overlays.Cut()
+ cut_overlays()
// Welding overlay.
if(welding)
- var/image/I = image(icon, src, "[icon_state]-on")
- overlays.Add(I)
+ add_overlay("[icon_state]-on")
item_state = "[initial(item_state)]1"
else
item_state = initial(item_state)
@@ -221,8 +220,7 @@
if(change_icons && get_max_fuel())
var/ratio = get_fuel() / get_max_fuel()
ratio = CEILING(ratio * 4, 1) * 25
- var/image/I = image(icon, src, "[icon_state][ratio]")
- overlays.Add(I)
+ add_overlay("[icon_state][ratio]")
// Lights
if(welding && flame_intensity)
diff --git a/code/game/objects/items/weapons/trays.dm b/code/game/objects/items/weapons/trays.dm
index 6809ae45470..3215af0a102 100644
--- a/code/game/objects/items/weapons/trays.dm
+++ b/code/game/objects/items/weapons/trays.dm
@@ -19,7 +19,7 @@
/obj/item/weapon/tray/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
user.setClickCooldown(user.get_attack_speed(src))
// Drop all the things. All of them.
- overlays.Cut()
+ cut_overlays()
for(var/obj/item/I in carrying)
I.loc = M.loc
carrying.Remove(I)
@@ -193,7 +193,7 @@
var/obj/item/weapon/material/O = I
if(O.applies_material_colour)
Img.color = O.color
- overlays += Img
+ add_overlay(Img)
/obj/item/weapon/tray/dropped(mob/user)
var/noTable = null
@@ -203,7 +203,7 @@
noTable = 1
if(isturf(loc) && !(locate(/mob/living) in src.loc))
- overlays.Cut()
+ cut_overlays()
for(var/obj/item/I in carrying)
I.forceMove(src.loc)
carrying.Remove(I)
diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm
index e332ed40f74..06a5e75fd12 100644
--- a/code/game/objects/random/mapping.dm
+++ b/code/game/objects/random/mapping.dm
@@ -1345,6 +1345,28 @@
/obj/random/multiple/large_corp_crate
)
)
+//VOREStation Add - Random good, no guns gooder
+/obj/random/multiple/random_size_crate/no_weapons
+ name = "random size corporate crate (no weapons)"
+ desc = "A random size corporate crate with thematic contents: prefers small crates."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "largermetal"
+ spawn_nothing_percentage = 50
+
+/obj/random/multiple/random_size_crate/no_weapons/item_to_spawn()
+ return pick(
+ prob(85);list(
+ /obj/random/multiple/corp_crate/no_weapons
+ ),
+ prob(15);list(
+ /obj/random/multiple/large_corp_crate/no_weapons
+ )
+ )
+
+/obj/random/multiple/random_size_crate/no_weapons/nofail
+ spawn_nothing_percentage = 0
+
+//VOREStation Add End
/*
* Turf swappers.
*/
diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm
index 833617861c9..1827af8df83 100644
--- a/code/game/objects/random/misc.dm
+++ b/code/game/objects/random/misc.dm
@@ -249,6 +249,7 @@
prob(8);/obj/item/weapon/storage/firstaid/o2,
prob(6);/obj/item/weapon/storage/firstaid/adv,
prob(8);/obj/item/weapon/storage/firstaid/fire,
+ prob(1);/obj/item/device/denecrotizer/medical, //VOREStation Add,
prob(1);/obj/item/weapon/storage/firstaid/combat)
/obj/random/contraband
diff --git a/code/game/objects/random/misc_vr.dm b/code/game/objects/random/misc_vr.dm
index d8c3df7af0f..0d3a17c23f2 100644
--- a/code/game/objects/random/misc_vr.dm
+++ b/code/game/objects/random/misc_vr.dm
@@ -8,4 +8,44 @@
/obj/random/explorer_shield/item_to_spawn()
return pick(/obj/item/weapon/shield/riot/explorer,
- /obj/item/weapon/shield/riot/explorer/purple)
\ No newline at end of file
+ /obj/item/weapon/shield/riot/explorer/purple)
+
+/obj/random/awayloot
+ name = "random away mission loot"
+ desc = "A list of things that people can find in away missions."
+ icon = 'icons/mob/randomlandmarks.dmi'
+ icon_state = "awayloot"
+ spawn_nothing_percentage = 50
+
+/obj/random/awayloot/item_to_spawn()
+ return pick(prob(50);/obj/item/weapon/aliencoin,
+ prob(40);/obj/item/weapon/aliencoin/silver,
+ prob(30);/obj/item/weapon/aliencoin/gold,
+ prob(20);/obj/item/weapon/aliencoin/phoron,
+ prob(10);/obj/item/device/denecrotizer,
+ prob(5);/obj/item/device/perfect_tele,
+ prob(5);/obj/item/weapon/bluespace_harpoon,
+ prob(1);/obj/item/weapon/cell/infinite,
+ prob(1);/obj/item/weapon/cell/void,
+ prob(1);/obj/item/weapon/cell/device/weapon/recharge/alien,
+ prob(1);/obj/item/clothing/shoes/boots/speed,
+ prob(1);/obj/item/device/nif,
+ prob(1);/obj/item/device/paicard,
+ prob(2);/obj/item/weapon/storage/backpack/dufflebag/syndie,
+ prob(2);/obj/item/weapon/storage/backpack/dufflebag/syndie/ammo,
+ prob(2);/obj/item/weapon/storage/backpack/dufflebag/syndie/med,
+ prob(2);/obj/item/clothing/mask/gas/voice,
+ prob(2);/obj/item/device/radio_jammer,
+ prob(1);/obj/item/toy/bosunwhistle,
+ prob(1);/obj/item/weapon/bananapeel,
+ prob(5);/obj/fiftyspawner/platinum,
+ prob(3);/obj/fiftyspawner/gold,
+ prob(3);/obj/fiftyspawner/silver,
+ prob(1);/obj/fiftyspawner/diamond,
+ prob(5);/obj/fiftyspawner/phoron,
+ prob(1);/obj/item/weapon/telecube/randomized
+ )
+
+/obj/random/awayloot/nofail
+ name = "garunteed random away mission loot"
+ spawn_nothing_percentage = 0
diff --git a/code/game/objects/random/spacesuits.dm b/code/game/objects/random/spacesuits.dm
index da380f28425..2d394625b94 100644
--- a/code/game/objects/random/spacesuits.dm
+++ b/code/game/objects/random/spacesuits.dm
@@ -257,4 +257,8 @@
prob(5);/obj/item/weapon/rig/eva,
prob(4);/obj/item/weapon/rig/light/stealth,
prob(3);/obj/item/weapon/rig/hazard,
- prob(1);/obj/item/weapon/rig/merc/empty)
\ No newline at end of file
+ prob(1);/obj/item/weapon/rig/merc/empty)
+//VOREStation Add Start
+/obj/random/rigsuit/chancetofail
+ spawn_nothing_percentage = 50
+//VOREStation Add End
\ No newline at end of file
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index f81419be75e..87332c776f0 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -1,6 +1,7 @@
/obj/structure
icon = 'icons/obj/structures.dmi'
w_class = ITEMSIZE_NO_CONTAINER
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC
var/climbable
var/climb_delay = 3.5 SECONDS
diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm
index f07fb8d1dc3..8b1780f077c 100644
--- a/code/game/objects/structures/bonfire.dm
+++ b/code/game/objects/structures/bonfire.dm
@@ -184,7 +184,7 @@
L.IgniteMob()
/obj/structure/bonfire/update_icon()
- overlays.Cut()
+ cut_overlays()
if(burning)
var/state
switch(get_fuel_amount())
@@ -194,14 +194,14 @@
state = "bonfire_hot"
var/image/I = image(icon, state)
I.appearance_flags = RESET_COLOR
- overlays += I
+ add_overlay(I)
if(has_buckled_mobs() && get_fuel_amount() >= 5)
I = image(icon, "bonfire_intense")
I.pixel_y = 13
I.layer = MOB_LAYER + 0.1
I.appearance_flags = RESET_COLOR
- overlays += I
+ add_overlay(I)
var/light_strength = max(get_fuel_amount() / 2, 2)
set_light(light_strength, light_strength, "#FF9933")
@@ -211,7 +211,7 @@
if(grill)
var/image/grille_image = image(icon, "bonfire_grill")
grille_image.appearance_flags = RESET_COLOR
- overlays += grille_image
+ add_overlay(grille_image)
/obj/structure/bonfire/process()
@@ -373,7 +373,7 @@
O.fire_act(null, 1000, 500)
/obj/structure/fireplace/update_icon()
- overlays.Cut()
+ cut_overlays()
if(burning)
var/state
switch(get_fuel_amount())
@@ -385,7 +385,7 @@
state = "fireplace_intense" //don't need to throw a corpse inside to make it burn hotter.
var/image/I = image(icon, state)
I.appearance_flags = RESET_COLOR
- overlays += I
+ add_overlay(I)
var/light_strength = max(get_fuel_amount() / 2, 2)
set_light(light_strength, light_strength, "#FF9933")
diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm
index 848168dd08e..9da45df7beb 100644
--- a/code/game/objects/structures/coathanger.dm
+++ b/code/game/objects/structures/coathanger.dm
@@ -43,10 +43,10 @@
return 1
/obj/structure/coatrack/update_icon()
- overlays.Cut()
+ cut_overlays()
if (istype(coat, /obj/item/clothing/suit/storage/toggle/labcoat))
- overlays += image(icon, icon_state = "coat_lab")
+ add_overlay("coat_lab")
if (istype(coat, /obj/item/clothing/suit/storage/toggle/labcoat/cmo))
- overlays += image(icon, icon_state = "coat_cmo")
+ add_overlay("coat_cmo")
if (istype(coat, /obj/item/clothing/suit/storage/det_trench))
- overlays += image(icon, icon_state = "coat_det")
+ add_overlay("coat_det")
diff --git a/code/game/objects/structures/crates_lockers/__closets.dm b/code/game/objects/structures/crates_lockers/__closets.dm
index 85e45314de4..f111d191968 100644
--- a/code/game/objects/structures/crates_lockers/__closets.dm
+++ b/code/game/objects/structures/crates_lockers/__closets.dm
@@ -7,6 +7,7 @@
density = 1
w_class = ITEMSIZE_HUGE
layer = UNDER_JUNK_LAYER
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC
var/opened = 0
var/sealed = 0
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm
index b69a3ff368d..028f67f06d5 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm
@@ -14,9 +14,9 @@
update_icon()
/obj/structure/closet/secure_closet/guncabinet/update_icon()
- overlays.Cut()
+ cut_overlays()
if(opened)
- overlays += icon(icon,"door_open")
+ add_overlay("door_open")
else
var/lazors = 0
var/shottas = 0
@@ -35,17 +35,17 @@
shottas--
gun.icon_state = "projectile"
gun.pixel_x = i*4
- overlays += gun
+ add_overlay(gun)
- overlays += icon(src.icon, "door")
+ add_overlay("door")
if(sealed)
- overlays += icon(src.icon,"sealed")
+ add_overlay("sealed")
if(broken)
- overlays += icon(src.icon,"broken")
+ add_overlay("broken")
else if (locked)
- overlays += icon(src.icon,"locked")
+ add_overlay("locked")
else
- overlays += icon(src.icon,"open")
+ add_overlay("open")
diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm
index 2ea6372aef3..dc6e92355d7 100644
--- a/code/game/objects/structures/crates_lockers/closets/statue.dm
+++ b/code/game/objects/structures/crates_lockers/closets/statue.dm
@@ -6,6 +6,7 @@
density = 1
anchored = 1
health = 0 //destroying the statue kills the mob within
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
var/intialTox = 0 //these are here to keep the mob from taking damage from things that logically wouldn't affect a rock
var/intialFire = 0 //it's a little sloppy I know but it was this or the GODMODE flag. Lesser of two evils.
var/intialBrute = 0
@@ -43,7 +44,7 @@
qdel(src)
return
- START_PROCESSING(SSobj, src)
+ START_PROCESSING(SSobj, src)
..()
/obj/structure/closet/statue/process()
diff --git a/code/game/objects/structures/crates_lockers/vehiclecage.dm b/code/game/objects/structures/crates_lockers/vehiclecage.dm
index b98636eb16c..31862846ff1 100644
--- a/code/game/objects/structures/crates_lockers/vehiclecage.dm
+++ b/code/game/objects/structures/crates_lockers/vehiclecage.dm
@@ -44,13 +44,13 @@
/obj/structure/vehiclecage/update_icon()
..()
- overlays.Cut()
+ cut_overlays()
underlays.Cut()
var/image/framepaint = new(icon = 'icons/obj/storage.dmi', icon_state = "[initial(icon_state)]_a", layer = MOB_LAYER + 1.1)
framepaint.plane = MOB_PLANE
framepaint.color = paint_color
- overlays += framepaint
+ add_overlay(framepaint)
for(var/obj/vehicle/V in src.contents)
var/image/showcase = new(V)
diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm
index b3f174e25a5..ca515e230f8 100644
--- a/code/game/objects/structures/electricchair.dm
+++ b/code/game/objects/structures/electricchair.dm
@@ -6,9 +6,9 @@
var/obj/item/assembly/shock_kit/part = null
var/last_time = 1.0
-/obj/structure/bed/chair/e_chair/New()
- ..()
- overlays += image('icons/obj/objects.dmi', src, "echair_over", MOB_LAYER + 1, dir)
+/obj/structure/bed/chair/e_chair/Initialize()
+ . = ..()
+ add_overlay(image('icons/obj/objects.dmi', src, "echair_over", MOB_LAYER + 1, dir))
return
/obj/structure/bed/chair/e_chair/attackby(obj/item/weapon/W as obj, mob/user as mob)
@@ -39,8 +39,8 @@
/obj/structure/bed/chair/e_chair/rotate_clockwise()
..()
- overlays.Cut()
- overlays += image('icons/obj/objects.dmi', src, "echair_over", MOB_LAYER + 1, dir) //there's probably a better way of handling this, but eh. -Pete
+ cut_overlays()
+ add_overlay(image('icons/obj/objects.dmi', src, "echair_over", MOB_LAYER + 1, dir)) //there's probably a better way of handling this, but eh. -Pete
return
/obj/structure/bed/chair/e_chair/proc/shock()
diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm
index 729e578ba58..f41fbfa8cf8 100644
--- a/code/game/objects/structures/fitness.dm
+++ b/code/game/objects/structures/fitness.dm
@@ -29,6 +29,7 @@
name = "weightlifting machine"
desc = "A machine used to lift weights."
icon_state = "weightlifter"
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
var/weight = 1
var/list/qualifiers = list("with ease", "without any trouble", "with great effort")
diff --git a/code/game/objects/structures/flora/flora.dm b/code/game/objects/structures/flora/flora.dm
index 9195de1767f..e73e2a17580 100644
--- a/code/game/objects/structures/flora/flora.dm
+++ b/code/game/objects/structures/flora/flora.dm
@@ -313,6 +313,7 @@
light_range = 2
light_power = 0.6
light_color = "#33CCFF"
+ light_on = TRUE
catalogue_data = list(/datum/category_item/catalogue/flora/sif_tree)
/obj/structure/flora/pottedplant/orientaltree
@@ -372,6 +373,7 @@
light_range = 2
light_power = 0.6
light_color = "#FF6633"
+ light_on = TRUE
/obj/structure/flora/pottedplant/minitree
name = "potted tree"
@@ -439,6 +441,7 @@
light_range = 2
light_power = 0.6
light_color = "#FF6633"
+ light_on = TRUE
catalogue_data = list(/datum/category_item/catalogue/flora/subterranean_bulbs)
/obj/structure/flora/sif/subterranean/Initialize()
diff --git a/code/game/objects/structures/flora/moretrees_vr.dm b/code/game/objects/structures/flora/moretrees_vr.dm
new file mode 100644
index 00000000000..57947139bb2
--- /dev/null
+++ b/code/game/objects/structures/flora/moretrees_vr.dm
@@ -0,0 +1,22 @@
+/obj/structure/flora/tree/bigtree
+ icon = 'icons/obj/flora/moretrees_vr.dmi'
+ icon_state = "bigtree1"
+ base_state = "tree"
+ product = /obj/item/stack/material/log
+ product_amount = 20
+ health = 2000
+ max_health = 2000
+ pixel_x = -65
+ pixel_y = -8
+ layer = MOB_LAYER - 1
+ shake_animation_degrees = 2
+
+/obj/structure/flora/tree/bigtree/choose_icon_state()
+ return "[base_state][rand(1, 4)]"
+
+/obj/structure/flora/tree/bigtree/Initialize()
+ . = ..()
+
+ var/image/i = image('icons/obj/flora/moretrees_vr.dmi', "[icon_state]-b")
+ i.plane = ABOVE_MOB_PLANE
+ add_overlay(i)
\ No newline at end of file
diff --git a/code/game/objects/structures/flora/trees.dm b/code/game/objects/structures/flora/trees.dm
index a9f3658ff6e..2ced6ba550c 100644
--- a/code/game/objects/structures/flora/trees.dm
+++ b/code/game/objects/structures/flora/trees.dm
@@ -115,7 +115,7 @@
is_stump = TRUE
density = FALSE
icon_state = "[base_state]_stump"
- overlays.Cut() // For the Sif tree and other future glowy trees.
+ cut_overlays() // For the Sif tree and other future glowy trees.
set_light(0)
/obj/structure/flora/tree/ex_act(var/severity)
@@ -265,6 +265,7 @@
icon = 'icons/obj/flora/deadtrees.dmi'
icon_state = "tree_sif"
base_state = "tree_sif"
+ blocks_emissive = FALSE
product = /obj/item/stack/material/log/sif
catalogue_data = list(/datum/category_item/catalogue/flora/sif_tree)
randomize_size = TRUE
@@ -289,7 +290,10 @@
update_icon()
/obj/structure/flora/tree/sif/update_icon()
- set_light(5 - light_shift, 1, "#33ccff") // 5 variants, missing bulbs. 5th has no bulbs, so no glow.
- var/image/glow = image(icon = icon, icon_state = "[base_state][light_shift]_glow")
- glow.plane = PLANE_LIGHTING_ABOVE
- overlays = list(glow)
+ cut_overlays()
+ var/bulbs = (5 - light_shift)
+ if(bulbs > 0)
+ set_light(bulbs, 1, "#33ccff") // 5 variants, missing bulbs. 5th has no bulbs, so no glow.
+ add_overlay(mutable_appearance(icon, "[base_state][bulbs]_glow"))
+ add_overlay(emissive_appearance(icon, "[base_state][bulbs]_glow"))
+
\ No newline at end of file
diff --git a/code/game/objects/structures/holoplant.dm b/code/game/objects/structures/holoplant.dm
index dbd39361d6e..01a0436be93 100644
--- a/code/game/objects/structures/holoplant.dm
+++ b/code/game/objects/structures/holoplant.dm
@@ -46,12 +46,13 @@
return
plant = prepare_icon(emagged ? "emagged" : null)
- overlays = list(plant)
+ cut_overlays()
+ add_overlay(plant)
set_light(2)
update_use_power(USE_POWER_ACTIVE)
/obj/machinery/holoplant/proc/deactivate()
- overlays.Cut()
+ cut_overlays()
QDEL_NULL(plant)
set_light(0)
update_use_power(USE_POWER_OFF)
@@ -66,16 +67,16 @@
/obj/machinery/holoplant/proc/flicker()
interference = TRUE
spawn(0)
- overlays.Cut()
+ cut_overlays()
set_light(0)
sleep(rand(2,4))
- overlays = list(plant)
+ add_overlay(plant)
set_light(2)
sleep(rand(2,4))
- overlays.Cut()
+ cut_overlays()
set_light(0)
sleep(rand(2,4))
- overlays = list(plant)
+ add_overlay(plant)
set_light(2)
interference = FALSE
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index a6dc8e42ac4..fba31409f51 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -288,22 +288,22 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
return TRUE
/obj/structure/janitorialcart/update_icon()
- overlays.Cut()
+ cut_overlays()
if(mybucket)
- overlays += "cart_bucket"
+ add_overlay("cart_bucket")
if(mybucket.reagents.total_volume >= 1)
- overlays += "water_cart"
+ add_overlay("water_cart")
if(mybag)
- overlays += "cart_garbage"
+ add_overlay("cart_garbage")
if(mymop)
- overlays += "cart_mop"
+ add_overlay("cart_mop")
if(myspray)
- overlays += "cart_spray"
+ add_overlay("cart_spray")
if(myreplacer)
- overlays += "cart_replacer"
+ add_overlay("cart_replacer")
if(signs)
- overlays += "cart_sign[signs]"
+ add_overlay("cart_sign[signs]")
//This is called if the cart is caught in an explosion, or destroyed by weapon fire
/obj/structure/janitorialcart/proc/spill(var/chance = 100)
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index b8597d6d292..8c1879ec80a 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -82,7 +82,7 @@
//if(!(istype(src.loc, /turf/space)))
// qdel(src)
spawn(1)
- overlays = list()
+ cut_overlays()
var/dir_sum = 0
diff --git a/code/game/objects/structures/medical_stand_vr.dm b/code/game/objects/structures/medical_stand_vr.dm
index eb3031eca80..3ca9999f85f 100644
--- a/code/game/objects/structures/medical_stand_vr.dm
+++ b/code/game/objects/structures/medical_stand_vr.dm
@@ -29,32 +29,32 @@
update_icon()
/obj/structure/medical_stand/update_icon()
- overlays.Cut()
+ cut_overlays()
if (tank)
if (breather)
- overlays += "tube_active"
+ add_overlay("tube_active")
else
- overlays += "tube"
+ add_overlay("tube")
if(istype(tank,/obj/item/weapon/tank/anesthetic))
- overlays += "tank_anest"
+ add_overlay("tank_anest")
else if(istype(tank,/obj/item/weapon/tank/nitrogen))
- overlays += "tank_nitro"
+ add_overlay("tank_nitro")
else if(istype(tank,/obj/item/weapon/tank/oxygen))
- overlays += "tank_oxyg"
+ add_overlay("tank_oxyg")
else if(istype(tank,/obj/item/weapon/tank/phoron))
- overlays += "tank_plasma"
+ add_overlay("tank_plasma")
//else if(istype(tank,/obj/item/weapon/tank/hydrogen))
- // overlays += "tank_hydro"
+ // add_overlay("tank_hydro")
else
- overlays += "tank_other"
+ add_overlay("tank_other")
if(beaker)
- overlays += "beaker"
+ add_overlay("beaker")
if(attached)
- overlays += "line_active"
+ add_overlay("line_active")
else
- overlays += "line"
+ add_overlay("line")
var/datum/reagents/reagents = beaker.reagents
var/percent = round((reagents.total_volume / beaker.volume) * 100)
if(reagents.total_volume)
@@ -69,7 +69,7 @@
if(91 to INFINITY) filling.icon_state = "reagent100"
if (filling.icon)
filling.icon += reagents.get_color()
- overlays += filling
+ add_overlay(filling)
/obj/structure/medical_stand/Destroy()
STOP_PROCESSING(SSobj,src)
diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm
index 5a4ce00a8ce..e039f7806f9 100644
--- a/code/game/objects/structures/railing.dm
+++ b/code/game/objects/structures/railing.dm
@@ -108,27 +108,27 @@
/obj/structure/railing/update_icon(var/UpdateNeighgors = 1)
NeighborsCheck(UpdateNeighgors)
//layer = (dir == SOUTH) ? FLY_LAYER : initial(layer) // wtf does this even do
- overlays.Cut()
+ cut_overlays()
if (!check || !anchored)//|| !anchored
icon_state = "[icon_modifier]railing0"
else
icon_state = "[icon_modifier]railing1"
if (check & 32)
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]corneroverlay")
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]corneroverlay"))
if ((check & 16) || !(check & 32) || (check & 64))
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]frontoverlay_l")
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]frontoverlay_l"))
if (!(check & 2) || (check & 1) || (check & 4))
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]frontoverlay_r")
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]frontoverlay_r"))
if(check & 4)
switch (src.dir)
if (NORTH)
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_x = 32)
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_x = 32))
if (SOUTH)
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_x = -32)
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_x = -32))
if (EAST)
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_y = -32)
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_y = -32))
if (WEST)
- overlays += image ('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_y = 32)
+ add_overlay(image('icons/obj/railing.dmi', src, "[icon_modifier]mcorneroverlay", pixel_y = 32))
/obj/structure/railing/verb/rotate_counterclockwise()
set name = "Rotate Railing Counter-Clockwise"
diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm
index 19ae278730d..6fe2aa384ad 100644
--- a/code/game/objects/structures/simple_doors.dm
+++ b/code/game/objects/structures/simple_doors.dm
@@ -12,7 +12,7 @@
var/isSwitchingStates = 0
var/hardness = 1
var/oreAmount = 7
-
+
/obj/structure/simple_door/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
TemperatureAct(exposed_temperature)
@@ -20,13 +20,22 @@
hardness -= material.combustion_effect(get_turf(src),temperature, 0.3)
CheckHardness()
-/obj/structure/simple_door/New(var/newloc, var/material_name)
- ..()
+/obj/structure/simple_door/Initialize(mapload, var/material_name)
+ . = ..()
+ set_material(material_name)
+ if(!material)
+ return INITIALIZE_HINT_QDEL
+
+/obj/structure/simple_door/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ update_nearby_tiles()
+ return ..()
+
+/obj/structure/simple_door/proc/set_material(var/material_name)
if(!material_name)
material_name = DEFAULT_WALL_MATERIAL
material = get_material_by_name(material_name)
if(!material)
- qdel(src)
return
hardness = max(1,round(material.integrity/10))
icon_state = material.door_icon_base
@@ -40,11 +49,6 @@
START_PROCESSING(SSobj, src)
update_nearby_tiles(need_rebuild=1)
-/obj/structure/simple_door/Destroy()
- STOP_PROCESSING(SSobj, src)
- update_nearby_tiles()
- return ..()
-
/obj/structure/simple_door/get_material()
return material
@@ -198,38 +202,38 @@
return
SSradiation.radiate(src, round(material.radioactivity/3))
-/obj/structure/simple_door/iron/New(var/newloc,var/material_name)
- ..(newloc, "iron")
+/obj/structure/simple_door/iron/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "iron")
-/obj/structure/simple_door/silver/New(var/newloc,var/material_name)
- ..(newloc, "silver")
+/obj/structure/simple_door/silver/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "silver")
-/obj/structure/simple_door/gold/New(var/newloc,var/material_name)
- ..(newloc, "gold")
+/obj/structure/simple_door/gold/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "gold")
-/obj/structure/simple_door/uranium/New(var/newloc,var/material_name)
- ..(newloc, "uranium")
+/obj/structure/simple_door/uranium/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "uranium")
-/obj/structure/simple_door/sandstone/New(var/newloc,var/material_name)
- ..(newloc, "sandstone")
+/obj/structure/simple_door/sandstone/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "sandstone")
-/obj/structure/simple_door/phoron/New(var/newloc,var/material_name)
- ..(newloc, "phoron")
+/obj/structure/simple_door/phoron/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "phoron")
-/obj/structure/simple_door/diamond/New(var/newloc,var/material_name)
- ..(newloc, "diamond")
+/obj/structure/simple_door/diamond/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "diamond")
-/obj/structure/simple_door/wood/New(var/newloc,var/material_name)
- ..(newloc, MAT_WOOD)
+/obj/structure/simple_door/wood/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || MAT_WOOD)
-/obj/structure/simple_door/sifwood/New(var/newloc,var/material_name)
- ..(newloc, MAT_SIFWOOD)
+/obj/structure/simple_door/sifwood/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || MAT_SIFWOOD)
-/obj/structure/simple_door/resin/New(var/newloc,var/material_name)
- ..(newloc, "resin")
+/obj/structure/simple_door/resin/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "resin")
-/obj/structure/simple_door/cult/New(var/newloc,var/material_name)
- ..(newloc, "cult")
+/obj/structure/simple_door/cult/Initialize(mapload,var/material_name)
+ ..(mapload, material_name || "cult")
/obj/structure/simple_door/cult/TryToSwitchState(atom/user)
if(isliving(user))
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index 15919a754a5..9a2b18e8c66 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -28,13 +28,13 @@
update_icon()
/obj/structure/dispenser/update_icon()
- overlays.Cut()
+ cut_overlays()
switch(oxygentanks)
- if(1 to 3) overlays += "oxygen-[oxygentanks]"
- if(4 to INFINITY) overlays += "oxygen-4"
+ if(1 to 3) add_overlay("oxygen-[oxygentanks]")
+ if(4 to INFINITY) add_overlay("oxygen-4")
switch(phorontanks)
- if(1 to 4) overlays += "phoron-[phorontanks]"
- if(5 to INFINITY) overlays += "phoron-5"
+ if(1 to 4) add_overlay("phoron-[phorontanks]")
+ if(5 to INFINITY) add_overlay("phoron-5")
/obj/structure/dispenser/attack_ai(mob/user)
// This looks silly, but robots also call attack_ai, and they're allowed physical state stuff.
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 6b95d902111..47a37334435 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -179,13 +179,13 @@
add_fingerprint(user)
/obj/machinery/shower/update_icon() //this is terribly unreadable, but basically it makes the shower mist up
- overlays.Cut() //once it's been on for a while, in addition to handling the water overlay.
+ cut_overlay() //once it's been on for a while, in addition to handling the water overlay.
if(mymist)
qdel(mymist)
mymist = null
if(on)
- overlays += image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir)
+ add_overlay(image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir))
if(temperature_settings[watertemp] < T20C)
return //no mist for cold water
if(!ismist)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 2cf49eb2b53..2ae7c7adfcc 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -1,689 +1,695 @@
-/obj/structure/window
- name = "window"
- desc = "A window."
- icon = 'icons/obj/structures_vr.dmi' // VOREStation Edit - New icons
- density = 1
- can_atmos_pass = ATMOS_PASS_PROC
- w_class = ITEMSIZE_NORMAL
-
- layer = WINDOW_LAYER
- pressure_resistance = 4*ONE_ATMOSPHERE
- anchored = 1.0
- flags = ON_BORDER
- var/maxhealth = 14.0
- var/maximal_heat = T0C + 100 // Maximal heat before this window begins taking damage from fire
- var/damage_per_fire_tick = 2.0 // Amount of damage per fire tick. Regular windows are not fireproof so they might as well break quickly.
- var/health
- var/force_threshold = 0
- var/ini_dir = null
- var/state = 2
- var/reinf = 0
- var/basestate
- var/shardtype = /obj/item/weapon/material/shard
- var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass.
- var/silicate = 0 // number of units of silicate
- var/fulltile = FALSE // Set to true on full-tile variants.
-
-/obj/structure/window/examine(mob/user)
- . = ..()
-
- if(health == maxhealth)
- . += "It looks fully intact."
- else
- var/perc = health / maxhealth
- if(perc > 0.75)
- . += "It has a few cracks."
- else if(perc > 0.5)
- . += "It looks slightly damaged."
- else if(perc > 0.25)
- . += "It looks moderately damaged."
- else
- . += "It looks heavily damaged."
- if(silicate)
- if (silicate < 30)
- . += "It has a thin layer of silicate."
- else if (silicate < 70)
- . += "It is covered in silicate."
- 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
-
- if(silicate)
- damage = damage * (1 - silicate / 200)
-
- health = max(0, health - damage)
-
- if(health <= 0)
- shatter()
- else
- if(sound_effect)
- playsound(src, 'sound/effects/Glasshit.ogg', 100, 1)
- if(health < maxhealth / 4 && initialhealth >= maxhealth / 4)
- visible_message("[src] looks like it's about to shatter!" )
- update_icon()
- else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2)
- visible_message("[src] looks seriously damaged!" )
- update_icon()
- else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4)
- visible_message("Cracks begin to appear in [src]!" )
- update_icon()
- return
-
-/obj/structure/window/proc/apply_silicate(var/amount)
- if(health < maxhealth) // Mend the damage
- health = min(health + amount * 3, maxhealth)
- if(health == maxhealth)
- visible_message("[src] looks fully repaired." )
- else // Reinforce
- silicate = min(silicate + amount, 100)
- updateSilicate()
-
-/obj/structure/window/proc/updateSilicate()
- if (overlays)
- overlays.Cut()
- update_icon()
-
- var/image/img = image(src)
- img.color = "#ffffff"
- img.alpha = silicate * 255 / 100
- overlays += img
-
-/obj/structure/window/proc/shatter(var/display_message = 1)
- playsound(src, "shatter", 70, 1)
- if(display_message)
- visible_message("[src] shatters!")
- new shardtype(loc)
- if(reinf)
- new /obj/item/stack/rods(loc)
- if(is_fulltile())
- new shardtype(loc) //todo pooling?
- if(reinf)
- new /obj/item/stack/rods(loc)
- qdel(src)
- return
-
-
-/obj/structure/window/bullet_act(var/obj/item/projectile/Proj)
-
- var/proj_damage = Proj.get_structure_damage()
- if(!proj_damage) return
-
- ..()
- take_damage(proj_damage)
- return
-
-
-/obj/structure/window/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- shatter(0)
- return
- if(3.0)
- if(prob(50))
- shatter(0)
- return
-
-/obj/structure/window/blob_act()
- take_damage(50)
-
-/obj/structure/window/CanPass(atom/movable/mover, turf/target)
- if(istype(mover) && mover.checkpass(PASSGLASS))
- return TRUE
- if(is_fulltile())
- return FALSE //full tile window, you can't move into it!
- if((get_dir(loc, target) & dir) || (get_dir(mover, target) == turn(dir, 180)))
- return !density
- else
- return TRUE
-
-
-/obj/structure/window/CanZASPass(turf/T, is_zone)
- if(is_fulltile() || get_dir(T, loc) == turn(dir, 180)) // Make sure we're handling the border correctly.
- return !anchored // If it's anchored, it'll block air.
- return TRUE // Don't stop airflow from the other sides.
-
-/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf)
- if(istype(O) && O.checkpass(PASSGLASS))
- return 1
- if(get_dir(O.loc, target) == dir)
- return 0
- return 1
-
-/obj/structure/window/hitby(AM as mob|obj)
- ..()
- visible_message("[src] was hit by [AM].")
- var/tforce = 0
- if(ismob(AM))
- tforce = 40
- else if(isobj(AM))
- var/obj/item/I = AM
- tforce = I.throwforce
- if(reinf) tforce *= 0.25
- if(health - tforce <= 7 && !reinf)
- anchored = 0
- update_verbs()
- update_nearby_icons()
- step(src, get_dir(AM, src))
- take_damage(tforce)
-
-/obj/structure/window/attack_tk(mob/user as mob)
- user.visible_message("Something knocks on [src].")
- playsound(src, 'sound/effects/Glasshit.ogg', 50, 1)
-
-/obj/structure/window/attack_hand(mob/user as mob)
- user.setClickCooldown(user.get_attack_speed())
- if(HULK in user.mutations)
- user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
- user.visible_message("[user] smashes through [src]!")
- user.do_attack_animation(src)
- shatter()
-
- else if (usr.a_intent == I_HURT)
-
- if (istype(usr,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = usr
- if(H.species.can_shred(H))
- attack_generic(H,25)
- return
-
- playsound(src, 'sound/effects/glassknock.ogg', 80, 1)
- user.do_attack_animation(src)
- usr.visible_message("\The [usr] bangs against \the [src]!",
- "You bang against \the [src]!",
- "You hear a banging sound.")
- else
- playsound(src, 'sound/effects/glassknock.ogg', 80, 1)
- usr.visible_message("[usr.name] knocks on the [src.name].",
- "You knock on the [src.name].",
- "You hear a knocking sound.")
- return
-
-/obj/structure/window/attack_generic(var/mob/user, var/damage)
- user.setClickCooldown(user.get_attack_speed())
- if(!damage)
- return
- if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
- visible_message("[user] smashes into [src]!")
- if(reinf)
- damage = damage / 2
- take_damage(damage)
- else
- visible_message("\The [user] bonks \the [src] harmlessly.")
- user.do_attack_animation(src)
- return 1
-
-/obj/structure/window/attackby(obj/item/W as obj, mob/user as mob)
- if(!istype(W)) return//I really wish I did not need this
-
- // Fixing.
- if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP)
- var/obj/item/weapon/weldingtool/WT = W
- if(health < maxhealth)
- if(WT.remove_fuel(1 ,user))
- to_chat(user, "You begin repairing [src]...")
- playsound(src, WT.usesound, 50, 1)
- if(do_after(user, 40 * WT.toolspeed, target = src))
- health = maxhealth
- // playsound(src, 'sound/items/Welder.ogg', 50, 1)
- update_icon()
- to_chat(user, "You repair [src].")
- else
- to_chat(user, "[src] is already in good condition!")
- return
-
- // Slamming.
- if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
- var/obj/item/weapon/grab/G = W
- if(istype(G.affecting,/mob/living))
- var/mob/living/M = G.affecting
- var/state = G.state
- qdel(W) //gotta delete it here because if window breaks, it won't get deleted
- switch (state)
- if(1)
- M.visible_message("[user] slams [M] against \the [src]!")
- M.apply_damage(7)
- hit(10)
- if(2)
- M.visible_message("[user] bashes [M] against \the [src]!")
- if (prob(50))
- M.Weaken(1)
- M.apply_damage(10)
- hit(25)
- if(3)
- M.visible_message("[user] crushes [M] against \the [src]!")
- M.Weaken(5)
- M.apply_damage(20)
- hit(50)
- return
-
- if(W.flags & NOBLUDGEON) return
-
- if(W.is_screwdriver())
- if(reinf && state >= 1)
- state = 3 - state
- update_nearby_icons()
- playsound(src, W.usesound, 75, 1)
- to_chat(user, "You have [state == 1 ? "un" : ""]fastened the window [state ? "from" : "to"] the frame.")
- else if(reinf && state == 0)
- anchored = !anchored
- update_nearby_icons()
- update_verbs()
- playsound(src, W.usesound, 75, 1)
- to_chat(user, "You have [anchored ? "" : "un"]fastened the frame [anchored ? "to" : "from"] the floor.")
- else if(!reinf)
- anchored = !anchored
- update_nearby_icons()
- update_verbs()
- playsound(src, W.usesound, 75, 1)
- to_chat(user, "You have [anchored ? "" : "un"]fastened the window [anchored ? "to" : "from"] the floor.")
- else if(W.is_crowbar() && reinf && state <= 1)
- state = 1 - state
- playsound(src, W.usesound, 75, 1)
- to_chat(user, "You have pried the window [state ? "into" : "out of"] the frame.")
- else if(W.is_wrench() && !anchored && (!state || !reinf))
- if(!glasstype)
- to_chat(user, "You're not sure how to dismantle \the [src] properly.")
- else
- playsound(src, W.usesound, 75, 1)
- visible_message("[user] dismantles \the [src].")
- var/obj/item/stack/material/mats = new glasstype(loc)
- if(is_fulltile())
- mats.amount = 4
- qdel(src)
- else if(istype(W, /obj/item/stack/cable_coil) && reinf && state == 0 && !istype(src, /obj/structure/window/reinforced/polarized))
- var/obj/item/stack/cable_coil/C = W
- if (C.use(1))
- playsound(src, 'sound/effects/sparks1.ogg', 75, 1)
- user.visible_message( \
- "\The [user] begins to wire \the [src] for electrochromic tinting.", \
- "You begin to wire \the [src] for electrochromic tinting.", \
- "You hear sparks.")
- if(do_after(user, 20 * C.toolspeed, src) && state == 0)
- playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
- var/obj/structure/window/reinforced/polarized/P = new(loc, dir)
- if(is_fulltile())
- P.fulltile = TRUE
- P.icon_state = "fwindow"
- P.maxhealth = maxhealth
- P.health = health
- P.state = state
- P.anchored = anchored
- qdel(src)
- else if(istype(W,/obj/item/frame) && anchored)
- var/obj/item/frame/F = W
- F.try_build(src, user)
- else
- user.setClickCooldown(user.get_attack_speed(W))
- if(W.damtype == BRUTE || W.damtype == BURN)
- user.do_attack_animation(src)
- hit(W.force)
- if(health <= 7)
- anchored = 0
- update_nearby_icons()
- step(src, get_dir(user, src))
- else
- playsound(src, 'sound/effects/Glasshit.ogg', 75, 1)
- ..()
- return
-
-/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1)
- if(damage < force_threshold || force_threshold < 0)
- return
- if(reinf) damage *= 0.5
- take_damage(damage)
- return
-
-
-/obj/structure/window/verb/rotate_counterclockwise()
- set name = "Rotate Window Counterclockwise"
- set category = "Object"
- set src in oview(1)
-
- if(usr.incapacitated())
- return 0
-
- if(is_fulltile())
- return 0
-
- if(anchored)
- to_chat(usr, "It is fastened to the floor therefore you can't rotate it!")
- return 0
-
- update_nearby_tiles(need_rebuild=1) //Compel updates before
- src.set_dir(turn(src.dir, 90))
- updateSilicate()
- update_nearby_tiles(need_rebuild=1)
- return
-
-
-/obj/structure/window/verb/rotate_clockwise()
- set name = "Rotate Window Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if(usr.incapacitated())
- return 0
-
- if(is_fulltile())
- return 0
-
- if(anchored)
- to_chat(usr, "It is fastened to the floor therefore you can't rotate it!")
- return 0
-
- update_nearby_tiles(need_rebuild=1) //Compel updates before
- src.set_dir(turn(src.dir, 270))
- updateSilicate()
- update_nearby_tiles(need_rebuild=1)
- return
-
-/obj/structure/window/New(Loc, start_dir=null, constructed=0)
- ..()
-
- if (start_dir)
- set_dir(start_dir)
-
- //player-constructed windows
- if (constructed)
- anchored = 0
- state = 0
- update_verbs()
-
- health = maxhealth
-
- ini_dir = dir
-
- update_nearby_tiles(need_rebuild=1)
- update_nearby_icons()
-
-
-/obj/structure/window/Destroy()
- density = 0
- update_nearby_tiles()
- var/turf/location = loc
- . = ..()
- for(var/obj/structure/window/W in orange(location, 1))
- W.update_icon()
-
-/obj/structure/window/Move()
- var/ini_dir = dir
- update_nearby_tiles(need_rebuild=1)
- . = ..()
- set_dir(ini_dir)
- update_nearby_tiles(need_rebuild=1)
-
-//checks if this window is full-tile one
-/obj/structure/window/proc/is_fulltile()
- return fulltile
-
-/obj/structure/window/is_between_turfs(var/turf/origin, var/turf/target)
- if(fulltile)
- return TRUE
- return ..()
-
-//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc!
-/obj/structure/window/proc/update_nearby_icons()
- update_icon()
- for(var/obj/structure/window/W in orange(src, 1))
- W.update_icon()
-
-//Updates the availabiliy of the rotation verbs
-/obj/structure/window/proc/update_verbs()
- if(anchored || is_fulltile())
- verbs -= /obj/structure/window/verb/rotate_counterclockwise
- verbs -= /obj/structure/window/verb/rotate_clockwise
- else if(!is_fulltile())
- verbs += /obj/structure/window/verb/rotate_counterclockwise
- verbs += /obj/structure/window/verb/rotate_clockwise
-
-//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm)
-/obj/structure/window/update_icon()
- //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong.
- //this way it will only update full-tile ones
- overlays.Cut()
- if(!is_fulltile())
- // Rotate the sprite somewhat so non-fulltiled windows can be seen as needing repair.
- var/full_tilt_degrees = 15
- var/tilt_to_apply = abs((health / maxhealth) - 1)
- if(tilt_to_apply && prob(50))
- tilt_to_apply = -tilt_to_apply
- adjust_rotation(LERP(0, full_tilt_degrees, tilt_to_apply))
-
- icon_state = "[basestate]"
- return
- var/list/dirs = list()
- if(anchored)
- for(var/obj/structure/window/W in orange(src,1))
- if(W.anchored && W.density && W.glasstype == src.glasstype && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows.
- dirs += get_dir(src, W)
-
- var/list/connections = dirs_to_corner_states(dirs)
-
- icon_state = ""
- for(var/i = 1 to 4)
- var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1))
- overlays += I
-
- // Damage overlays.
- var/ratio = health / maxhealth
- ratio = CEILING(ratio * 4, 1) * 25
-
- if(ratio > 75)
- return
- var/image/I = image(icon, "damage[ratio]", layer = layer + 0.1)
- overlays += I
-
- return
-
-/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > maximal_heat)
- hit(damage_per_fire_tick, 0)
- ..()
-
-
-
-/obj/structure/window/basic
- desc = "It looks thin and flimsy. A few knocks with... almost anything, really should shatter it."
- icon_state = "window"
- basestate = "window"
- glasstype = /obj/item/stack/material/glass
- maximal_heat = T0C + 100
- damage_per_fire_tick = 2.0
- maxhealth = 12.0
- force_threshold = 3
-
-/obj/structure/window/basic/full
- icon_state = "window-full"
- maxhealth = 24
- fulltile = TRUE
-
-/obj/structure/window/phoronbasic
- name = "phoron window"
- desc = "A borosilicate alloy window. It seems to be quite strong."
- basestate = "phoronwindow"
- icon_state = "phoronwindow"
- shardtype = /obj/item/weapon/material/shard/phoron
- glasstype = /obj/item/stack/material/glass/phoronglass
- maximal_heat = T0C + 2000
- damage_per_fire_tick = 1.0
- maxhealth = 40.0
- force_threshold = 5
-
-/obj/structure/window/phoronbasic/full
- icon_state = "phoronwindow-full"
- maxhealth = 80
- fulltile = TRUE
-
-/obj/structure/window/phoronreinforced
- name = "reinforced borosilicate window"
- desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
- basestate = "phoronrwindow"
- icon_state = "phoronrwindow"
- shardtype = /obj/item/weapon/material/shard/phoron
- glasstype = /obj/item/stack/material/glass/phoronrglass
- reinf = 1
- maximal_heat = T0C + 4000
- damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
- maxhealth = 80.0
- force_threshold = 10
-
-/obj/structure/window/phoronreinforced/full
- icon_state = "phoronrwindow-full"
- maxhealth = 160
- fulltile = TRUE
-
-/obj/structure/window/reinforced
- name = "reinforced window"
- desc = "It looks rather strong. Might take a few good hits to shatter it."
- icon_state = "rwindow"
- basestate = "rwindow"
- maxhealth = 40.0
- reinf = 1
- maximal_heat = T0C + 750
- damage_per_fire_tick = 2.0
- glasstype = /obj/item/stack/material/glass/reinforced
- force_threshold = 6
-
-/obj/structure/window/reinforced/full
- icon_state = "rwindow-full"
- maxhealth = 80
- fulltile = TRUE
-
-/obj/structure/window/reinforced/tinted
- name = "tinted window"
- desc = "It looks rather strong and opaque. Might take a few good hits to shatter it."
- icon_state = "twindow"
- basestate = "twindow"
- opacity = 1
-
-/obj/structure/window/reinforced/tinted/frosted
- name = "frosted window"
- desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window."
- icon_state = "fwindow"
- basestate = "fwindow"
- maxhealth = 30
- force_threshold = 5
-
-/obj/structure/window/shuttle
- name = "shuttle window"
- desc = "It looks rather strong. Might take a few good hits to shatter it."
- icon = 'icons/obj/podwindows.dmi'
- icon_state = "window"
- basestate = "window"
- maxhealth = 40
- reinf = 1
- basestate = "w"
- dir = 5
- force_threshold = 7
-
-/obj/structure/window/reinforced/polarized
- name = "electrochromic window"
- desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it."
- var/id
-
-/obj/structure/window/reinforced/polarized/full
- icon_state = "rwindow-full"
- maxhealth = 80
- fulltile = TRUE
-
-/obj/structure/window/reinforced/polarized/attackby(obj/item/W as obj, mob/user as mob)
- if(istype(W, /obj/item/device/multitool) && !anchored) // Only allow programming if unanchored!
- var/obj/item/device/multitool/MT = W
- // First check if they have a windowtint button buffered
- if(istype(MT.connectable, /obj/machinery/button/windowtint))
- var/obj/machinery/button/windowtint/buffered_button = MT.connectable
- src.id = buffered_button.id
- to_chat(user, "\The [src] is linked to \the [buffered_button].")
- return TRUE
- // Otherwise fall back to asking them
- var/t = sanitizeSafe(input(user, "Enter the ID for the window.", src.name, null), MAX_NAME_LEN)
- if (!t && user.get_active_hand() != W && in_range(src, user))
- src.id = t
- to_chat(user, "The new ID of \the [src] is [id]")
- return TRUE
- . = ..()
-
-/obj/structure/window/reinforced/polarized/proc/toggle()
- if(opacity)
- animate(src, color="#FFFFFF", time=5)
- set_opacity(0)
- else
- animate(src, color="#222222", time=5)
- set_opacity(1)
-
-
-
-/obj/machinery/button/windowtint
- name = "window tint control"
- icon = 'icons/obj/stationobjs_vr.dmi' // VOREStation Edit - New icons
- icon_state = "light0"
- desc = "A remote control switch for polarized windows."
- var/range = 7
-
-/obj/machinery/button/windowtint/attack_hand(mob/user as mob)
- if(..())
- return 1
-
- toggle_tint()
-
-/obj/machinery/button/windowtint/proc/toggle_tint()
- use_power(5)
-
- active = !active
- update_icon()
-
- for(var/obj/structure/window/reinforced/polarized/W in range(src,range))
- if (W.id == src.id || !W.id)
- spawn(0)
- W.toggle()
- return
-
-/obj/machinery/button/windowtint/power_change()
- ..()
- if(active && !powered(power_channel))
- toggle_tint()
-
-/obj/machinery/button/windowtint/update_icon()
- icon_state = "light[active]"
-
-/obj/machinery/button/windowtint/attackby(obj/item/W as obj, mob/user as mob)
- if(istype(W, /obj/item/device/multitool))
- var/obj/item/device/multitool/MT = W
- if(!id)
- // If no ID is set yet (newly built button?) let them select an ID for first-time use!
- var/t = sanitizeSafe(input(user, "Enter an ID for \the [src].", src.name, null), MAX_NAME_LEN)
- if (t && user.get_active_hand() != W && in_range(src, user))
- src.id = t
- to_chat(user, "The new ID of \the [src] is [id]")
- if(id)
- // It already has an ID (or they just set one), buffer it for copying to windows.
- to_chat(user, "You store \the [src] in \the [MT]'s buffer!")
- MT.connectable = src
- MT.update_icon()
- return TRUE
- . = ..()
-
-/obj/structure/window/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
- switch(passed_mode)
- if(RCD_DECONSTRUCT)
- return list(
- RCD_VALUE_MODE = RCD_DECONSTRUCT,
- RCD_VALUE_DELAY = 5 SECONDS,
- RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
- )
-
-/obj/structure/window/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
- switch(passed_mode)
- if(RCD_DECONSTRUCT)
- to_chat(user, span("notice", "You deconstruct \the [src]."))
- qdel(src)
- return TRUE
- return FALSE
+/obj/structure/window
+ name = "window"
+ desc = "A window."
+ icon = 'icons/obj/structures_vr.dmi' // VOREStation Edit - New icons
+ density = 1
+ can_atmos_pass = ATMOS_PASS_PROC
+ w_class = ITEMSIZE_NORMAL
+
+ layer = WINDOW_LAYER
+ pressure_resistance = 4*ONE_ATMOSPHERE
+ anchored = 1.0
+ flags = ON_BORDER
+ var/maxhealth = 14.0
+ var/maximal_heat = T0C + 100 // Maximal heat before this window begins taking damage from fire
+ var/damage_per_fire_tick = 2.0 // Amount of damage per fire tick. Regular windows are not fireproof so they might as well break quickly.
+ var/health
+ var/force_threshold = 0
+ var/ini_dir = null
+ var/state = 2
+ var/reinf = 0
+ var/basestate
+ var/shardtype = /obj/item/weapon/material/shard
+ var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass.
+ var/silicate = 0 // number of units of silicate
+ var/fulltile = FALSE // Set to true on full-tile variants.
+
+/obj/structure/window/examine(mob/user)
+ . = ..()
+
+ if(health == maxhealth)
+ . += "It looks fully intact."
+ else
+ var/perc = health / maxhealth
+ if(perc > 0.75)
+ . += "It has a few cracks."
+ else if(perc > 0.5)
+ . += "It looks slightly damaged."
+ else if(perc > 0.25)
+ . += "It looks moderately damaged."
+ else
+ . += "It looks heavily damaged."
+ if(silicate)
+ if (silicate < 30)
+ . += "It has a thin layer of silicate."
+ else if (silicate < 70)
+ . += "It is covered in silicate."
+ 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
+
+ if(silicate)
+ damage = damage * (1 - silicate / 200)
+
+ health = max(0, health - damage)
+
+ if(health <= 0)
+ shatter()
+ else
+ if(sound_effect)
+ playsound(src, 'sound/effects/Glasshit.ogg', 100, 1)
+ if(health < maxhealth / 4 && initialhealth >= maxhealth / 4)
+ visible_message("[src] looks like it's about to shatter!" )
+ update_icon()
+ else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2)
+ visible_message("[src] looks seriously damaged!" )
+ update_icon()
+ else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4)
+ visible_message("Cracks begin to appear in [src]!" )
+ update_icon()
+ return
+
+/obj/structure/window/proc/apply_silicate(var/amount)
+ if(health < maxhealth) // Mend the damage
+ health = min(health + amount * 3, maxhealth)
+ if(health == maxhealth)
+ visible_message("[src] looks fully repaired." )
+ else // Reinforce
+ silicate = min(silicate + amount, 100)
+ updateSilicate()
+
+/obj/structure/window/proc/updateSilicate()
+ cut_overlays()
+ update_icon()
+
+ var/image/img = image(src)
+ img.color = "#ffffff"
+ img.alpha = silicate * 255 / 100
+ add_overlay(img)
+
+/obj/structure/window/proc/shatter(var/display_message = 1)
+ playsound(src, "shatter", 70, 1)
+ if(display_message)
+ visible_message("[src] shatters!")
+ new shardtype(loc)
+ if(reinf)
+ new /obj/item/stack/rods(loc)
+ if(is_fulltile())
+ new shardtype(loc) //todo pooling?
+ if(reinf)
+ new /obj/item/stack/rods(loc)
+ qdel(src)
+ return
+
+
+/obj/structure/window/bullet_act(var/obj/item/projectile/Proj)
+
+ var/proj_damage = Proj.get_structure_damage()
+ if(!proj_damage) return
+
+ ..()
+ take_damage(proj_damage)
+ return
+
+
+/obj/structure/window/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ shatter(0)
+ return
+ if(3.0)
+ if(prob(50))
+ shatter(0)
+ return
+
+/obj/structure/window/blob_act()
+ take_damage(50)
+
+/obj/structure/window/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover) && mover.checkpass(PASSGLASS))
+ return TRUE
+ if(is_fulltile())
+ return FALSE //full tile window, you can't move into it!
+ if((get_dir(loc, target) & dir) || (get_dir(mover, target) == turn(dir, 180)))
+ return !density
+ else
+ return TRUE
+
+
+/obj/structure/window/CanZASPass(turf/T, is_zone)
+ if(is_fulltile() || get_dir(T, loc) == turn(dir, 180)) // Make sure we're handling the border correctly.
+ return !anchored // If it's anchored, it'll block air.
+ return TRUE // Don't stop airflow from the other sides.
+
+/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf)
+ if(istype(O) && O.checkpass(PASSGLASS))
+ return 1
+ if(get_dir(O.loc, target) == dir)
+ return 0
+ return 1
+
+/obj/structure/window/hitby(AM as mob|obj)
+ ..()
+ visible_message("[src] was hit by [AM].")
+ var/tforce = 0
+ if(ismob(AM))
+ tforce = 40
+ else if(isobj(AM))
+ var/obj/item/I = AM
+ tforce = I.throwforce
+ if(reinf) tforce *= 0.25
+ if(health - tforce <= 7 && !reinf)
+ anchored = 0
+ update_verbs()
+ update_nearby_icons()
+ step(src, get_dir(AM, src))
+ take_damage(tforce)
+
+/obj/structure/window/attack_tk(mob/user as mob)
+ user.visible_message("Something knocks on [src].")
+ playsound(src, 'sound/effects/Glasshit.ogg', 50, 1)
+
+/obj/structure/window/attack_hand(mob/user as mob)
+ user.setClickCooldown(user.get_attack_speed())
+ if(HULK in user.mutations)
+ user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
+ user.visible_message("[user] smashes through [src]!")
+ user.do_attack_animation(src)
+ shatter()
+
+ else if (usr.a_intent == I_HURT)
+
+ if (istype(usr,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = usr
+ if(H.species.can_shred(H))
+ attack_generic(H,25)
+ return
+
+ playsound(src, 'sound/effects/glassknock.ogg', 80, 1)
+ user.do_attack_animation(src)
+ usr.visible_message("\The [usr] bangs against \the [src]!",
+ "You bang against \the [src]!",
+ "You hear a banging sound.")
+ else
+ playsound(src, 'sound/effects/glassknock.ogg', 80, 1)
+ usr.visible_message("[usr.name] knocks on the [src.name].",
+ "You knock on the [src.name].",
+ "You hear a knocking sound.")
+ return
+
+/obj/structure/window/attack_generic(var/mob/user, var/damage)
+ user.setClickCooldown(user.get_attack_speed())
+ if(!damage)
+ return
+ if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
+ visible_message("[user] smashes into [src]!")
+ if(reinf)
+ damage = damage / 2
+ take_damage(damage)
+ else
+ visible_message("\The [user] bonks \the [src] harmlessly.")
+ user.do_attack_animation(src)
+ return 1
+
+/obj/structure/window/attackby(obj/item/W as obj, mob/user as mob)
+ if(!istype(W)) return//I really wish I did not need this
+
+ // Fixing.
+ if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP)
+ var/obj/item/weapon/weldingtool/WT = W
+ if(health < maxhealth)
+ if(WT.remove_fuel(1 ,user))
+ to_chat(user, "You begin repairing [src]...")
+ playsound(src, WT.usesound, 50, 1)
+ if(do_after(user, 40 * WT.toolspeed, target = src))
+ health = maxhealth
+ // playsound(src, 'sound/items/Welder.ogg', 50, 1)
+ update_icon()
+ to_chat(user, "You repair [src].")
+ else
+ to_chat(user, "[src] is already in good condition!")
+ return
+
+ // Slamming.
+ if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
+ var/obj/item/weapon/grab/G = W
+ if(istype(G.affecting,/mob/living))
+ var/mob/living/M = G.affecting
+ var/state = G.state
+ qdel(W) //gotta delete it here because if window breaks, it won't get deleted
+ switch (state)
+ if(1)
+ M.visible_message("[user] slams [M] against \the [src]!")
+ M.apply_damage(7)
+ hit(10)
+ if(2)
+ M.visible_message("[user] bashes [M] against \the [src]!")
+ if (prob(50))
+ M.Weaken(1)
+ M.apply_damage(10)
+ hit(25)
+ if(3)
+ M.visible_message("[user] crushes [M] against \the [src]!")
+ M.Weaken(5)
+ M.apply_damage(20)
+ hit(50)
+ return
+
+ if(W.flags & NOBLUDGEON) return
+
+ if(W.is_screwdriver())
+ if(reinf && state >= 1)
+ state = 3 - state
+ update_nearby_icons()
+ playsound(src, W.usesound, 75, 1)
+ to_chat(user, "You have [state == 1 ? "un" : ""]fastened the window [state ? "from" : "to"] the frame.")
+ else if(reinf && state == 0)
+ anchored = !anchored
+ update_nearby_icons()
+ update_verbs()
+ playsound(src, W.usesound, 75, 1)
+ to_chat(user, "You have [anchored ? "" : "un"]fastened the frame [anchored ? "to" : "from"] the floor.")
+ else if(!reinf)
+ anchored = !anchored
+ update_nearby_icons()
+ update_verbs()
+ playsound(src, W.usesound, 75, 1)
+ to_chat(user, "You have [anchored ? "" : "un"]fastened the window [anchored ? "to" : "from"] the floor.")
+ else if(W.is_crowbar() && reinf && state <= 1)
+ state = 1 - state
+ playsound(src, W.usesound, 75, 1)
+ to_chat(user, "You have pried the window [state ? "into" : "out of"] the frame.")
+ else if(W.is_wrench() && !anchored && (!state || !reinf))
+ if(!glasstype)
+ to_chat(user, "You're not sure how to dismantle \the [src] properly.")
+ else
+ playsound(src, W.usesound, 75, 1)
+ visible_message("[user] dismantles \the [src].")
+ var/obj/item/stack/material/mats = new glasstype(loc)
+ if(is_fulltile())
+ mats.amount = 4
+ qdel(src)
+ else if(istype(W, /obj/item/stack/cable_coil) && reinf && state == 0 && !istype(src, /obj/structure/window/reinforced/polarized))
+ var/obj/item/stack/cable_coil/C = W
+ if (C.use(1))
+ playsound(src, 'sound/effects/sparks1.ogg', 75, 1)
+ user.visible_message( \
+ "\The [user] begins to wire \the [src] for electrochromic tinting.", \
+ "You begin to wire \the [src] for electrochromic tinting.", \
+ "You hear sparks.")
+ if(do_after(user, 20 * C.toolspeed, src) && state == 0)
+ playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
+ var/obj/structure/window/reinforced/polarized/P = new(loc, dir)
+ if(is_fulltile())
+ P.fulltile = TRUE
+ P.icon_state = "fwindow"
+ P.maxhealth = maxhealth
+ P.health = health
+ P.state = state
+ P.anchored = anchored
+ qdel(src)
+ else if(istype(W,/obj/item/frame) && anchored)
+ var/obj/item/frame/F = W
+ F.try_build(src, user)
+ else
+ user.setClickCooldown(user.get_attack_speed(W))
+ if(W.damtype == BRUTE || W.damtype == BURN)
+ user.do_attack_animation(src)
+ hit(W.force)
+ if(health <= 7)
+ anchored = 0
+ update_nearby_icons()
+ step(src, get_dir(user, src))
+ else
+ playsound(src, 'sound/effects/Glasshit.ogg', 75, 1)
+ ..()
+ return
+
+/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1)
+ if(damage < force_threshold || force_threshold < 0)
+ return
+ if(reinf) damage *= 0.5
+ take_damage(damage)
+ return
+
+
+/obj/structure/window/verb/rotate_counterclockwise()
+ set name = "Rotate Window Counterclockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if(usr.incapacitated())
+ return 0
+
+ if(is_fulltile())
+ return 0
+
+ if(anchored)
+ to_chat(usr, "It is fastened to the floor therefore you can't rotate it!")
+ return 0
+
+ update_nearby_tiles(need_rebuild=1) //Compel updates before
+ src.set_dir(turn(src.dir, 90))
+ updateSilicate()
+ update_nearby_tiles(need_rebuild=1)
+ return
+
+
+/obj/structure/window/verb/rotate_clockwise()
+ set name = "Rotate Window Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if(usr.incapacitated())
+ return 0
+
+ if(is_fulltile())
+ return 0
+
+ if(anchored)
+ to_chat(usr, "It is fastened to the floor therefore you can't rotate it!")
+ return 0
+
+ update_nearby_tiles(need_rebuild=1) //Compel updates before
+ src.set_dir(turn(src.dir, 270))
+ updateSilicate()
+ update_nearby_tiles(need_rebuild=1)
+ return
+
+/obj/structure/window/New(Loc, start_dir=null, constructed=0)
+ ..()
+
+ if (start_dir)
+ set_dir(start_dir)
+
+ //player-constructed windows
+ if (constructed)
+ anchored = 0
+ state = 0
+ update_verbs()
+
+ health = maxhealth
+
+ ini_dir = dir
+
+ update_nearby_tiles(need_rebuild=1)
+ update_nearby_icons()
+
+
+/obj/structure/window/Destroy()
+ density = 0
+ update_nearby_tiles()
+ var/turf/location = loc
+ . = ..()
+ for(var/obj/structure/window/W in orange(location, 1))
+ W.update_icon()
+
+/obj/structure/window/Move()
+ var/ini_dir = dir
+ update_nearby_tiles(need_rebuild=1)
+ . = ..()
+ set_dir(ini_dir)
+ update_nearby_tiles(need_rebuild=1)
+
+//checks if this window is full-tile one
+/obj/structure/window/proc/is_fulltile()
+ return fulltile
+
+/obj/structure/window/is_between_turfs(var/turf/origin, var/turf/target)
+ if(is_fulltile())
+ return TRUE
+ return ..()
+
+//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc!
+/obj/structure/window/proc/update_nearby_icons()
+ update_icon()
+ for(var/obj/structure/window/W in orange(src, 1))
+ W.update_icon()
+
+//Updates the availabiliy of the rotation verbs
+/obj/structure/window/proc/update_verbs()
+ if(anchored || is_fulltile())
+ verbs -= /obj/structure/window/verb/rotate_counterclockwise
+ verbs -= /obj/structure/window/verb/rotate_clockwise
+ else if(!is_fulltile())
+ verbs += /obj/structure/window/verb/rotate_counterclockwise
+ verbs += /obj/structure/window/verb/rotate_clockwise
+
+//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm)
+/obj/structure/window/update_icon()
+ //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong.
+ //this way it will only update full-tile ones
+ cut_overlays()
+ if(!is_fulltile())
+ // Rotate the sprite somewhat so non-fulltiled windows can be seen as needing repair.
+ var/full_tilt_degrees = 15
+ var/tilt_to_apply = abs((health / maxhealth) - 1)
+ if(tilt_to_apply && prob(50))
+ tilt_to_apply = -tilt_to_apply
+ adjust_rotation(LERP(0, full_tilt_degrees, tilt_to_apply))
+
+ icon_state = "[basestate]"
+ return
+ else
+ flags = 0 // Removes ON_BORDER and OPPOSITE_OPACITY
+ var/list/dirs = list()
+ if(anchored)
+ for(var/obj/structure/window/W in orange(src,1))
+ if(W.anchored && W.density && W.glasstype == src.glasstype && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows.
+ dirs += get_dir(src, W)
+
+ var/list/connections = dirs_to_corner_states(dirs)
+
+ icon_state = ""
+ for(var/i = 1 to 4)
+ var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1))
+ add_overlay(I)
+
+ // Damage overlays.
+ var/ratio = health / maxhealth
+ ratio = CEILING(ratio * 4, 1) * 25
+
+ if(ratio > 75)
+ return
+ var/image/I = image(icon, "damage[ratio]", layer = layer + 0.1)
+ add_overlay(I)
+
+ return
+
+/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ if(exposed_temperature > maximal_heat)
+ hit(damage_per_fire_tick, 0)
+ ..()
+
+
+
+/obj/structure/window/basic
+ desc = "It looks thin and flimsy. A few knocks with... almost anything, really should shatter it."
+ icon_state = "window"
+ basestate = "window"
+ glasstype = /obj/item/stack/material/glass
+ maximal_heat = T0C + 100
+ damage_per_fire_tick = 2.0
+ maxhealth = 12.0
+ force_threshold = 3
+
+/obj/structure/window/basic/full
+ icon_state = "window-full"
+ maxhealth = 24
+ fulltile = TRUE
+ flags = 0
+
+/obj/structure/window/phoronbasic
+ name = "phoron window"
+ desc = "A borosilicate alloy window. It seems to be quite strong."
+ basestate = "phoronwindow"
+ icon_state = "phoronwindow"
+ shardtype = /obj/item/weapon/material/shard/phoron
+ glasstype = /obj/item/stack/material/glass/phoronglass
+ maximal_heat = T0C + 2000
+ damage_per_fire_tick = 1.0
+ maxhealth = 40.0
+ force_threshold = 5
+
+/obj/structure/window/phoronbasic/full
+ icon_state = "phoronwindow-full"
+ maxhealth = 80
+ fulltile = TRUE
+ flags = 0
+
+/obj/structure/window/phoronreinforced
+ name = "reinforced borosilicate window"
+ desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
+ basestate = "phoronrwindow"
+ icon_state = "phoronrwindow"
+ shardtype = /obj/item/weapon/material/shard/phoron
+ glasstype = /obj/item/stack/material/glass/phoronrglass
+ reinf = 1
+ maximal_heat = T0C + 4000
+ damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
+ maxhealth = 80.0
+ force_threshold = 10
+
+/obj/structure/window/phoronreinforced/full
+ icon_state = "phoronrwindow-full"
+ maxhealth = 160
+ fulltile = TRUE
+ flags = 0
+
+/obj/structure/window/reinforced
+ name = "reinforced window"
+ desc = "It looks rather strong. Might take a few good hits to shatter it."
+ icon_state = "rwindow"
+ basestate = "rwindow"
+ maxhealth = 40.0
+ reinf = 1
+ maximal_heat = T0C + 750
+ damage_per_fire_tick = 2.0
+ glasstype = /obj/item/stack/material/glass/reinforced
+ force_threshold = 6
+
+/obj/structure/window/reinforced/full
+ icon_state = "rwindow-full"
+ maxhealth = 80
+ fulltile = TRUE
+ flags = 0
+
+/obj/structure/window/reinforced/tinted
+ name = "tinted window"
+ desc = "It looks rather strong and opaque. Might take a few good hits to shatter it."
+ icon_state = "twindow"
+ basestate = "twindow"
+ opacity = 1
+
+/obj/structure/window/reinforced/tinted/frosted
+ name = "frosted window"
+ desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window."
+ icon_state = "fwindow"
+ basestate = "fwindow"
+ maxhealth = 30
+ force_threshold = 5
+
+/obj/structure/window/shuttle
+ name = "shuttle window"
+ desc = "It looks rather strong. Might take a few good hits to shatter it."
+ icon = 'icons/obj/podwindows.dmi'
+ icon_state = "window"
+ basestate = "window"
+ maxhealth = 40
+ reinf = 1
+ basestate = "w"
+ dir = 5
+ force_threshold = 7
+
+/obj/structure/window/reinforced/polarized
+ name = "electrochromic window"
+ desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it."
+ var/id
+
+/obj/structure/window/reinforced/polarized/full
+ icon_state = "rwindow-full"
+ maxhealth = 80
+ fulltile = TRUE
+ flags = 0
+
+/obj/structure/window/reinforced/polarized/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/device/multitool) && !anchored) // Only allow programming if unanchored!
+ var/obj/item/device/multitool/MT = W
+ // First check if they have a windowtint button buffered
+ if(istype(MT.connectable, /obj/machinery/button/windowtint))
+ var/obj/machinery/button/windowtint/buffered_button = MT.connectable
+ src.id = buffered_button.id
+ to_chat(user, "\The [src] is linked to \the [buffered_button].")
+ return TRUE
+ // Otherwise fall back to asking them
+ var/t = sanitizeSafe(input(user, "Enter the ID for the window.", src.name, null), MAX_NAME_LEN)
+ if (!t && user.get_active_hand() != W && in_range(src, user))
+ src.id = t
+ to_chat(user, "The new ID of \the [src] is [id]")
+ return TRUE
+ . = ..()
+
+/obj/structure/window/reinforced/polarized/proc/toggle()
+ if(opacity)
+ animate(src, color="#FFFFFF", time=5)
+ set_opacity(0)
+ else
+ animate(src, color="#222222", time=5)
+ set_opacity(1)
+ var/turf/T = get_turf(src)
+ T.recalculate_directional_opacity()
+
+/obj/machinery/button/windowtint
+ name = "window tint control"
+ icon = 'icons/obj/stationobjs_vr.dmi' // VOREStation Edit - New icons
+ icon_state = "light0"
+ desc = "A remote control switch for polarized windows."
+ var/range = 7
+
+/obj/machinery/button/windowtint/attack_hand(mob/user as mob)
+ if(..())
+ return 1
+
+ toggle_tint()
+
+/obj/machinery/button/windowtint/proc/toggle_tint()
+ use_power(5)
+
+ active = !active
+ update_icon()
+
+ for(var/obj/structure/window/reinforced/polarized/W in range(src,range))
+ if (W.id == src.id || !W.id)
+ spawn(0)
+ W.toggle()
+ return
+
+/obj/machinery/button/windowtint/power_change()
+ ..()
+ if(active && !powered(power_channel))
+ toggle_tint()
+
+/obj/machinery/button/windowtint/update_icon()
+ icon_state = "light[active]"
+
+/obj/machinery/button/windowtint/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/device/multitool))
+ var/obj/item/device/multitool/MT = W
+ if(!id)
+ // If no ID is set yet (newly built button?) let them select an ID for first-time use!
+ var/t = sanitizeSafe(input(user, "Enter an ID for \the [src].", src.name, null), MAX_NAME_LEN)
+ if (t && user.get_active_hand() != W && in_range(src, user))
+ src.id = t
+ to_chat(user, "The new ID of \the [src] is [id]")
+ if(id)
+ // It already has an ID (or they just set one), buffer it for copying to windows.
+ to_chat(user, "You store \the [src] in \the [MT]'s buffer!")
+ MT.connectable = src
+ MT.update_icon()
+ return TRUE
+ . = ..()
+
+/obj/structure/window/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = 5 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
+ )
+
+/obj/structure/window/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ qdel(src)
+ return TRUE
+ return FALSE
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 2e6099aec25..1d37f4b47ab 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -30,7 +30,6 @@
thermal_conductivity = 0.040
heat_capacity = 10000
- var/lava = 0
/turf/simulated/floor/is_plating()
return (!flooring || flooring.is_plating)
diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm
index e82edc294de..d975f81090d 100644
--- a/code/game/turfs/simulated/floor_icon.dm
+++ b/code/game/turfs/simulated/floor_icon.dm
@@ -11,10 +11,6 @@ var/image/no_ceiling_image = null
no_ceiling_image.plane = PLANE_MESONS
/turf/simulated/floor/update_icon(var/update_neighbors)
-
- if(lava)
- return
-
cut_overlays()
if(flooring)
diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm
index 437912b4d26..e5c4391e642 100644
--- a/code/game/turfs/simulated/floor_types.dm
+++ b/code/game/turfs/simulated/floor_types.dm
@@ -214,11 +214,13 @@
light_range = 3
light_power = 0.6
light_color = "#66ffff" // Bright cyan.
+ light_on = TRUE
block_tele = TRUE
/turf/simulated/shuttle/floor/alien/Initialize()
. = ..()
icon_state = "alienpod[rand(1, 9)]"
+ update_light()
/turf/simulated/shuttle/floor/alienplating
icon_state = "alienplating"
diff --git a/code/game/turfs/simulated/lava.dm b/code/game/turfs/simulated/lava.dm
index 22b79272b87..67524c05ef0 100644
--- a/code/game/turfs/simulated/lava.dm
+++ b/code/game/turfs/simulated/lava.dm
@@ -10,6 +10,7 @@
light_range = 2
light_power = 0.75
light_color = LIGHT_COLOR_LAVA
+ light_on = TRUE
movement_cost = 2
can_build_into_floor = TRUE
can_dirty = FALSE
@@ -23,6 +24,7 @@
if(!outdoors)
name = "magma"
update_icon()
+ update_light()
return ..()
/turf/simulated/floor/lava/make_outdoors()
diff --git a/code/game/turfs/simulated/outdoors/outdoors_vr.dm b/code/game/turfs/simulated/outdoors/outdoors_vr.dm
new file mode 100644
index 00000000000..a7233b43293
--- /dev/null
+++ b/code/game/turfs/simulated/outdoors/outdoors_vr.dm
@@ -0,0 +1,108 @@
+/turf/simulated/floor/tiled/asteroid_steel/outdoors
+ name = "weathered tiles"
+ desc = "Old tiles left out in the elements."
+ outdoors = 1
+ edge_blending_priority = 1
+
+/turf/simulated/floor/outdoors/newdirt
+ name = "dirt"
+ desc = "Looks dirty."
+ icon = 'icons/turf/outdoors_vr.dmi'
+ icon_state = "dirt0"
+ edge_blending_priority = 2
+ initial_flooring = /decl/flooring/outdoors/newdirt
+
+/decl/flooring/outdoors/newdirt
+ name = "dirt"
+ desc = "Looks dirty."
+ icon = 'icons/turf/outdoors_vr.dmi'
+ icon_base = "dirt0"
+ 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',
+ 'sound/effects/footstep/MedDirt1.ogg',
+ 'sound/effects/footstep/MedDirt2.ogg',
+ 'sound/effects/footstep/MedDirt3.ogg',
+ 'sound/effects/footstep/MedDirt4.ogg'))
+
+/turf/simulated/floor/outdoors/newdirt/Initialize(mapload)
+ var/possibledirts = list(
+ "dirt0" = 150,
+ "dirt1" = 25,
+ "dirt2" = 25,
+ "dirt3" = 10,
+ "dirt4" = 3,
+ "dirt5" = 3,
+ "dirt6" = 1,
+ "dirt7" = 25,
+ "dirt8" = 10,
+ "dirt9" = 25
+ )
+ flooring_override = pickweight(possibledirts)
+ return ..()
+
+
+/turf/simulated/floor/outdoors/newdirt_nograss
+ name = "dirt"
+ desc = "Looks dirty."
+ icon = 'icons/turf/outdoors_vr.dmi'
+ icon_state = "dirt0"
+ edge_blending_priority = 2
+ initial_flooring = /decl/flooring/outdoors/newdirt
+
+/turf/simulated/floor/outdoors/newdirt_nograss/Initialize(mapload)
+ var/possibledirts = list(
+ "dirt0" = 200,
+ "dirt3" = 20,
+ "dirt4" = 3,
+ "dirt5" = 3,
+ "dirt6" = 1
+ )
+ flooring_override = pickweight(possibledirts)
+ return ..()
+
+/turf/simulated/floor/outdoors/sidewalk
+ name = "sidewalk"
+ desc = "Concrete shaped into a path!"
+ icon = 'icons/turf/outdoors_vr.dmi'
+ icon_state = "sidewalk"
+ edge_blending_priority = 1
+ movement_cost = -0.5
+ initial_flooring = /decl/flooring/outdoors/sidewalk
+
+/decl/flooring/outdoors/sidewalk
+ name = "sidewalk"
+ desc = "Concrete shaped into a path!"
+ icon = 'icons/turf/outdoors_vr.dmi'
+ icon_base = "sidewalk"
+ footstep_sounds = list("human" = list(
+ 'sound/effects/footstep/LightStone1.ogg',
+ 'sound/effects/footstep/LightStone2.ogg',
+ 'sound/effects/footstep/LightStone3.ogg',
+ 'sound/effects/footstep/LightStone4.ogg',))
+
+/turf/simulated/floor/outdoors/sidewalk/Initialize(mapload)
+ var/possibledirts = list(
+ "[initial(icon_state)]" = 150,
+ "[initial(icon_state)]1" = 3,
+ "[initial(icon_state)]2" = 3,
+ "[initial(icon_state)]3" = 3,
+ "[initial(icon_state)]4" = 3,
+ "[initial(icon_state)]5" = 3,
+ "[initial(icon_state)]6" = 2,
+ "[initial(icon_state)]7" = 2,
+ "[initial(icon_state)]8" = 2,
+ "[initial(icon_state)]9" = 2,
+ "[initial(icon_state)]10" = 2
+ )
+ flooring_override = pickweight(possibledirts)
+ return ..()
+
+/turf/simulated/floor/outdoors/sidewalk/side
+ icon_state = "side-walk"
+
+/turf/simulated/floor/outdoors/sidewalk/slab
+ icon_state = "slab"
diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm
index 4ead21508b7..0f7b4bb60cd 100644
--- a/code/game/turfs/simulated/wall_types.dm
+++ b/code/game/turfs/simulated/wall_types.dm
@@ -156,8 +156,13 @@
light_range = 3
light_power = 0.75
light_color = "#ff0066" // Pink-ish
+ light_on = TRUE
block_tele = TRUE // Will be used for dungeons so this is needed to stop cheesing with handteles.
+/turf/simulated/shuttle/wall/alien/Initialize()
+ . = ..()
+ update_light()
+
/turf/simulated/shuttle/wall/alien/hard_corner
name = "hardcorner wall"
icon_state = "alien-hc"
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 9cacb36eaf4..db8947b0563 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -41,7 +41,9 @@
//Lighting related
luminosity = !(dynamic_lighting)
- has_opaque_atom |= (opacity)
+
+ if(opacity)
+ directional_opacity = ALL_CARDINALS
//Pathfinding related
if(movement_cost && pathweight == 1) // This updates pathweight automatically.
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index b3988f3f77a..efbea4ffb37 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -32,11 +32,13 @@
N = /turf/simulated/open
var/obj/fire/old_fire = fire
- var/old_opacity = opacity
var/old_dynamic_lighting = dynamic_lighting
- var/old_affecting_lights = affecting_lights
- var/old_lighting_overlay = lighting_overlay
- var/old_corners = corners
+ var/old_lighting_object = lighting_object
+ var/old_lighting_corner_NE = lighting_corner_NE
+ var/old_lighting_corner_SE = lighting_corner_SE
+ var/old_lighting_corner_SW = lighting_corner_SW
+ var/old_lighting_corner_NW = lighting_corner_NW
+ var/old_directional_opacity = directional_opacity
var/old_outdoors = outdoors
var/old_dangerous_objects = dangerous_objects
@@ -94,21 +96,29 @@
W.post_change()
. = W
- recalc_atom_opacity()
-
dangerous_objects = old_dangerous_objects
- if(lighting_overlays_initialised)
- lighting_overlay = old_lighting_overlay
- affecting_lights = old_affecting_lights
- corners = old_corners
- if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting))
- reconsider_lights()
- if(dynamic_lighting != old_dynamic_lighting)
- if(dynamic_lighting)
+ lighting_corner_NE = old_lighting_corner_NE
+ lighting_corner_SE = old_lighting_corner_SE
+ lighting_corner_SW = old_lighting_corner_SW
+ lighting_corner_NW = old_lighting_corner_NW
+
+ if(SSlighting.subsystem_initialized)
+ lighting_object = old_lighting_object
+
+ directional_opacity = old_directional_opacity
+ recalculate_directional_opacity()
+
+ if (dynamic_lighting != old_dynamic_lighting)
+ if (IS_DYNAMIC_LIGHTING(src))
lighting_build_overlay()
else
lighting_clear_overlay()
+ else if(lighting_object && !lighting_object.needs_update)
+ lighting_object.update()
+
+ for(var/turf/space/space_tile in RANGE_TURFS(1, src))
+ space_tile.update_starlight()
if(preserve_outdoors)
outdoors = old_outdoors
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index e7c3a34c11f..96761437512 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -1609,7 +1609,7 @@ datum/admins/var/obj/item/weapon/paper/admin/faxreply // var to hold fax replies
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/weapon/stamp/centcomm
- P.overlays += stampoverlay
+ P.add_overlay(stampoverlay)
var/obj/item/rcvdcopy
rcvdcopy = destination.copy(P)
diff --git a/code/modules/ai/ai_holder_movement.dm b/code/modules/ai/ai_holder_movement.dm
index bc5916917a9..50624926844 100644
--- a/code/modules/ai/ai_holder_movement.dm
+++ b/code/modules/ai/ai_holder_movement.dm
@@ -126,7 +126,7 @@
if(path_display)
var/turf/T = src.path[1]
- T.overlays -= path_overlay
+ T.cut_overlay(path_overlay)
// step_towards(holder, src.path[1])
if(holder.IMove(get_step_towards(holder, src.path[1])) != MOVEMENT_ON_COOLDOWN)
diff --git a/code/modules/ai/ai_holder_pathfinding.dm b/code/modules/ai/ai_holder_pathfinding.dm
index 1a20c6f682b..fed867ee244 100644
--- a/code/modules/ai/ai_holder_pathfinding.dm
+++ b/code/modules/ai/ai_holder_pathfinding.dm
@@ -14,7 +14,7 @@
ai_log("forget_path() : Entering.", AI_LOG_DEBUG)
if(path_display)
for(var/turf/T in path)
- T.overlays -= path_overlay
+ T.cut_overlay(path_overlay)
path.Cut()
ai_log("forget_path() : Exiting.", AI_LOG_DEBUG)
@@ -49,7 +49,7 @@
ai_log("get_path() : Made new path.",AI_LOG_DEBUG)
if(path_display)
for(var/turf/T in path)
- T.overlays |= path_overlay
+ T.add_overlay(path_overlay)
else
ai_log("get_path() : Failed to make new path. Exiting.",AI_LOG_DEBUG)
return 0
diff --git a/code/modules/ai/ai_holder_targeting.dm b/code/modules/ai/ai_holder_targeting.dm
index 3b3878babee..a243ab8a582 100644
--- a/code/modules/ai/ai_holder_targeting.dm
+++ b/code/modules/ai/ai_holder_targeting.dm
@@ -222,17 +222,17 @@
lose_target_position()
if(last_turf_display && target_last_seen_turf)
- target_last_seen_turf.overlays -= last_turf_overlay
+ target_last_seen_turf.cut_overlay(last_turf_overlay)
target_last_seen_turf = get_turf(target)
if(last_turf_display)
- target_last_seen_turf.overlays += last_turf_overlay
+ target_last_seen_turf.add_overlay(last_turf_overlay)
// Resets the last known position to null.
/datum/ai_holder/proc/lose_target_position()
if(last_turf_display && target_last_seen_turf)
- target_last_seen_turf.overlays -= last_turf_overlay
+ target_last_seen_turf.cut_overlay(last_turf_overlay)
ai_log("lose_target_position() : Last position is being reset.", AI_LOG_INFO)
target_last_seen_turf = null
diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm
index fa8b7838157..30f002de7d2 100644
--- a/code/modules/assembly/timer.dm
+++ b/code/modules/assembly/timer.dm
@@ -53,10 +53,10 @@
time = 10
/obj/item/device/assembly/timer/update_icon()
- overlays.Cut()
+ cut_overlays()
attached_overlays = list()
if(timing)
- overlays += "timer_timing"
+ add_overlay("timer_timing")
attached_overlays += "timer_timing"
if(holder)
holder.update_icon()
diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm
index 9bd72d824e1..9e6043a7803 100644
--- a/code/modules/asset_cache/asset_list_items.dm
+++ b/code/modules/asset_cache/asset_list_items.dm
@@ -1,11 +1,18 @@
//DEFINITIONS FOR ASSET DATUMS START HERE.
+/datum/asset/simple/tgui_common
+ // keep_local_name = TRUE
+ assets = list(
+ "tgui-common.bundle.js" = file("tgui/public/tgui-common.bundle.js"),
+ )
/datum/asset/simple/tgui
+ // keep_local_name = TRUE
assets = list(
- "tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
- "tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
+ "tgui.bundle.js" = file("tgui/public/tgui.bundle.js"),
+ "tgui.bundle.css" = file("tgui/public/tgui.bundle.css"),
)
+
/datum/asset/simple/headers
assets = list(
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
@@ -175,6 +182,14 @@
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
)
+/datum/asset/simple/tgfont
+ assets = list(
+ "tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"),
+ "tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"),
+ "tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"),
+ )
+
+
// /datum/asset/spritesheet/goonchat
// name = "chat"
diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm
index daf964e4433..1d1b4c4a8e9 100644
--- a/code/modules/awaymissions/gateway.dm
+++ b/code/modules/awaymissions/gateway.dm
@@ -148,6 +148,13 @@ obj/machinery/gateway/centerstation/process()
if(dest)
M.forceMove(dest.loc)
M.set_dir(SOUTH)
+ //VOREStation Addition Start: Mcguffin time!
+ if(istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = M
+ if(!H.client)
+ awaygate.entrydetect()
+ //VOREStation Addition End: Mcguffin time!
+
//VOREStation Addition Start: Abduction!
if(istype(M, /mob/living) && dest.abductor)
var/mob/living/L = M
@@ -318,4 +325,4 @@ obj/machinery/gateway/centerstation/process()
else
to_chat(user, "Recalibration successful!: This gate's systems have been fine tuned. Travel to this gate will now be on target.")
calibrated = 1
- return
+ return
\ No newline at end of file
diff --git a/code/modules/awaymissions/gateway_vr.dm b/code/modules/awaymissions/gateway_vr.dm
new file mode 100644
index 00000000000..86ff8e5e135
--- /dev/null
+++ b/code/modules/awaymissions/gateway_vr.dm
@@ -0,0 +1,79 @@
+//This gateway type takes a special item that you will have to find on the map to activate, instead of using a multitool//
+
+/obj/machinery/gateway/centeraway/mcguffin
+ icon = 'icons/obj/machines/gateway_vr.dmi'
+ calibrated = 0
+ var/mcguffin_type = /obj/item/device/mcguffin/brass //you should be able to change the var to be whatever kind of path you like, so maybe you can use other things on it sometimes
+ var/key //holds a ref to the key we spawned
+
+/obj/machinery/gateway/centeraway/mcguffin/attackby(obj/item/device/W as obj, mob/user as mob)
+ if(calibrated && stationgate)
+ to_chat(user, "The gate is already configured, you should be able to activate it.")
+ return
+ else if(!stationgate)
+ to_chat(user, "Error: Configuration failed. No destination found... That can't be good.")
+ return
+
+ if(istype(W,mcguffin_type) && !calibrated)
+ to_chat(user, "As the device nears the gateway, mechanical clunks and whirrs can be heard. Configuration successful! This gate's systems have been fine tuned. Travel to this gate will now be on target.")
+ calibrated = 1
+ return
+ else
+ to_chat(user, "This device does not seem to interface correctly with the gateway. Perhaps you should try something else.")
+ return
+
+//If you use this kind of gateway you NEED one of these on the map or the players won't be able to leave//
+//You should use the random spawner though so it won't always be in the same place//
+/obj/item/device/mcguffin/brass
+ name = "mysterious brass device"
+ desc = "A curious object made of what appears to be brass and silver. Its purpose is unclear by looking at it. Perhaps it should be used with something of similar materials?"
+ icon = 'icons/obj/machines/gateway_vr.dmi'
+ icon_state = "mcguffin"
+ drop_sound = 'sound/items/drop/wrench.ogg'
+ pickup_sound = 'sound/items/pickup/wrench.ogg'
+
+/obj/effect/landmark/mcguffin_spawner
+ name = "gateway key spawner"
+ icon = 'icons/mob/randomlandmarks.dmi'
+ icon_state = "key"
+
+/obj/machinery/gateway/centeraway/proc/entrydetect()
+ return
+
+/obj/machinery/gateway/centeraway/mcguffin/entrydetect()
+ if(key)
+ return
+
+ var/list/spawners = list()
+ for(var/obj/effect/landmark/mcguffin_spawner/sp in world)
+ spawners += sp
+
+ var/obj/effect/landmark/mcguffin_spawner/the_cool_one = pick(spawners)
+
+ var/atom/destination = get_turf(the_cool_one)
+ var/obj/structure/closet/CL = locate() in destination
+ if(CL)
+ destination = CL
+
+ if(!destination)
+ warning("A gateway is trying to spawn it's mcguffin but there are no mapped in spawner landmarks")
+ destination = get_turf(src)
+
+ key = new mcguffin_type(destination)
+
+/obj/machinery/gateway/centeraway/mcguffin/Bumped(atom/movable/M as mob|obj)
+ if(!ready) return
+ if(!active) return
+ M.forceMove(get_step(stationgate.loc, SOUTH))
+ M.set_dir(SOUTH)
+ M << 'sound/effects/swooshygate.ogg'
+ playsound(src, 'sound/effects/swooshygate.ogg', 100, 1)
+
+/obj/machinery/gateway/brass
+ name = "mysterious brass gateway"
+ desc = "A gateway of strange construction. It appears to be made primarily of materials resembling brass and silver."
+ icon = 'icons/obj/machines/gateway_vr.dmi'
+
+//No, you can't digest the key to leave the gateway.
+/obj/item/device/mcguffin/digest_act(var/atom/movable/item_storage = null)
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/blob2/blobs/core.dm b/code/modules/blob2/blobs/core.dm
index b3633b406eb..cd4a68a3088 100644
--- a/code/modules/blob2/blobs/core.dm
+++ b/code/modules/blob2/blobs/core.dm
@@ -119,14 +119,14 @@ var/list/blob_cores = list()
return ..()
/obj/structure/blob/core/update_icon()
- overlays.Cut()
+ cut_overlays()
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
if(overmind)
blob_overlay.color = overmind.blob_type.color
name = "[overmind.blob_type.name] [base_name]"
- overlays += blob_overlay
- overlays += mutable_appearance('icons/mob/blob.dmi', "blob_core_overlay")
+ add_overlay(blob_overlay)
+ add_overlay("blob_core_overlay")
/obj/structure/blob/core/process()
set waitfor = FALSE
diff --git a/code/modules/blob2/blobs/node.dm b/code/modules/blob2/blobs/node.dm
index 5f54b6b80a1..072769b73aa 100644
--- a/code/modules/blob2/blobs/node.dm
+++ b/code/modules/blob2/blobs/node.dm
@@ -21,14 +21,14 @@ var/list/blob_nodes = list()
return ..()
/obj/structure/blob/node/update_icon()
- overlays.Cut()
+ cut_overlays()
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
if(overmind)
name = "[overmind.blob_type.name] [base_name]"
blob_overlay.color = overmind.blob_type.color
- overlays += blob_overlay
- overlays += mutable_appearance('icons/mob/blob.dmi', "blob_node_overlay")
+ add_overlay(blob_overlay)
+ add_overlay("blob_node_overlay")
/obj/structure/blob/node/process()
set waitfor = FALSE
diff --git a/code/modules/blob2/mobs/spore.dm b/code/modules/blob2/mobs/spore.dm
index 5d8808c57fd..732db9a4da4 100644
--- a/code/modules/blob2/mobs/spore.dm
+++ b/code/modules/blob2/mobs/spore.dm
@@ -61,14 +61,14 @@
set_light(0)
if(is_infesting)
- overlays.Cut()
+ cut_overlays()
icon = infested.icon
- overlays = infested.overlays
+ add_overlay(infested.overlays)
var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
if(overmind)
blob_head_overlay.color = overmind.blob_type.complementary_color
color = initial(color)//looks better.
- overlays += blob_head_overlay
+ add_overlay(blob_head_overlay)
/mob/living/simple_mob/hostile/blob/spore/Life()
if(can_infest && !is_infesting && isturf(src.loc))
diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm
index b006fc7a0d6..3278aa23f8f 100644
--- a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm
@@ -102,7 +102,7 @@
display_name = "pilot qualification pin"
description = "An iron pin denoting the qualification to fly SCG spacecraft."
path = /obj/item/clothing/accessory/solgov/specialty/pilot
- allowed_roles = list("Pathfinder","Pilot","Field Medic","Talon Pilot")
+ allowed_roles = list("Pathfinder","Pilot","Field Medic","Talon Pilot")
/datum/gear/accessory/flops
display_name = "drop straps"
@@ -112,3 +112,11 @@
/datum/gear/accessory/flops/New()
..()
gear_tweaks += gear_tweak_free_color_choice
+
+/*
+Talon pin
+*/
+/datum/gear/accessory/talonpin
+ display_name = "ITV pin"
+ description = "A small enamel pin of the ITV logo."
+ path = /obj/item/clothing/accessory/talon
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_head_vr.dm b/code/modules/client/preference_setup/loadout/loadout_head_vr.dm
index d7add786c52..5dfabc578c3 100644
--- a/code/modules/client/preference_setup/loadout/loadout_head_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_head_vr.dm
@@ -47,4 +47,16 @@
/datum/gear/head/tigerpeltpink
display_name = "pink tiger pelt"
- path = /obj/item/clothing/head/pelt/tigerpeltpink
\ No newline at end of file
+ path = /obj/item/clothing/head/pelt/tigerpeltpink
+
+/*
+Talon hats
+*/
+/datum/gear/head/cap/talon
+ display_name = "cap, ITV"
+ path = /obj/item/clothing/head/soft/talon
+
+/datum/gear/head/beret/talon
+ display_name = "beret, ITV"
+ path = /obj/item/clothing/head/beret
+
diff --git a/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm b/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm
index 25dc8d4511a..881d4dd8b3e 100644
--- a/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm
@@ -72,4 +72,11 @@
/datum/gear/suit/oversize/New()
..()
- gear_tweaks += gear_tweak_free_color_choice
\ No newline at end of file
+ gear_tweaks += gear_tweak_free_color_choice
+
+/*
+Talon winter coat
+*/
+/datum/gear/suit/wintercoat/talon
+ display_name = "winter coat, ITV"
+ path = /obj/item/clothing/suit/storage/hooded/wintercoat/talon
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm b/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm
index 1f169dbc70c..bbbafe56722 100644
--- a/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm
@@ -215,4 +215,12 @@ Bluespace jumpsuit
/datum/gear/uniform/hfjumpsuit
display_name = "HYPER jumpsuit"
path = /obj/item/clothing/under/hyperfiber
- cost = 2
\ No newline at end of file
+ cost = 2
+
+/*
+Talon jumpsuit
+*/
+/datum/gear/uniform/talonbasic
+ display_name = "ITV Jumpsuit"
+ description = "A jumpsuit that is usually issued to ITV contractors, however others can purchase it to show their support towards ITV."
+ path = /obj/item/clothing/under/rank/talon/basic
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm b/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm
index 8f9f47a374e..3e76ac89349 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm
@@ -61,6 +61,10 @@
path = /obj/item/weapon/storage/backpack/dufflebag/explorer
allowed_roles = list("Pathfinder","Explorer")
+/datum/gear/utility/dufflebag/talon
+ display_name = "ITV dufflebag"
+ path = /obj/item/weapon/storage/backpack/dufflebag/explorer
+
/datum/gear/utility/ID
display_name = "contractor identification card"
path = /obj/item/weapon/card/id/event/polymorphic/altcard
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index a98e0898510..3d31c9e08fb 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -86,7 +86,8 @@ datum/preferences
"2" = "character_preview_map:2,5",
"4" = "character_preview_map:2,3",
"8" = "character_preview_map:2,1",
- "BG" = "character_preview_map:1,1 to 3,8"
+ "BG" = "character_preview_map:1,1 to 3,8",
+ "PMH" = "character_preview_map:2,7"
)
//Jobs, uses bitflags
@@ -270,6 +271,13 @@ datum/preferences
if(!client)
return
+ var/obj/screen/setup_preview/pm_helper/PMH = LAZYACCESS(char_render_holders, "PMH")
+ if(!PMH)
+ PMH = new
+ LAZYSET(char_render_holders, "PMH", PMH)
+ client.screen |= PMH
+ PMH.screen_loc = preview_screen_locs["PMH"]
+
var/obj/screen/setup_preview/bg/BG = LAZYACCESS(char_render_holders, "BG")
if(!BG)
BG = new
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index d0cb86230b4..c57c261322a 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -1,1096 +1,1094 @@
-/obj/item/clothing
- name = "clothing"
- siemens_coefficient = 0.9
- drop_sound = 'sound/items/drop/clothing.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
- var/list/species_restricted = null //Only these species can wear this kit.
- var/gunshot_residue //Used by forensics.
-
- var/list/accessories
- var/list/valid_accessory_slots
- var/list/restricted_accessory_slots
- var/list/starting_accessories
-
- var/flash_protection = FLASH_PROTECTION_NONE
- var/tint = TINT_NONE
- var/list/enables_planes //Enables these planes in the wearing mob's plane_holder
- var/list/plane_slots //But only if it's equipped into this specific slot
-
- /*
- Sprites used when the clothing item is refit. This is done by setting icon_override.
- For best results, if this is set then sprite_sheets should be null and vice versa, but that is by no means necessary.
- Ideally, sprite_sheets_refit should be used for "hard" clothing items that can't change shape very well to fit the wearer (e.g. helmets, hardsuits),
- while sprite_sheets should be used for "flexible" clothing items that do not need to be refitted (e.g. aliens wearing jumpsuits).
- */
- var/list/sprite_sheets_refit = null
- var/ear_protection = 0
- var/blood_sprite_state
-
- var/index //null by default, if set, will change which dmi it uses
-
- var/update_icon_define = null // Only needed if you've got multiple files for the same type of clothing
-
- var/polychromic = FALSE //VOREStation edit
-
-//Updates the icons of the mob wearing the clothing item, if any.
-/obj/item/clothing/proc/update_clothing_icon()
- return
-
-// Aurora forensics port.
-/obj/item/clothing/clean_blood()
- . = ..()
- gunshot_residue = null
-
-
-/obj/item/clothing/New()
- ..()
- if(starting_accessories)
- for(var/T in starting_accessories)
- var/obj/item/clothing/accessory/tie = new T(src)
- src.attach_accessory(null, tie)
- set_clothing_index()
-
- //VOREStation edit start
- if(polychromic)
- verbs |= /obj/item/clothing/proc/change_color
- //VOREStation edit start
-
-/obj/item/clothing/update_icon()
- overlays.Cut() //This removes all the overlays on the sprite and then goes down a checklist adding them as required.
- if(blood_DNA)
- add_blood()
- . = ..()
-
-/obj/item/clothing/equipped(var/mob/user,var/slot)
- ..()
- if(enables_planes)
- user.recalculate_vis()
-
-/obj/item/clothing/dropped(var/mob/user)
- ..()
- if(enables_planes)
- user.recalculate_vis()
-
-//BS12: Species-restricted clothing check.
-/obj/item/clothing/mob_can_equip(M as mob, slot, disable_warning = FALSE)
-
- //if we can't equip the item anyway, don't bother with species_restricted (cuts down on spam)
- if (!..())
- return 0
-
- if(LAZYLEN(species_restricted) && istype(M,/mob/living/carbon/human))
- var/exclusive = null
- var/wearable = null
- var/mob/living/carbon/human/H = M
-
- if("exclude" in species_restricted)
- exclusive = 1
-
- if(H.species)
- if(exclusive)
- if(!(H.species.get_bodytype(H) in species_restricted))
- wearable = 1
- else
- if(H.species.get_bodytype(H) in species_restricted)
- wearable = 1
-
- if(!wearable && !(slot in list(slot_l_store, slot_r_store, slot_s_store)))
- to_chat(H, "Your species cannot wear [src].")
- return 0
- return 1
-
-/obj/item/clothing/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
- . = ..()
- if((. == 0) && LAZYLEN(accessories))
- for(var/obj/item/I in accessories)
- var/check = I.handle_shield(user, damage, damage_source, attacker, def_zone, attack_text)
-
- if(check != 0) // Projectiles sometimes use negatives IIRC, 0 is only returned if something is not blocked.
- . = check
- break
-
-// For now, these two temp procs only return TRUE or FALSE if they can provide resistance to a given temperature.
-/obj/item/clothing/proc/handle_low_temperature(var/tempcheck = T20C)
- . = FALSE
- if(LAZYLEN(accessories))
- for(var/obj/item/clothing/C in accessories)
- if(C.handle_low_temperature(tempcheck))
- . = TRUE
-
- if(min_cold_protection_temperature && min_cold_protection_temperature <= tempcheck)
- . = TRUE
-
-/obj/item/clothing/proc/handle_high_temperature(var/tempcheck = T20C)
- . = FALSE
- if(LAZYLEN(accessories))
- for(var/obj/item/clothing/C in accessories)
- if(C.handle_high_temperature(tempcheck))
- . = TRUE
-
- if(max_heat_protection_temperature && max_heat_protection_temperature >= tempcheck)
- . = TRUE
-
-// Returns the relative flag-vars for covered protection.
-/obj/item/clothing/proc/get_cold_protection_flags()
- . = cold_protection
-
- if(LAZYLEN(accessories))
- for(var/obj/item/clothing/C in accessories)
- . |= C.get_cold_protection_flags()
-
-/obj/item/clothing/proc/get_heat_protection_flags()
- . = heat_protection
-
- if(LAZYLEN(accessories))
- for(var/obj/item/clothing/C in accessories)
- . |= C.get_heat_protection_flags()
-
-/obj/item/clothing/proc/refit_for_species(var/target_species)
- if(!species_restricted)
- return //this item doesn't use the species_restricted system
-
- //Set species_restricted list
- switch(target_species)
- //VOREStation Edit Start
- if(SPECIES_HUMAN, SPECIES_SKRELL) //humanoid bodytypes
- species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_RAPALA, SPECIES_VASILISSAN, SPECIES_ALRAUNE, SPECIES_PROMETHEAN, SPECIES_XENOCHIMERA)
- if(SPECIES_UNATHI)
- species_restricted = list(SPECIES_UNATHI, SPECIES_XENOHYBRID)
- if(SPECIES_VULPKANIN)
- species_restricted = list(SPECIES_VULPKANIN, SPECIES_ZORREN_HIGH, SPECIES_FENNEC)
- if(SPECIES_SERGAL)
- species_restricted = list(SPECIES_SERGAL, SPECIES_NEVREAN)
- //VOREStation Edit End
- else
- species_restricted = list(target_species)
-
- //Set icon
- if (sprite_sheets_refit && (target_species in sprite_sheets_refit))
- sprite_sheets[target_species] = sprite_sheets_refit[target_species]
-
- if (sprite_sheets_obj && (target_species in sprite_sheets_obj))
- icon = sprite_sheets_obj[target_species]
- else
- icon = initial(icon)
-
-//VOREStation edit start
-/obj/item/clothing/proc/change_color()
- set name = "Change Color"
- set category = "Object"
- set desc = "Change the color of the clothing."
- set src in usr
-
- if(usr.stat || usr.restrained() || usr.incapacitated())
- return
-
- var/new_color = input(usr, "Pick a new color", "Color", color) as color|null
-
- if(new_color && (new_color != color))
- color = new_color
- update_icon()
- update_clothing_icon()
-//VOREStation edit end
-
-/obj/item/clothing/head/helmet/refit_for_species(var/target_species)
- if(!species_restricted)
- return //this item doesn't use the species_restricted system
-
- //Set species_restricted list
- switch(target_species)
- //VOREStation Edit Start
- if(SPECIES_HUMAN)
- species_restricted = list(SPECIES_HUMAN, SPECIES_RAPALA, SPECIES_VASILISSAN, SPECIES_ALRAUNE, SPECIES_PROMETHEAN, SPECIES_XENOCHIMERA)
- if(SPECIES_SKRELL)
- species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_RAPALA, SPECIES_VASILISSAN, SPECIES_ALRAUNE, SPECIES_PROMETHEAN, SPECIES_XENOCHIMERA)
- if(SPECIES_UNATHI)
- species_restricted = list(SPECIES_UNATHI, SPECIES_XENOHYBRID)
- if(SPECIES_VULPKANIN)
- species_restricted = list(SPECIES_VULPKANIN, SPECIES_ZORREN_HIGH, SPECIES_FENNEC)
- if(SPECIES_SERGAL)
- species_restricted = list(SPECIES_SERGAL, SPECIES_NEVREAN)
- //VOREStation Edit End
- else
- species_restricted = list(target_species)
-
- //Set icon
- if (sprite_sheets_refit && (target_species in sprite_sheets_refit))
- sprite_sheets[target_species] = sprite_sheets_refit[target_species]
-
- if (sprite_sheets_obj && (target_species in sprite_sheets_obj))
- icon = sprite_sheets_obj[target_species]
- else
- icon = initial(icon)
-
-///////////////////////////////////////////////////////////////////////
-// Ears: headsets, earmuffs and tiny objects
-/obj/item/clothing/ears
- name = "ears"
- w_class = ITEMSIZE_TINY
- throwforce = 2
- slot_flags = SLOT_EARS
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/ears.dmi')
-
-/obj/item/clothing/ears/attack_hand(mob/user as mob)
- if (!user) return
-
- if (src.loc != user || !istype(user,/mob/living/carbon/human))
- ..()
- return
-
- var/mob/living/carbon/human/H = user
- if(H.l_ear != src && H.r_ear != src)
- ..()
- return
-
- if(!canremove)
- return
-
- var/obj/item/clothing/ears/O
- if(slot_flags & SLOT_TWOEARS )
- O = (H.l_ear == src ? H.r_ear : H.l_ear)
- user.u_equip(O)
- if(!istype(src,/obj/item/clothing/ears/offear))
- qdel(O)
- O = src
- else
- O = src
-
- user.unEquip(src)
-
- if (O)
- user.put_in_hands(O)
- O.add_fingerprint(user)
-
- if(istype(src,/obj/item/clothing/ears/offear))
- qdel(src)
-
-/obj/item/clothing/ears/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_ears()
-
-/obj/item/clothing/ears/MouseDrop(var/obj/over_object)
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- // If this covers both ears, we want to return the result of unequipping the primary object, and kill the off-ear one
- if(slot_flags & SLOT_TWOEARS)
- var/obj/item/clothing/ears/O = (H.l_ear == src ? H.r_ear : H.l_ear)
- if(istype(src, /obj/item/clothing/ears/offear))
- . = O.MouseDrop(over_object)
- H.drop_from_inventory(src)
- qdel(src)
- else
- . = ..()
- H.drop_from_inventory(O)
- qdel(O)
- else
- . = ..()
-
-
-/obj/item/clothing/ears/offear
- name = "Other ear"
- w_class = ITEMSIZE_HUGE
- icon = 'icons/mob/screen1_Midnight.dmi'
- icon_state = "block"
- slot_flags = SLOT_EARS | SLOT_TWOEARS
-
-/obj/item/clothing/ears/offear/New(var/obj/O)
- name = O.name
- desc = O.desc
- icon = O.icon
- icon_state = O.icon_state
- set_dir(O.dir)
-
-////////////////////////////////////////////////////////////////////////////////////////
-//Gloves
-/obj/item/clothing/gloves
- name = "gloves"
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_gloves.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_gloves.dmi',
- )
- gender = PLURAL //Carn: for grammarically correct text-parsing
- w_class = ITEMSIZE_SMALL
- icon = 'icons/obj/clothing/gloves.dmi'
- siemens_coefficient = 0.9
- blood_sprite_state = "bloodyhands"
- var/wired = 0
- var/obj/item/weapon/cell/cell = 0
- var/fingerprint_chance = 0 //How likely the glove is to let fingerprints through
- var/obj/item/clothing/gloves/ring = null //Covered ring
- var/mob/living/carbon/human/wearer = null //Used for covered rings when dropping
- var/glove_level = 2 //What "layer" the glove is on
- var/overgloves = 0 //Used by gauntlets and arm_guards
- var/punch_force = 0 //How much damage do these gloves add to a punch?
- var/punch_damtype = BRUTE //What type of damage does this make fists be?
- body_parts_covered = HANDS
- slot_flags = SLOT_GLOVES
- attack_verb = list("challenged")
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/gloves.dmi',
- SPECIES_VOX = 'icons/mob/species/vox/gloves.dmi'
- )
- drop_sound = 'sound/items/drop/gloves.ogg'
- pickup_sound = 'sound/items/pickup/gloves.ogg'
-
-/obj/item/clothing/proc/set_clothing_index()
- return
-
-/obj/item/clothing/gloves/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_gloves()
-
-/obj/item/clothing/gloves/emp_act(severity)
- if(cell)
- cell.emp_act(severity)
- if(ring)
- ring.emp_act(severity)
- ..()
-
-// Called just before an attack_hand(), in mob/UnarmedAttack()
-/obj/item/clothing/gloves/proc/Touch(var/atom/A, var/proximity)
- return 0 // return 1 to cancel attack_hand()
-
-/*/obj/item/clothing/gloves/attackby(obj/item/weapon/W, mob/user)
- if(W.is_wirecutter() || istype(W, /obj/item/weapon/scalpel))
- if (clipped)
- to_chat(user, "The [src] have already been clipped!")
- update_icon()
- return
-
- playsound(src, W.usesound, 50, 1)
- user.visible_message("[user] cuts the fingertips off of the [src].","You cut the fingertips off of the [src].")
-
- clipped = 1
- name = "modified [name]"
- desc = "[desc] They have had the fingertips cut off of them."
- if("exclude" in species_restricted)
- species_restricted -= SPECIES_UNATHI
- species_restricted -= SPECIES_TAJ
- return
-*/
-
-/obj/item/clothing/gloves/clean_blood()
- . = ..()
- transfer_blood = 0
- update_icon()
-
-/obj/item/clothing/gloves/mob_can_equip(mob/user, slot, disable_warning = FALSE)
- var/mob/living/carbon/human/H = user
-
- if(slot && slot == slot_gloves)
- var/obj/item/clothing/gloves/G = H.gloves
- if(istype(G))
- ring = H.gloves
- if(ring.glove_level >= src.glove_level)
- to_chat(user, "You are unable to wear \the [src] as \the [H.gloves] are in the way.")
- ring = null
- return 0
- else
- H.drop_from_inventory(ring) //Remove the ring (or other under-glove item in the hand slot?) so you can put on the gloves.
- ring.forceMove(src)
- to_chat(user, "You slip \the [src] on over \the [src.ring].")
- if(!(flags & THICKMATERIAL))
- punch_force += ring.punch_force
- else
- ring = null
-
- if(!..())
- if(ring) //Put the ring back on if the check fails.
- if(H.equip_to_slot_if_possible(ring, slot_gloves))
- src.ring = null
- punch_force = initial(punch_force)
- return 0
-
- wearer = H //TODO clean this when magboots are cleaned
- return 1
-
-/obj/item/clothing/gloves/dropped()
- ..()
-
- if(!wearer)
- return
-
- var/mob/living/carbon/human/H = wearer
- if(ring && istype(H))
- if(!H.equip_to_slot_if_possible(ring, slot_gloves))
- ring.forceMove(get_turf(src))
- src.ring = null
- punch_force = initial(punch_force)
- wearer = null
-
-/obj/item/clothing/gloves
- var/datum/unarmed_attack/special_attack = null //do the gloves have a special unarmed attack?
- var/special_attack_type = null
-
-/obj/item/clothing/gloves/New()
- ..()
- if(special_attack_type && ispath(special_attack_type))
- special_attack = new special_attack_type
-
-
-
-/////////////////////////////////////////////////////////////////////
-//Rings
-
-/obj/item/clothing/gloves/ring
- name = "ring"
- w_class = ITEMSIZE_TINY
- icon = 'icons/obj/clothing/rings.dmi'
- gender = NEUTER
- species_restricted = list("exclude", SPECIES_DIONA)
- siemens_coefficient = 1
- glove_level = 1
- fingerprint_chance = 100
- punch_force = 2
- body_parts_covered = 0
- drop_sound = 'sound/items/drop/ring.ogg'
- pickup_sound = 'sound/items/pickup/ring.ogg'
-
-///////////////////////////////////////////////////////////////////////
-//Head
-/obj/item/clothing/head
- name = "head"
- icon = 'icons/obj/clothing/hats.dmi'
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_hats.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_hats.dmi',
- )
- body_parts_covered = HEAD
- slot_flags = SLOT_HEAD
- w_class = ITEMSIZE_SMALL
- blood_sprite_state = "helmetblood"
-
- var/light_overlay = "helmet_light"
- var/light_applied
- var/brightness_on
- var/on = 0
- var/image/helmet_light
-
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/head.dmi',
- SPECIES_VOX = 'icons/mob/species/vox/head.dmi'
- )
- drop_sound = 'sound/items/drop/hat.ogg'
- pickup_sound = 'sound/items/pickup/hat.ogg'
-
-/obj/item/clothing/head/attack_self(mob/user)
- if(brightness_on)
- if(!isturf(user.loc))
- to_chat(user, "You cannot turn the light on while in this [user.loc]")
- return
- on = !on
- to_chat(user, "You [on ? "enable" : "disable"] the helmet light.")
- update_flashlight(user)
- else
- return ..(user)
-
-/obj/item/clothing/head/proc/update_flashlight(var/mob/user = null)
- if(on && !light_applied)
- set_light(brightness_on)
- light_applied = 1
- else if(!on && light_applied)
- set_light(0)
- light_applied = 0
- update_icon(user)
- user.update_action_buttons()
-
-/obj/item/clothing/head/attack_ai(var/mob/user)
- if(!mob_wear_hat(user))
- return ..()
-
-/obj/item/clothing/head/attack_generic(var/mob/user)
- if(!mob_wear_hat(user))
- return ..()
-
-/obj/item/clothing/head/proc/mob_wear_hat(var/mob/user)
- if(!Adjacent(user))
- return 0
- var/success
- if(istype(user, /mob/living/silicon/robot/drone))
- var/mob/living/silicon/robot/drone/D = user
- if(D.hat)
- success = 2
- else
- D.wear_hat(src)
- success = 1
- else if(istype(user, /mob/living/carbon/alien/diona))
- var/mob/living/carbon/alien/diona/D = user
- if(D.hat)
- success = 2
- else
- D.wear_hat(src)
- success = 1
-
- if(!success)
- return 0
- else if(success == 2)
- to_chat(user, "You are already wearing a hat.")
- else if(success == 1)
- to_chat(user, "You crawl under \the [src].")
- return 1
-
-/obj/item/clothing/head/update_icon(var/mob/user)
- var/mob/living/carbon/human/H
- if(ishuman(user))
- H = user
-
- if(on)
- // Generate object icon.
- if(!light_overlay_cache["[light_overlay]_icon"])
- light_overlay_cache["[light_overlay]_icon"] = image(icon = 'icons/obj/light_overlays.dmi', icon_state = "[light_overlay]")
- helmet_light = light_overlay_cache["[light_overlay]_icon"]
- add_overlay(helmet_light)
-
- // Generate and cache the on-mob icon, which is used in update_inv_head().
- var/body_type = (H && H.species.get_bodytype(H))
- var/cache_key = "[light_overlay][body_type && sprite_sheets[body_type] ? "_[body_type]" : ""]"
- if(!light_overlay_cache[cache_key])
- var/use_icon = LAZYACCESS(sprite_sheets,body_type) || 'icons/mob/light_overlays.dmi'
- light_overlay_cache[cache_key] = image(icon = use_icon, icon_state = "[light_overlay]")
-
- else if(helmet_light)
- cut_overlay(helmet_light)
- helmet_light = null
-
- user.update_inv_head() //Will redraw the helmet with the light on the mob
-
-/obj/item/clothing/head/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_head()
-
-///////////////////////////////////////////////////////////////////////
-//Mask
-/obj/item/clothing/mask
- name = "mask"
- icon = 'icons/obj/clothing/masks.dmi'
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_masks.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_masks.dmi',
- )
- body_parts_covered = HEAD
- slot_flags = SLOT_MASK
- body_parts_covered = FACE|EYES
- blood_sprite_state = "maskblood"
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/masks.dmi',
- SPECIES_VOX = 'icons/mob/species/vox/masks.dmi',
- SPECIES_TAJ = 'icons/mob/species/tajaran/mask.dmi',
- SPECIES_UNATHI = 'icons/mob/species/unathi/mask.dmi'
- )
-
- var/voicechange = 0
- var/list/say_messages
- var/list/say_verbs
-
- drop_sound = "generic_drop"
- pickup_sound = "generic_pickup"
-
-/obj/item/clothing/mask/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_wear_mask()
-
-/obj/item/clothing/mask/proc/filter_air(datum/gas_mixture/air)
- return
-
-///////////////////////////////////////////////////////////////////////
-//Shoes
-/obj/item/clothing/shoes
- name = "shoes"
- icon = 'icons/obj/clothing/shoes.dmi'
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_shoes.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_shoes.dmi',
- )
- desc = "Comfortable-looking shoes."
- gender = PLURAL //Carn: for grammarically correct text-parsing
- siemens_coefficient = 0.9
- body_parts_covered = FEET
- slot_flags = SLOT_FEET
- blood_sprite_state = "shoeblood"
-
- var/can_hold_knife = 0
- var/obj/item/holding
-
- var/shoes_under_pants = 0
-
- var/water_speed = 0 //Speed boost/decrease in water, lower/negative values mean more speed
- var/snow_speed = 0 //Speed boost/decrease on snow, lower/negative values mean more speed
- var/rock_climbing = FALSE // If true, allows climbing cliffs with clickdrag.
-
- var/step_volume_mod = 1 //How quiet or loud footsteps in this shoe are
-
- permeability_coefficient = 0.50
- slowdown = SHOES_SLOWDOWN
- force = 2
- var/overshoes = 0
- species_restricted = list("exclude",SPECIES_TESHARI, SPECIES_VOX)
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/shoes.dmi',
- SPECIES_VOX = 'icons/mob/species/vox/shoes.dmi'
- )
- drop_sound = 'sound/items/drop/shoes.ogg'
- pickup_sound = 'sound/items/pickup/shoes.ogg'
-
-/obj/item/clothing/shoes/proc/draw_knife()
- set name = "Draw Boot Knife"
- set desc = "Pull out your boot knife."
- set category = "IC"
- set src in usr
-
- if(usr.stat || usr.restrained() || usr.incapacitated())
- return
-
- holding.forceMove(get_turf(usr))
-
- if(usr.put_in_hands(holding))
- usr.visible_message("\The [usr] pulls a knife out of their boot!")
- playsound(src, 'sound/weapons/holster/sheathout.ogg', 25)
- holding = null
- overlays -= image(icon, "[icon_state]_knife")
- else
- to_chat(usr, "Your need an empty, unbroken hand to do that.")
- holding.forceMove(src)
-
- if(!holding)
- verbs -= /obj/item/clothing/shoes/proc/draw_knife
-
- update_icon()
- return
-
-/obj/item/clothing/shoes/attack_hand(var/mob/living/M)
- if(can_hold_knife == 1 && holding && src.loc == M)
- draw_knife()
- return
- ..()
-
-/obj/item/clothing/shoes/attackby(var/obj/item/I, var/mob/user)
- if((can_hold_knife == 1) && (istype(I, /obj/item/weapon/material/shard) || \
- istype(I, /obj/item/weapon/material/butterfly) || \
- istype(I, /obj/item/weapon/material/kitchen/utensil) || \
- istype(I, /obj/item/weapon/material/knife/tacknife)))
- if(holding)
- to_chat(user, "\The [src] is already holding \a [holding].")
- return
- user.unEquip(I)
- I.forceMove(src)
- holding = I
- user.visible_message("\The [user] shoves \the [I] into \the [src].")
- verbs |= /obj/item/clothing/shoes/proc/draw_knife
- update_icon()
- else
- return ..()
-
-/obj/item/clothing/shoes/verb/toggle_layer()
- set name = "Switch Shoe Layer"
- set category = "Object"
-
- if(shoes_under_pants == -1)
- to_chat(usr, "\The [src] cannot be worn above your suit!")
- return
- shoes_under_pants = !shoes_under_pants
- update_icon()
-
-/obj/item/clothing/shoes/update_icon()
- . = ..()
- if(holding)
- overlays += image(icon, "[icon_state]_knife")
- if(contaminated)
- overlays += contamination_overlay
- if(gurgled) //VOREStation Edit Start
- decontaminate()
- gurgle_contaminate() //VOREStation Edit End
- if(ismob(usr))
- var/mob/M = usr
- M.update_inv_shoes()
-
-/obj/item/clothing/shoes/clean_blood()
- update_icon()
- return ..()
-
-/obj/item/clothing/shoes/proc/handle_movement(var/turf/walking, var/running)
- if(prob(1) && !recent_squish) //VOREStation edit begin
- recent_squish = 1
- spawn(100)
- recent_squish = 0
- for(var/mob/living/M in contents)
- var/emote = pick(inside_emotes)
- to_chat(M,emote) //VOREStation edit end
- return
-
-/obj/item/clothing/shoes/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_shoes()
-
-
-///////////////////////////////////////////////////////////////////////
-//Suit
-/obj/item/clothing/suit
- icon = 'icons/obj/clothing/suits.dmi'
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_suits.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_suits.dmi',
- )
- name = "suit"
- var/fire_resist = T0C+100
- body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS
- allowed = list(/obj/item/weapon/tank/emergency/oxygen)
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
- slot_flags = SLOT_OCLOTHING
- var/blood_overlay_type = "suit"
- blood_sprite_state = "suitblood" //Defaults to the suit's blood overlay, so that some blood renders instead of no blood.
-
- var/taurized = FALSE
- siemens_coefficient = 0.9
- w_class = ITEMSIZE_NORMAL
- preserve_item = 1
- equip_sound = 'sound/items/jumpsuit_equip.ogg'
-
-
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/suit.dmi',
- SPECIES_VOX = 'icons/mob/species/vox/suit.dmi'
- )
-
- valid_accessory_slots = (ACCESSORY_SLOT_OVER | ACCESSORY_SLOT_ARMBAND)
- restricted_accessory_slots = (ACCESSORY_SLOT_ARMBAND)
-
-/obj/item/clothing/suit/set_clothing_index()
- ..()
-
- if(index && !icon_override)
- icon = new /icon("icons/obj/clothing/suits_[index].dmi")
- item_icons = list(
- slot_l_hand_str = new /icon("icons/mob/items/lefthand_suits_[index].dmi"),
- slot_r_hand_str = new /icon("icons/mob/items/righthand_suits_[index].dmi"),
- )
-
- return 1
-
- return 0
-
-/obj/item/clothing/suit/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_wear_suit()
-
- set_clothing_index()
-
-/obj/item/clothing/suit/equipped(var/mob/user, var/slot)
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if((taurized && !isTaurTail(H.tail_style)) || (!taurized && isTaurTail(H.tail_style)))
- taurize(user)
-
- return ..()
-
-/obj/item/clothing/suit/proc/taurize(var/mob/living/carbon/human/Taur)
- if(isTaurTail(Taur.tail_style))
- var/datum/sprite_accessory/tail/taur/taurtail = Taur.tail_style
- if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in cached_icon_states(taurtail.suit_sprites)))
- icon_override = taurtail.suit_sprites
- taurized = TRUE
-
- if(!taurized)
- icon_override = initial(icon_override)
- taurized = FALSE
-
-// Taur suits need to be shifted so its centered on their taur half.
-/obj/item/clothing/suit/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer = 0,var/icon/clip_mask)
- var/image/standing = ..()
- if(taurized) //Special snowflake var on suits
- standing.pixel_x = -16
- standing.layer = BODY_LAYER + 15 // 15 is above tail layer, so will not be covered by taurbody.
- return standing
-
-/obj/item/clothing/suit/apply_accessories(var/image/standing)
- if(LAZYLEN(accessories) && taurized)
- for(var/obj/item/clothing/accessory/A in accessories)
- var/image/I = new(A.get_mob_overlay())
- I.pixel_x = 16 //Opposite of the pixel_x on the suit (-16) from taurization to cancel it out and puts the accessory in the correct place on the body.
- standing.add_overlay(I)
- else
- return ..()
-
-
-///////////////////////////////////////////////////////////////////////
-//Under clothing
-/obj/item/clothing/under
- icon = 'icons/obj/clothing/uniforms.dmi'
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_uniforms.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_uniforms.dmi',
- )
- name = "under"
- body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
- permeability_coefficient = 0.90
- slot_flags = SLOT_ICLOTHING
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
- equip_sound = 'sound/items/jumpsuit_equip.ogg'
- w_class = ITEMSIZE_NORMAL
- show_messages = 1
- blood_sprite_state = "uniformblood"
-
- var/has_sensor = 1 //For the crew computer 2 = unable to change mode
- var/sensor_mode = 0
- /*
- 1 = Report living/dead
- 2 = Report detailed damages
- 3 = Report location
- */
- var/displays_id = 1
- var/rolled_down = -1 //0 = unrolled, 1 = rolled, -1 = cannot be toggled
- var/rolled_sleeves = -1 //0 = unrolled, 1 = rolled, -1 = cannot be toggled
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/teshari/uniform.dmi',
- SPECIES_VOX = 'icons/mob/species/vox/uniform.dmi'
- )
-
- //convenience var for defining the icon state for the overlay used when the clothing is worn.
- //Also used by rolling/unrolling.
- var/worn_state = null
- valid_accessory_slots = (\
- ACCESSORY_SLOT_UTILITY\
- |ACCESSORY_SLOT_WEAPON\
- |ACCESSORY_SLOT_ARMBAND\
- |ACCESSORY_SLOT_DECOR\
- |ACCESSORY_SLOT_MEDAL\
- |ACCESSORY_SLOT_INSIGNIA\
- |ACCESSORY_SLOT_TIE\
- |ACCESSORY_SLOT_RANK\
- |ACCESSORY_SLOT_DEPT\
- |ACCESSORY_SLOT_OVER)
- restricted_accessory_slots = (\
- ACCESSORY_SLOT_UTILITY\
- |ACCESSORY_SLOT_WEAPON\
- |ACCESSORY_SLOT_ARMBAND\
- |ACCESSORY_SLOT_TIE\
- |ACCESSORY_SLOT_RANK\
- |ACCESSORY_SLOT_DEPT\
- |ACCESSORY_SLOT_OVER)
-
- var/icon/rolled_down_icon = 'icons/mob/uniform_rolled_down.dmi'
- var/icon/rolled_down_sleeves_icon = 'icons/mob/uniform_sleeves_rolled.dmi'
-
-/obj/item/clothing/under/attack_hand(var/mob/user)
- if(LAZYLEN(accessories))
- ..()
- if ((ishuman(usr) || issmall(usr)) && src.loc == user)
- return
- ..()
-
-/obj/item/clothing/under/New()
- ..()
- if(worn_state)
- if(!item_state_slots)
- item_state_slots = list()
- item_state_slots[slot_w_uniform_str] = worn_state
- else
- worn_state = icon_state
-
- //autodetect rollability
- if(rolled_down < 0)
- 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)
- verbs -= /obj/item/clothing/under/verb/rollsuit
- if(rolled_sleeves == -1)
- verbs -= /obj/item/clothing/under/verb/rollsleeves
-
-/obj/item/clothing/under/set_clothing_index()
- ..()
-
- if(index && !icon_override)
- icon = new /icon("icons/obj/clothing/uniforms_[index].dmi")
-
- item_icons = list(
- slot_l_hand_str = new /icon("icons/mob/items/lefthand_uniforms_[index].dmi"),
- slot_r_hand_str = new /icon("icons/mob/items/righthand_uniforms_[index].dmi"),
- )
-
- rolled_down_icon = new /icon("icons/mob/uniform_rolled_down_[index].dmi")
- rolled_down_sleeves_icon = new /icon("icons/mob/uniform_sleeves_rolled_[index].dmi")
- return 1
-
- return 0
-
-/obj/item/clothing/under/proc/update_rolldown_status()
- var/mob/living/carbon/human/H
- if(istype(src.loc, /mob/living/carbon/human))
- H = src.loc
-
- var/icon/under_icon
- if(icon_override)
- under_icon = icon_override
- else if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)])
- 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 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 cached_icon_states(under_icon))) || ("[worn_state]_d_s" in cached_icon_states(under_icon)))
- if(rolled_down != 1)
- rolled_down = 0
- else
- rolled_down = -1
- if(H) update_clothing_icon()
-
-/obj/item/clothing/under/proc/update_rollsleeves_status()
- var/mob/living/carbon/human/H
- if(istype(src.loc, /mob/living/carbon/human))
- H = src.loc
-
- var/icon/under_icon
- if(icon_override)
- under_icon = icon_override
- else if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)])
- 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 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 cached_icon_states(under_icon))) || ("[worn_state]_r_s" in cached_icon_states(under_icon)))
- if(rolled_sleeves != 1)
- rolled_sleeves = 0
- else
- rolled_sleeves = -1
- if(H) update_clothing_icon()
-
-/obj/item/clothing/under/update_clothing_icon()
- if (ismob(src.loc))
- var/mob/M = src.loc
- M.update_inv_w_uniform()
-
- set_clothing_index()
-
-
-/obj/item/clothing/under/examine(mob/user)
- . = ..()
- switch(src.sensor_mode)
- if(0)
- . += "Its sensors appear to be disabled."
- if(1)
- . += "Its binary life sensors appear to be enabled."
- if(2)
- . += "Its vital tracker appears to be enabled."
- if(3)
- . += "Its vital tracker and tracking beacon appear to be enabled."
-
-/obj/item/clothing/under/proc/set_sensors(mob/usr as mob)
- var/mob/M = usr
- if (istype(M, /mob/observer)) return
- if (usr.stat || usr.restrained()) return
- if(has_sensor >= 2)
- to_chat(usr, "The controls are locked.")
- return 0
- if(has_sensor <= 0)
- to_chat(usr, "This suit does not have any sensors.")
- return 0
-
- var/list/modes = list("Off", "Binary sensors", "Vitals tracker", "Tracking beacon")
- var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes
- if(get_dist(usr, src) > 1)
- to_chat(usr, "You have moved too far away.")
- return
- sensor_mode = modes.Find(switchMode) - 1
-
- if (src.loc == usr)
- switch(sensor_mode)
- if(0)
- usr.visible_message("[usr] adjusts their sensors.", "You disable your suit's remote sensing equipment.")
- if(1)
- usr.visible_message("[usr] adjusts their sensors.", "Your suit will now report whether you are live or dead.")
- if(2)
- usr.visible_message("[usr] adjusts their sensors.", "Your suit will now report your vital lifesigns.")
- if(3)
- usr.visible_message("[usr] adjusts their sensors.", "Your suit will now report your vital lifesigns as well as your coordinate position.")
-
- else if (istype(src.loc, /mob))
- usr.visible_message("[usr] adjusts [src.loc]'s sensors.", "You adjust [src.loc]'s sensors.")
-
-/obj/item/clothing/under/verb/toggle()
- set name = "Toggle Suit Sensors"
- set category = "Object"
- set src in usr
- set_sensors(usr)
-
-/obj/item/clothing/under/verb/rollsuit()
- set name = "Roll Down Jumpsuit"
- set category = "Object"
- set src in usr
- if(!istype(usr, /mob/living)) return
- if(usr.stat) return
-
- update_rolldown_status()
- if(rolled_down == -1)
- to_chat(usr, "You cannot roll down [src]!")
- return
- if((rolled_sleeves == 1) && !(rolled_down))
- rolled_sleeves = 0
-
- rolled_down = !rolled_down
- if(rolled_down)
- body_parts_covered = initial(body_parts_covered)
- body_parts_covered &= ~(UPPER_TORSO|ARMS)
- 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
- item_state_slots[slot_w_uniform_str] = "[worn_state]_d"
-
- to_chat(usr, "You roll down your [src].")
- else
- body_parts_covered = initial(body_parts_covered)
- if(icon_override == rolled_down_icon)
- icon_override = initial(icon_override)
- item_state_slots[slot_w_uniform_str] = "[worn_state]"
- to_chat(usr, "You roll up your [src].")
- update_clothing_icon()
-
-/obj/item/clothing/under/verb/rollsleeves()
- set name = "Roll Up Sleeves"
- set category = "Object"
- set src in usr
- if(!istype(usr, /mob/living)) return
- if(usr.stat) return
-
- update_rollsleeves_status()
- if(rolled_sleeves == -1)
- to_chat(usr, "You cannot roll up your [src]'s sleeves!")
- return
- if(rolled_down == 1)
- to_chat(usr, "You must roll up your [src] first!")
- return
-
- rolled_sleeves = !rolled_sleeves
- if(rolled_sleeves)
- body_parts_covered &= ~(ARMS)
- 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
- item_state_slots[slot_w_uniform_str] = "[worn_state]_r"
- to_chat(usr, "You roll up your [src]'s sleeves.")
- else
- body_parts_covered = initial(body_parts_covered)
- if(icon_override == rolled_down_sleeves_icon)
- icon_override = initial(icon_override)
- item_state_slots[slot_w_uniform_str] = "[worn_state]"
- to_chat(usr, "You roll down your [src]'s sleeves.")
- update_clothing_icon()
-
-/obj/item/clothing/under/rank/New()
- sensor_mode = pick(0,1,2,3)
- ..()
+/obj/item/clothing
+ name = "clothing"
+ siemens_coefficient = 0.9
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+ var/list/species_restricted = null //Only these species can wear this kit.
+ var/gunshot_residue //Used by forensics.
+
+ var/list/accessories
+ var/list/valid_accessory_slots
+ var/list/restricted_accessory_slots
+ var/list/starting_accessories
+
+ var/flash_protection = FLASH_PROTECTION_NONE
+ var/tint = TINT_NONE
+ var/list/enables_planes //Enables these planes in the wearing mob's plane_holder
+ var/list/plane_slots //But only if it's equipped into this specific slot
+
+ /*
+ Sprites used when the clothing item is refit. This is done by setting icon_override.
+ For best results, if this is set then sprite_sheets should be null and vice versa, but that is by no means necessary.
+ Ideally, sprite_sheets_refit should be used for "hard" clothing items that can't change shape very well to fit the wearer (e.g. helmets, hardsuits),
+ while sprite_sheets should be used for "flexible" clothing items that do not need to be refitted (e.g. aliens wearing jumpsuits).
+ */
+ var/list/sprite_sheets_refit = null
+ var/ear_protection = 0
+ var/blood_sprite_state
+
+ var/index //null by default, if set, will change which dmi it uses
+
+ var/update_icon_define = null // Only needed if you've got multiple files for the same type of clothing
+
+ var/polychromic = FALSE //VOREStation edit
+
+//Updates the icons of the mob wearing the clothing item, if any.
+/obj/item/clothing/proc/update_clothing_icon()
+ return
+
+// Aurora forensics port.
+/obj/item/clothing/clean_blood()
+ . = ..()
+ gunshot_residue = null
+
+
+/obj/item/clothing/New()
+ ..()
+ if(starting_accessories)
+ for(var/T in starting_accessories)
+ var/obj/item/clothing/accessory/tie = new T(src)
+ src.attach_accessory(null, tie)
+ set_clothing_index()
+
+ //VOREStation edit start
+ if(polychromic)
+ verbs |= /obj/item/clothing/proc/change_color
+ //VOREStation edit start
+
+/obj/item/clothing/update_icon()
+ cut_overlays() //This removes all the overlays on the sprite and then goes down a checklist adding them as required.
+ if(blood_DNA)
+ add_blood()
+ . = ..()
+
+/obj/item/clothing/equipped(var/mob/user,var/slot)
+ ..()
+ if(enables_planes)
+ user.recalculate_vis()
+
+/obj/item/clothing/dropped(var/mob/user)
+ ..()
+ if(enables_planes)
+ user.recalculate_vis()
+
+//BS12: Species-restricted clothing check.
+/obj/item/clothing/mob_can_equip(M as mob, slot, disable_warning = FALSE)
+
+ //if we can't equip the item anyway, don't bother with species_restricted (cuts down on spam)
+ if (!..())
+ return 0
+
+ if(LAZYLEN(species_restricted) && istype(M,/mob/living/carbon/human))
+ var/exclusive = null
+ var/wearable = null
+ var/mob/living/carbon/human/H = M
+
+ if("exclude" in species_restricted)
+ exclusive = 1
+
+ if(H.species)
+ if(exclusive)
+ if(!(H.species.get_bodytype(H) in species_restricted))
+ wearable = 1
+ else
+ if(H.species.get_bodytype(H) in species_restricted)
+ wearable = 1
+
+ if(!wearable && !(slot in list(slot_l_store, slot_r_store, slot_s_store)))
+ to_chat(H, "Your species cannot wear [src].")
+ return 0
+ return 1
+
+/obj/item/clothing/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
+ . = ..()
+ if((. == 0) && LAZYLEN(accessories))
+ for(var/obj/item/I in accessories)
+ var/check = I.handle_shield(user, damage, damage_source, attacker, def_zone, attack_text)
+
+ if(check != 0) // Projectiles sometimes use negatives IIRC, 0 is only returned if something is not blocked.
+ . = check
+ break
+
+// For now, these two temp procs only return TRUE or FALSE if they can provide resistance to a given temperature.
+/obj/item/clothing/proc/handle_low_temperature(var/tempcheck = T20C)
+ . = FALSE
+ if(LAZYLEN(accessories))
+ for(var/obj/item/clothing/C in accessories)
+ if(C.handle_low_temperature(tempcheck))
+ . = TRUE
+
+ if(min_cold_protection_temperature && min_cold_protection_temperature <= tempcheck)
+ . = TRUE
+
+/obj/item/clothing/proc/handle_high_temperature(var/tempcheck = T20C)
+ . = FALSE
+ if(LAZYLEN(accessories))
+ for(var/obj/item/clothing/C in accessories)
+ if(C.handle_high_temperature(tempcheck))
+ . = TRUE
+
+ if(max_heat_protection_temperature && max_heat_protection_temperature >= tempcheck)
+ . = TRUE
+
+// Returns the relative flag-vars for covered protection.
+/obj/item/clothing/proc/get_cold_protection_flags()
+ . = cold_protection
+
+ if(LAZYLEN(accessories))
+ for(var/obj/item/clothing/C in accessories)
+ . |= C.get_cold_protection_flags()
+
+/obj/item/clothing/proc/get_heat_protection_flags()
+ . = heat_protection
+
+ if(LAZYLEN(accessories))
+ for(var/obj/item/clothing/C in accessories)
+ . |= C.get_heat_protection_flags()
+
+/obj/item/clothing/proc/refit_for_species(var/target_species)
+ if(!species_restricted)
+ return //this item doesn't use the species_restricted system
+
+ //Set species_restricted list
+ switch(target_species)
+ //VOREStation Edit Start
+ if(SPECIES_HUMAN, SPECIES_SKRELL) //humanoid bodytypes
+ species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_RAPALA, SPECIES_VASILISSAN, SPECIES_ALRAUNE, SPECIES_PROMETHEAN, SPECIES_XENOCHIMERA)
+ if(SPECIES_UNATHI)
+ species_restricted = list(SPECIES_UNATHI, SPECIES_XENOHYBRID)
+ if(SPECIES_VULPKANIN)
+ species_restricted = list(SPECIES_VULPKANIN, SPECIES_ZORREN_HIGH, SPECIES_FENNEC)
+ if(SPECIES_SERGAL)
+ species_restricted = list(SPECIES_SERGAL, SPECIES_NEVREAN)
+ //VOREStation Edit End
+ else
+ species_restricted = list(target_species)
+
+ //Set icon
+ if (sprite_sheets_refit && (target_species in sprite_sheets_refit))
+ sprite_sheets[target_species] = sprite_sheets_refit[target_species]
+
+ if (sprite_sheets_obj && (target_species in sprite_sheets_obj))
+ icon = sprite_sheets_obj[target_species]
+ else
+ icon = initial(icon)
+
+//VOREStation edit start
+/obj/item/clothing/proc/change_color()
+ set name = "Change Color"
+ set category = "Object"
+ set desc = "Change the color of the clothing."
+ set src in usr
+
+ if(usr.stat || usr.restrained() || usr.incapacitated())
+ return
+
+ var/new_color = input(usr, "Pick a new color", "Color", color) as color|null
+
+ if(new_color && (new_color != color))
+ color = new_color
+ update_icon()
+ update_clothing_icon()
+//VOREStation edit end
+
+/obj/item/clothing/head/helmet/refit_for_species(var/target_species)
+ if(!species_restricted)
+ return //this item doesn't use the species_restricted system
+
+ //Set species_restricted list
+ switch(target_species)
+ //VOREStation Edit Start
+ if(SPECIES_HUMAN)
+ species_restricted = list(SPECIES_HUMAN, SPECIES_RAPALA, SPECIES_VASILISSAN, SPECIES_ALRAUNE, SPECIES_PROMETHEAN, SPECIES_XENOCHIMERA)
+ if(SPECIES_SKRELL)
+ species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_RAPALA, SPECIES_VASILISSAN, SPECIES_ALRAUNE, SPECIES_PROMETHEAN, SPECIES_XENOCHIMERA)
+ if(SPECIES_UNATHI)
+ species_restricted = list(SPECIES_UNATHI, SPECIES_XENOHYBRID)
+ if(SPECIES_VULPKANIN)
+ species_restricted = list(SPECIES_VULPKANIN, SPECIES_ZORREN_HIGH, SPECIES_FENNEC)
+ if(SPECIES_SERGAL)
+ species_restricted = list(SPECIES_SERGAL, SPECIES_NEVREAN)
+ //VOREStation Edit End
+ else
+ species_restricted = list(target_species)
+
+ //Set icon
+ if (sprite_sheets_refit && (target_species in sprite_sheets_refit))
+ sprite_sheets[target_species] = sprite_sheets_refit[target_species]
+
+ if (sprite_sheets_obj && (target_species in sprite_sheets_obj))
+ icon = sprite_sheets_obj[target_species]
+ else
+ icon = initial(icon)
+
+///////////////////////////////////////////////////////////////////////
+// Ears: headsets, earmuffs and tiny objects
+/obj/item/clothing/ears
+ name = "ears"
+ w_class = ITEMSIZE_TINY
+ throwforce = 2
+ slot_flags = SLOT_EARS
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/ears.dmi')
+
+/obj/item/clothing/ears/attack_hand(mob/user as mob)
+ if (!user) return
+
+ if (src.loc != user || !istype(user,/mob/living/carbon/human))
+ ..()
+ return
+
+ var/mob/living/carbon/human/H = user
+ if(H.l_ear != src && H.r_ear != src)
+ ..()
+ return
+
+ if(!canremove)
+ return
+
+ var/obj/item/clothing/ears/O
+ if(slot_flags & SLOT_TWOEARS )
+ O = (H.l_ear == src ? H.r_ear : H.l_ear)
+ user.u_equip(O)
+ if(!istype(src,/obj/item/clothing/ears/offear))
+ qdel(O)
+ O = src
+ else
+ O = src
+
+ user.unEquip(src)
+
+ if (O)
+ user.put_in_hands(O)
+ O.add_fingerprint(user)
+
+ if(istype(src,/obj/item/clothing/ears/offear))
+ qdel(src)
+
+/obj/item/clothing/ears/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_ears()
+
+/obj/item/clothing/ears/MouseDrop(var/obj/over_object)
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ // If this covers both ears, we want to return the result of unequipping the primary object, and kill the off-ear one
+ if(slot_flags & SLOT_TWOEARS)
+ var/obj/item/clothing/ears/O = (H.l_ear == src ? H.r_ear : H.l_ear)
+ if(istype(src, /obj/item/clothing/ears/offear))
+ . = O.MouseDrop(over_object)
+ H.drop_from_inventory(src)
+ qdel(src)
+ else
+ . = ..()
+ H.drop_from_inventory(O)
+ qdel(O)
+ else
+ . = ..()
+
+
+/obj/item/clothing/ears/offear
+ name = "Other ear"
+ w_class = ITEMSIZE_HUGE
+ icon = 'icons/mob/screen1_Midnight.dmi'
+ icon_state = "block"
+ slot_flags = SLOT_EARS | SLOT_TWOEARS
+
+/obj/item/clothing/ears/offear/New(var/obj/O)
+ name = O.name
+ desc = O.desc
+ icon = O.icon
+ icon_state = O.icon_state
+ set_dir(O.dir)
+
+////////////////////////////////////////////////////////////////////////////////////////
+//Gloves
+/obj/item/clothing/gloves
+ name = "gloves"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_gloves.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_gloves.dmi',
+ )
+ gender = PLURAL //Carn: for grammarically correct text-parsing
+ w_class = ITEMSIZE_SMALL
+ icon = 'icons/obj/clothing/gloves.dmi'
+ siemens_coefficient = 0.9
+ blood_sprite_state = "bloodyhands"
+ var/wired = 0
+ var/obj/item/weapon/cell/cell = 0
+ var/fingerprint_chance = 0 //How likely the glove is to let fingerprints through
+ var/obj/item/clothing/gloves/ring = null //Covered ring
+ var/mob/living/carbon/human/wearer = null //Used for covered rings when dropping
+ var/glove_level = 2 //What "layer" the glove is on
+ var/overgloves = 0 //Used by gauntlets and arm_guards
+ var/punch_force = 0 //How much damage do these gloves add to a punch?
+ var/punch_damtype = BRUTE //What type of damage does this make fists be?
+ body_parts_covered = HANDS
+ slot_flags = SLOT_GLOVES
+ attack_verb = list("challenged")
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/gloves.dmi',
+ SPECIES_VOX = 'icons/mob/species/vox/gloves.dmi'
+ )
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/gloves.ogg'
+
+/obj/item/clothing/proc/set_clothing_index()
+ return
+
+/obj/item/clothing/gloves/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_gloves()
+
+/obj/item/clothing/gloves/emp_act(severity)
+ if(cell)
+ cell.emp_act(severity)
+ if(ring)
+ ring.emp_act(severity)
+ ..()
+
+// Called just before an attack_hand(), in mob/UnarmedAttack()
+/obj/item/clothing/gloves/proc/Touch(var/atom/A, var/proximity)
+ return 0 // return 1 to cancel attack_hand()
+
+/*/obj/item/clothing/gloves/attackby(obj/item/weapon/W, mob/user)
+ if(W.is_wirecutter() || istype(W, /obj/item/weapon/scalpel))
+ if (clipped)
+ to_chat(user, "The [src] have already been clipped!")
+ update_icon()
+ return
+
+ playsound(src, W.usesound, 50, 1)
+ user.visible_message("[user] cuts the fingertips off of the [src].","You cut the fingertips off of the [src].")
+
+ clipped = 1
+ name = "modified [name]"
+ desc = "[desc] They have had the fingertips cut off of them."
+ if("exclude" in species_restricted)
+ species_restricted -= SPECIES_UNATHI
+ species_restricted -= SPECIES_TAJ
+ return
+*/
+
+/obj/item/clothing/gloves/clean_blood()
+ . = ..()
+ transfer_blood = 0
+ update_icon()
+
+/obj/item/clothing/gloves/mob_can_equip(mob/user, slot, disable_warning = FALSE)
+ var/mob/living/carbon/human/H = user
+
+ if(slot && slot == slot_gloves)
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(istype(G))
+ ring = H.gloves
+ if(ring.glove_level >= src.glove_level)
+ to_chat(user, "You are unable to wear \the [src] as \the [H.gloves] are in the way.")
+ ring = null
+ return 0
+ else
+ H.drop_from_inventory(ring) //Remove the ring (or other under-glove item in the hand slot?) so you can put on the gloves.
+ ring.forceMove(src)
+ to_chat(user, "You slip \the [src] on over \the [src.ring].")
+ if(!(flags & THICKMATERIAL))
+ punch_force += ring.punch_force
+ else
+ ring = null
+
+ if(!..())
+ if(ring) //Put the ring back on if the check fails.
+ if(H.equip_to_slot_if_possible(ring, slot_gloves))
+ src.ring = null
+ punch_force = initial(punch_force)
+ return 0
+
+ wearer = H //TODO clean this when magboots are cleaned
+ return 1
+
+/obj/item/clothing/gloves/dropped()
+ ..()
+
+ if(!wearer)
+ return
+
+ var/mob/living/carbon/human/H = wearer
+ if(ring && istype(H))
+ if(!H.equip_to_slot_if_possible(ring, slot_gloves))
+ ring.forceMove(get_turf(src))
+ src.ring = null
+ punch_force = initial(punch_force)
+ wearer = null
+
+/obj/item/clothing/gloves
+ var/datum/unarmed_attack/special_attack = null //do the gloves have a special unarmed attack?
+ var/special_attack_type = null
+
+/obj/item/clothing/gloves/New()
+ ..()
+ if(special_attack_type && ispath(special_attack_type))
+ special_attack = new special_attack_type
+
+
+
+/////////////////////////////////////////////////////////////////////
+//Rings
+
+/obj/item/clothing/gloves/ring
+ name = "ring"
+ w_class = ITEMSIZE_TINY
+ icon = 'icons/obj/clothing/rings.dmi'
+ gender = NEUTER
+ species_restricted = list("exclude", SPECIES_DIONA)
+ siemens_coefficient = 1
+ glove_level = 1
+ fingerprint_chance = 100
+ punch_force = 2
+ body_parts_covered = 0
+ drop_sound = 'sound/items/drop/ring.ogg'
+ pickup_sound = 'sound/items/pickup/ring.ogg'
+
+///////////////////////////////////////////////////////////////////////
+//Head
+/obj/item/clothing/head
+ name = "head"
+ icon = 'icons/obj/clothing/hats.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_hats.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_hats.dmi',
+ )
+ body_parts_covered = HEAD
+ slot_flags = SLOT_HEAD
+ w_class = ITEMSIZE_SMALL
+ blood_sprite_state = "helmetblood"
+
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
+ light_cone_y_offset = 11
+
+ var/light_overlay = "helmet_light"
+ var/image/helmet_light
+
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/head.dmi',
+ SPECIES_VOX = 'icons/mob/species/vox/head.dmi'
+ )
+ drop_sound = 'sound/items/drop/hat.ogg'
+ pickup_sound = 'sound/items/pickup/hat.ogg'
+
+/obj/item/clothing/head/attack_self(mob/user)
+ if(light_range)
+ if(!isturf(user.loc))
+ to_chat(user, "You cannot toggle the light while in this [user.loc]")
+ return
+ update_flashlight(user)
+ to_chat(user, "You [light_on ? "enable" : "disable"] the helmet light.")
+ else
+ return ..(user)
+
+/obj/item/clothing/head/proc/update_flashlight(var/mob/user = null)
+ set_light_on(!light_on)
+
+ if(light_system == STATIC_LIGHT)
+ update_light()
+
+ update_icon(user)
+ user.update_action_buttons()
+
+/obj/item/clothing/head/attack_ai(var/mob/user)
+ if(!mob_wear_hat(user))
+ return ..()
+
+/obj/item/clothing/head/attack_generic(var/mob/user)
+ if(!mob_wear_hat(user))
+ return ..()
+
+/obj/item/clothing/head/proc/mob_wear_hat(var/mob/user)
+ if(!Adjacent(user))
+ return 0
+ var/success
+ if(istype(user, /mob/living/silicon/robot/drone))
+ var/mob/living/silicon/robot/drone/D = user
+ if(D.hat)
+ success = 2
+ else
+ D.wear_hat(src)
+ success = 1
+ else if(istype(user, /mob/living/carbon/alien/diona))
+ var/mob/living/carbon/alien/diona/D = user
+ if(D.hat)
+ success = 2
+ else
+ D.wear_hat(src)
+ success = 1
+
+ if(!success)
+ return 0
+ else if(success == 2)
+ to_chat(user, "You are already wearing a hat.")
+ else if(success == 1)
+ to_chat(user, "You crawl under \the [src].")
+ return 1
+
+/obj/item/clothing/head/update_icon(var/mob/user)
+ var/mob/living/carbon/human/H
+ if(ishuman(user))
+ H = user
+
+ if(light_on)
+ // Generate object icon.
+ if(!light_overlay_cache["[light_overlay]_icon"])
+ light_overlay_cache["[light_overlay]_icon"] = image(icon = 'icons/obj/light_overlays.dmi', icon_state = "[light_overlay]")
+ helmet_light = light_overlay_cache["[light_overlay]_icon"]
+ add_overlay(helmet_light)
+
+ // Generate and cache the on-mob icon, which is used in update_inv_head().
+ var/body_type = (H && H.species.get_bodytype(H))
+ var/cache_key = "[light_overlay][body_type && sprite_sheets[body_type] ? "_[body_type]" : ""]"
+ if(!light_overlay_cache[cache_key])
+ var/use_icon = LAZYACCESS(sprite_sheets,body_type) || 'icons/mob/light_overlays.dmi'
+ light_overlay_cache[cache_key] = image(icon = use_icon, icon_state = "[light_overlay]")
+
+ else if(helmet_light)
+ cut_overlay(helmet_light)
+ helmet_light = null
+
+ user.update_inv_head() //Will redraw the helmet with the light on the mob
+
+/obj/item/clothing/head/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_head()
+
+///////////////////////////////////////////////////////////////////////
+//Mask
+/obj/item/clothing/mask
+ name = "mask"
+ icon = 'icons/obj/clothing/masks.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_masks.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_masks.dmi',
+ )
+ body_parts_covered = HEAD
+ slot_flags = SLOT_MASK
+ body_parts_covered = FACE|EYES
+ blood_sprite_state = "maskblood"
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/masks.dmi',
+ SPECIES_VOX = 'icons/mob/species/vox/masks.dmi',
+ SPECIES_TAJ = 'icons/mob/species/tajaran/mask.dmi',
+ SPECIES_UNATHI = 'icons/mob/species/unathi/mask.dmi'
+ )
+
+ var/voicechange = 0
+ var/list/say_messages
+ var/list/say_verbs
+
+ drop_sound = "generic_drop"
+ pickup_sound = "generic_pickup"
+
+/obj/item/clothing/mask/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_wear_mask()
+
+/obj/item/clothing/mask/proc/filter_air(datum/gas_mixture/air)
+ return
+
+///////////////////////////////////////////////////////////////////////
+//Shoes
+/obj/item/clothing/shoes
+ name = "shoes"
+ icon = 'icons/obj/clothing/shoes.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_shoes.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_shoes.dmi',
+ )
+ desc = "Comfortable-looking shoes."
+ gender = PLURAL //Carn: for grammarically correct text-parsing
+ siemens_coefficient = 0.9
+ body_parts_covered = FEET
+ slot_flags = SLOT_FEET
+ blood_sprite_state = "shoeblood"
+
+ var/can_hold_knife = 0
+ var/obj/item/holding
+
+ var/shoes_under_pants = 0
+
+ var/water_speed = 0 //Speed boost/decrease in water, lower/negative values mean more speed
+ var/snow_speed = 0 //Speed boost/decrease on snow, lower/negative values mean more speed
+ var/rock_climbing = FALSE // If true, allows climbing cliffs with clickdrag.
+
+ var/step_volume_mod = 1 //How quiet or loud footsteps in this shoe are
+
+ permeability_coefficient = 0.50
+ slowdown = SHOES_SLOWDOWN
+ force = 2
+ var/overshoes = 0
+ species_restricted = list("exclude",SPECIES_TESHARI, SPECIES_VOX)
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/shoes.dmi',
+ SPECIES_VOX = 'icons/mob/species/vox/shoes.dmi'
+ )
+ drop_sound = 'sound/items/drop/shoes.ogg'
+ pickup_sound = 'sound/items/pickup/shoes.ogg'
+
+/obj/item/clothing/shoes/proc/draw_knife()
+ set name = "Draw Boot Knife"
+ set desc = "Pull out your boot knife."
+ set category = "IC"
+ set src in usr
+
+ if(usr.stat || usr.restrained() || usr.incapacitated())
+ return
+
+ holding.forceMove(get_turf(usr))
+
+ if(usr.put_in_hands(holding))
+ usr.visible_message("\The [usr] pulls a knife out of their boot!")
+ playsound(src, 'sound/weapons/holster/sheathout.ogg', 25)
+ holding = null
+ cut_overlay("[icon_state]_knife")
+ else
+ to_chat(usr, "Your need an empty, unbroken hand to do that.")
+ holding.forceMove(src)
+
+ if(!holding)
+ verbs -= /obj/item/clothing/shoes/proc/draw_knife
+
+ update_icon()
+ return
+
+/obj/item/clothing/shoes/attack_hand(var/mob/living/M)
+ if(can_hold_knife == 1 && holding && src.loc == M)
+ draw_knife()
+ return
+ ..()
+
+/obj/item/clothing/shoes/attackby(var/obj/item/I, var/mob/user)
+ if((can_hold_knife == 1) && (istype(I, /obj/item/weapon/material/shard) || \
+ istype(I, /obj/item/weapon/material/butterfly) || \
+ istype(I, /obj/item/weapon/material/kitchen/utensil) || \
+ istype(I, /obj/item/weapon/material/knife/tacknife)))
+ if(holding)
+ to_chat(user, "\The [src] is already holding \a [holding].")
+ return
+ user.unEquip(I)
+ I.forceMove(src)
+ holding = I
+ user.visible_message("\The [user] shoves \the [I] into \the [src].")
+ verbs |= /obj/item/clothing/shoes/proc/draw_knife
+ update_icon()
+ else
+ return ..()
+
+/obj/item/clothing/shoes/verb/toggle_layer()
+ set name = "Switch Shoe Layer"
+ set category = "Object"
+
+ if(shoes_under_pants == -1)
+ to_chat(usr, "\The [src] cannot be worn above your suit!")
+ return
+ shoes_under_pants = !shoes_under_pants
+ update_icon()
+
+/obj/item/clothing/shoes/update_icon()
+ . = ..()
+ if(holding)
+ add_overlay("[icon_state]_knife")
+ if(contaminated)
+ add_overlay(contamination_overlay)
+ if(gurgled) //VOREStation Edit Start
+ decontaminate()
+ gurgle_contaminate() //VOREStation Edit End
+ if(ismob(usr))
+ var/mob/M = usr
+ M.update_inv_shoes()
+
+/obj/item/clothing/shoes/clean_blood()
+ update_icon()
+ return ..()
+
+/obj/item/clothing/shoes/proc/handle_movement(var/turf/walking, var/running)
+ if(prob(1) && !recent_squish) //VOREStation edit begin
+ recent_squish = 1
+ spawn(100)
+ recent_squish = 0
+ for(var/mob/living/M in contents)
+ var/emote = pick(inside_emotes)
+ to_chat(M,emote) //VOREStation edit end
+ return
+
+/obj/item/clothing/shoes/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_shoes()
+
+
+///////////////////////////////////////////////////////////////////////
+//Suit
+/obj/item/clothing/suit
+ icon = 'icons/obj/clothing/suits.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_suits.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_suits.dmi',
+ )
+ name = "suit"
+ var/fire_resist = T0C+100
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS
+ allowed = list(/obj/item/weapon/tank/emergency/oxygen)
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
+ slot_flags = SLOT_OCLOTHING
+ var/blood_overlay_type = "suit"
+ blood_sprite_state = "suitblood" //Defaults to the suit's blood overlay, so that some blood renders instead of no blood.
+
+ var/taurized = FALSE
+ siemens_coefficient = 0.9
+ w_class = ITEMSIZE_NORMAL
+ preserve_item = 1
+ equip_sound = 'sound/items/jumpsuit_equip.ogg'
+
+
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/suit.dmi',
+ SPECIES_VOX = 'icons/mob/species/vox/suit.dmi'
+ )
+
+ valid_accessory_slots = (ACCESSORY_SLOT_OVER | ACCESSORY_SLOT_ARMBAND)
+ restricted_accessory_slots = (ACCESSORY_SLOT_ARMBAND)
+
+/obj/item/clothing/suit/set_clothing_index()
+ ..()
+
+ if(index && !icon_override)
+ icon = new /icon("icons/obj/clothing/suits_[index].dmi")
+ item_icons = list(
+ slot_l_hand_str = new /icon("icons/mob/items/lefthand_suits_[index].dmi"),
+ slot_r_hand_str = new /icon("icons/mob/items/righthand_suits_[index].dmi"),
+ )
+
+ return 1
+
+ return 0
+
+/obj/item/clothing/suit/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_wear_suit()
+
+ set_clothing_index()
+
+/obj/item/clothing/suit/equipped(var/mob/user, var/slot)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if((taurized && !isTaurTail(H.tail_style)) || (!taurized && isTaurTail(H.tail_style)))
+ taurize(user)
+
+ return ..()
+
+/obj/item/clothing/suit/proc/taurize(var/mob/living/carbon/human/Taur)
+ if(isTaurTail(Taur.tail_style))
+ var/datum/sprite_accessory/tail/taur/taurtail = Taur.tail_style
+ if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in cached_icon_states(taurtail.suit_sprites)))
+ icon_override = taurtail.suit_sprites
+ taurized = TRUE
+
+ if(!taurized)
+ icon_override = initial(icon_override)
+ taurized = FALSE
+
+// Taur suits need to be shifted so its centered on their taur half.
+/obj/item/clothing/suit/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer = 0,var/icon/clip_mask)
+ var/image/standing = ..()
+ if(taurized) //Special snowflake var on suits
+ standing.pixel_x = -16
+ standing.layer = BODY_LAYER + 15 // 15 is above tail layer, so will not be covered by taurbody.
+ return standing
+
+/obj/item/clothing/suit/apply_accessories(var/image/standing)
+ if(LAZYLEN(accessories) && taurized)
+ for(var/obj/item/clothing/accessory/A in accessories)
+ var/image/I = new(A.get_mob_overlay())
+ I.pixel_x = 16 //Opposite of the pixel_x on the suit (-16) from taurization to cancel it out and puts the accessory in the correct place on the body.
+ standing.add_overlay(I)
+ else
+ return ..()
+
+
+///////////////////////////////////////////////////////////////////////
+//Under clothing
+/obj/item/clothing/under
+ icon = 'icons/obj/clothing/uniforms.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_uniforms.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_uniforms.dmi',
+ )
+ name = "under"
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
+ permeability_coefficient = 0.90
+ slot_flags = SLOT_ICLOTHING
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
+ equip_sound = 'sound/items/jumpsuit_equip.ogg'
+ w_class = ITEMSIZE_NORMAL
+ show_messages = 1
+ blood_sprite_state = "uniformblood"
+
+ var/has_sensor = 1 //For the crew computer 2 = unable to change mode
+ var/sensor_mode = 0
+ /*
+ 1 = Report living/dead
+ 2 = Report detailed damages
+ 3 = Report location
+ */
+ var/displays_id = 1
+ var/rolled_down = -1 //0 = unrolled, 1 = rolled, -1 = cannot be toggled
+ var/rolled_sleeves = -1 //0 = unrolled, 1 = rolled, -1 = cannot be toggled
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/uniform.dmi',
+ SPECIES_VOX = 'icons/mob/species/vox/uniform.dmi'
+ )
+
+ //convenience var for defining the icon state for the overlay used when the clothing is worn.
+ //Also used by rolling/unrolling.
+ var/worn_state = null
+ valid_accessory_slots = (\
+ ACCESSORY_SLOT_UTILITY\
+ |ACCESSORY_SLOT_WEAPON\
+ |ACCESSORY_SLOT_ARMBAND\
+ |ACCESSORY_SLOT_DECOR\
+ |ACCESSORY_SLOT_MEDAL\
+ |ACCESSORY_SLOT_INSIGNIA\
+ |ACCESSORY_SLOT_TIE\
+ |ACCESSORY_SLOT_RANK\
+ |ACCESSORY_SLOT_DEPT\
+ |ACCESSORY_SLOT_OVER)
+ restricted_accessory_slots = (\
+ ACCESSORY_SLOT_UTILITY\
+ |ACCESSORY_SLOT_WEAPON\
+ |ACCESSORY_SLOT_ARMBAND\
+ |ACCESSORY_SLOT_TIE\
+ |ACCESSORY_SLOT_RANK\
+ |ACCESSORY_SLOT_DEPT\
+ |ACCESSORY_SLOT_OVER)
+
+ var/icon/rolled_down_icon = 'icons/mob/uniform_rolled_down.dmi'
+ var/icon/rolled_down_sleeves_icon = 'icons/mob/uniform_sleeves_rolled.dmi'
+
+/obj/item/clothing/under/attack_hand(var/mob/user)
+ if(LAZYLEN(accessories))
+ ..()
+ if ((ishuman(usr) || issmall(usr)) && src.loc == user)
+ return
+ ..()
+
+/obj/item/clothing/under/New()
+ ..()
+ if(worn_state)
+ if(!item_state_slots)
+ item_state_slots = list()
+ item_state_slots[slot_w_uniform_str] = worn_state
+ else
+ worn_state = icon_state
+
+ //autodetect rollability
+ if(rolled_down < 0)
+ 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)
+ verbs -= /obj/item/clothing/under/verb/rollsuit
+ if(rolled_sleeves == -1)
+ verbs -= /obj/item/clothing/under/verb/rollsleeves
+
+/obj/item/clothing/under/set_clothing_index()
+ ..()
+
+ if(index && !icon_override)
+ icon = new /icon("icons/obj/clothing/uniforms_[index].dmi")
+
+ item_icons = list(
+ slot_l_hand_str = new /icon("icons/mob/items/lefthand_uniforms_[index].dmi"),
+ slot_r_hand_str = new /icon("icons/mob/items/righthand_uniforms_[index].dmi"),
+ )
+
+ rolled_down_icon = new /icon("icons/mob/uniform_rolled_down_[index].dmi")
+ rolled_down_sleeves_icon = new /icon("icons/mob/uniform_sleeves_rolled_[index].dmi")
+ return 1
+
+ return 0
+
+/obj/item/clothing/under/proc/update_rolldown_status()
+ var/mob/living/carbon/human/H
+ if(istype(src.loc, /mob/living/carbon/human))
+ H = src.loc
+
+ var/icon/under_icon
+ if(icon_override)
+ under_icon = icon_override
+ else if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)])
+ 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 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 cached_icon_states(under_icon))) || ("[worn_state]_d_s" in cached_icon_states(under_icon)))
+ if(rolled_down != 1)
+ rolled_down = 0
+ else
+ rolled_down = -1
+ if(H) update_clothing_icon()
+
+/obj/item/clothing/under/proc/update_rollsleeves_status()
+ var/mob/living/carbon/human/H
+ if(istype(src.loc, /mob/living/carbon/human))
+ H = src.loc
+
+ var/icon/under_icon
+ if(icon_override)
+ under_icon = icon_override
+ else if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)])
+ 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 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 cached_icon_states(under_icon))) || ("[worn_state]_r_s" in cached_icon_states(under_icon)))
+ if(rolled_sleeves != 1)
+ rolled_sleeves = 0
+ else
+ rolled_sleeves = -1
+ if(H) update_clothing_icon()
+
+/obj/item/clothing/under/update_clothing_icon()
+ if (ismob(src.loc))
+ var/mob/M = src.loc
+ M.update_inv_w_uniform()
+
+ set_clothing_index()
+
+
+/obj/item/clothing/under/examine(mob/user)
+ . = ..()
+ switch(src.sensor_mode)
+ if(0)
+ . += "Its sensors appear to be disabled."
+ if(1)
+ . += "Its binary life sensors appear to be enabled."
+ if(2)
+ . += "Its vital tracker appears to be enabled."
+ if(3)
+ . += "Its vital tracker and tracking beacon appear to be enabled."
+
+/obj/item/clothing/under/proc/set_sensors(mob/usr as mob)
+ var/mob/M = usr
+ if (istype(M, /mob/observer)) return
+ if (usr.stat || usr.restrained()) return
+ if(has_sensor >= 2)
+ to_chat(usr, "The controls are locked.")
+ return 0
+ if(has_sensor <= 0)
+ to_chat(usr, "This suit does not have any sensors.")
+ return 0
+
+ var/list/modes = list("Off", "Binary sensors", "Vitals tracker", "Tracking beacon")
+ var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes
+ if(get_dist(usr, src) > 1)
+ to_chat(usr, "You have moved too far away.")
+ return
+ sensor_mode = modes.Find(switchMode) - 1
+
+ if (src.loc == usr)
+ switch(sensor_mode)
+ if(0)
+ usr.visible_message("[usr] adjusts their sensors.", "You disable your suit's remote sensing equipment.")
+ if(1)
+ usr.visible_message("[usr] adjusts their sensors.", "Your suit will now report whether you are live or dead.")
+ if(2)
+ usr.visible_message("[usr] adjusts their sensors.", "Your suit will now report your vital lifesigns.")
+ if(3)
+ usr.visible_message("[usr] adjusts their sensors.", "Your suit will now report your vital lifesigns as well as your coordinate position.")
+
+ else if (istype(src.loc, /mob))
+ usr.visible_message("[usr] adjusts [src.loc]'s sensors.", "You adjust [src.loc]'s sensors.")
+
+/obj/item/clothing/under/verb/toggle()
+ set name = "Toggle Suit Sensors"
+ set category = "Object"
+ set src in usr
+ set_sensors(usr)
+
+/obj/item/clothing/under/verb/rollsuit()
+ set name = "Roll Down Jumpsuit"
+ set category = "Object"
+ set src in usr
+ if(!istype(usr, /mob/living)) return
+ if(usr.stat) return
+
+ update_rolldown_status()
+ if(rolled_down == -1)
+ to_chat(usr, "You cannot roll down [src]!")
+ return
+ if((rolled_sleeves == 1) && !(rolled_down))
+ rolled_sleeves = 0
+
+ rolled_down = !rolled_down
+ if(rolled_down)
+ body_parts_covered = initial(body_parts_covered)
+ body_parts_covered &= ~(UPPER_TORSO|ARMS)
+ 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
+ item_state_slots[slot_w_uniform_str] = "[worn_state]_d"
+
+ to_chat(usr, "You roll down your [src].")
+ else
+ body_parts_covered = initial(body_parts_covered)
+ if(icon_override == rolled_down_icon)
+ icon_override = initial(icon_override)
+ item_state_slots[slot_w_uniform_str] = "[worn_state]"
+ to_chat(usr, "You roll up your [src].")
+ update_clothing_icon()
+
+/obj/item/clothing/under/verb/rollsleeves()
+ set name = "Roll Up Sleeves"
+ set category = "Object"
+ set src in usr
+ if(!istype(usr, /mob/living)) return
+ if(usr.stat) return
+
+ update_rollsleeves_status()
+ if(rolled_sleeves == -1)
+ to_chat(usr, "You cannot roll up your [src]'s sleeves!")
+ return
+ if(rolled_down == 1)
+ to_chat(usr, "You must roll up your [src] first!")
+ return
+
+ rolled_sleeves = !rolled_sleeves
+ if(rolled_sleeves)
+ body_parts_covered &= ~(ARMS)
+ 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
+ item_state_slots[slot_w_uniform_str] = "[worn_state]_r"
+ to_chat(usr, "You roll up your [src]'s sleeves.")
+ else
+ body_parts_covered = initial(body_parts_covered)
+ if(icon_override == rolled_down_sleeves_icon)
+ icon_override = initial(icon_override)
+ item_state_slots[slot_w_uniform_str] = "[worn_state]"
+ to_chat(usr, "You roll down your [src]'s sleeves.")
+ update_clothing_icon()
+
+/obj/item/clothing/under/rank/New()
+ sensor_mode = pick(0,1,2,3)
+ ..()
diff --git a/code/modules/clothing/clothing_icons.dm b/code/modules/clothing/clothing_icons.dm
index 2adfbfa0b98..1762d092017 100644
--- a/code/modules/clothing/clothing_icons.dm
+++ b/code/modules/clothing/clothing_icons.dm
@@ -19,7 +19,7 @@
//HELMET: May have a lighting overlay
/obj/item/clothing/head/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer = 0,var/icon/clip_mask = null)
var/image/standing = ..()
- if(on && slot_name == slot_head_str)
+ if(light_on && slot_name == slot_head_str)
var/cache_key = "[light_overlay][LAZYACCESS(sprite_sheets,body_type) ? "_[body_type]" : ""]"
if(standing && light_overlay_cache[cache_key])
standing.add_overlay(light_overlay_cache[cache_key])
diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm
index f974c321c06..47a5b89f1aa 100644
--- a/code/modules/clothing/head/hardhat.dm
+++ b/code/modules/clothing/head/hardhat.dm
@@ -2,7 +2,8 @@
name = "hard hat"
desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight."
icon_state = "hardhat0_yellow"
- brightness_on = 4 //luminosity when on
+ light_range = 4 //luminosity when on
+ light_cone_y_offset = 14
light_overlay = "hardhat_light"
armor = list(melee = 30, bullet = 5, laser = 20,energy = 10, bomb = 20, bio = 10, rad = 20)
flags_inv = 0
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 8cf8a6292e7..cf0527c6a6c 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -111,7 +111,7 @@
icon_state = "flexitac"
armor = list(melee = 40, bullet = 40, laser = 60, energy = 35, bomb = 30, bio = 0, rad = 0)
siemens_coefficient = 0.6
- brightness_on = 6
+ light_range = 6
light_overlay = "helmet_light_dual_green"
action_button_name = "Toggle Head-light"
min_cold_protection_temperature = T0C - 20
diff --git a/code/modules/clothing/head/hood.dm b/code/modules/clothing/head/hood.dm
index 1fb1394bce6..28bc8a8a54a 100644
--- a/code/modules/clothing/head/hood.dm
+++ b/code/modules/clothing/head/hood.dm
@@ -152,6 +152,7 @@
light_range = 3
light_power = 1
light_color = "#B18B25" //clockwork slab background top color
+ light_on = TRUE
/obj/item/clothing/head/hood/winter/narsie
name = "runed winter hood"
diff --git a/code/modules/clothing/head/hood_vr.dm b/code/modules/clothing/head/hood_vr.dm
index 8c8b4f73681..c1de0bafc3b 100644
--- a/code/modules/clothing/head/hood_vr.dm
+++ b/code/modules/clothing/head/hood_vr.dm
@@ -2,17 +2,17 @@
name = "techpriest hood"
armor = list(melee = 20, bullet = 10, laser = 10, energy = 10, bomb = 25, bio = 50, rad = 25)
-// Armor versions here
+// Armor versions here
/obj/item/clothing/head/hood/galahad
name = "galahad hood"
armor = list(melee = 80, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 2
-
+
/obj/item/clothing/head/hood/lancelot
name = "lancelot hood"
armor = list(melee = 80, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 2
-
+
/obj/item/clothing/head/hood/robin
name = "robin hood"
armor = list(melee = 80, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
@@ -21,9 +21,16 @@
// Costume Versions Here
/obj/item/clothing/head/hood/galahad_costume
name = "galahad costume hood"
-
+
/obj/item/clothing/head/hood/lancelot_costume
name = "lancelot costume hood"
-
+
/obj/item/clothing/head/hood/robin_costume
- name = "robin costume hood"
\ No newline at end of file
+ name = "robin costume hood"
+
+// Talon Winter Hood
+/obj/item/clothing/head/hood/winter/talon
+ name = "ITV winter hood"
+ desc = "A cozy winter hood attached to a heavy winter jacket."
+ icon_override = 'icons/mob/head_vr.dmi'
+ icon_state = "winterhood_talon"
\ No newline at end of file
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 6ef9ee2be6b..dbb5f6d9398 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -167,7 +167,7 @@
icon_state = "hardhat0_pumpkin"//Could stand to be renamed
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR
body_parts_covered = HEAD|FACE|EYES
- brightness_on = 2
+ light_range = 2
light_overlay = "jackolantern"
w_class = ITEMSIZE_NORMAL
drop_sound = 'sound/items/drop/herb.ogg'
diff --git a/code/modules/clothing/head/misc_vr.dm b/code/modules/clothing/head/misc_vr.dm
index 5b37f8f7598..fc8bf9a69d3 100644
--- a/code/modules/clothing/head/misc_vr.dm
+++ b/code/modules/clothing/head/misc_vr.dm
@@ -93,4 +93,39 @@
desc = "A fancy visor showing alignment to pizza delivery service. Extremely risky career choice."
icon_state = "pizzadelivery"
icon = 'icons/obj/clothing/hats_vr.dmi'
- icon_override = 'icons/mob/head_vr.dmi'
\ No newline at end of file
+ icon_override = 'icons/mob/head_vr.dmi'
+
+//////////TALON HATS//////////
+
+/obj/item/clothing/head/soft/talon
+ name = "ITV baseball cap"
+ desc = "It's a ballcap bearing the colors of ITV."
+ icon = 'icons/obj/clothing/hats_vr.dmi'
+ icon_override = 'icons/mob/head_vr.dmi'
+ icon_state = "talonsoft"
+ item_state = "talonsoft"
+ item_state_slots = list(slot_r_hand_str = "blacksoft", slot_l_hand_str = "blacksoft")
+
+/obj/item/clothing/head/caphat/talon
+ name = "ITV nautical hat"
+ desc = "It's a classic nautical hat bearing the colors of ITV. Perfect for commanding the Talon."
+ icon = 'icons/obj/clothing/hats_vr.dmi'
+ icon_override = 'icons/mob/head_vr.dmi'
+ icon_state = "talon_captain_cap"
+ item_state = "taloncaptaincap"
+
+obj/item/clothing/head/beret/talon
+ name = "ITV beret"
+ desc = "It's a basic baret colored to match ITV's uniforms."
+ icon = 'icons/obj/clothing/hats_vr.dmi'
+ icon_override = 'icons/mob/head_vr.dmi'
+ icon_state = "beret_talon"
+ item_state = "baret_talon"
+
+obj/item/clothing/head/beret/talon/command
+ name = "ITV officer beret"
+ desc = "It's a basic baret colored to match ITV's uniforms with a badge pinned on the front. Perfect for commanders."
+ icon = 'icons/obj/clothing/hats_vr.dmi'
+ icon_override = 'icons/mob/head_vr.dmi'
+ icon_state = "beret_talon_officer"
+ item_state = "baret_talon_command"
\ No newline at end of file
diff --git a/code/modules/clothing/head/pilot_helmet_vr.dm b/code/modules/clothing/head/pilot_helmet_vr.dm
index 34f6c3293dc..55afe6f7138 100644
--- a/code/modules/clothing/head/pilot_helmet_vr.dm
+++ b/code/modules/clothing/head/pilot_helmet_vr.dm
@@ -44,3 +44,24 @@
src.icon_state = initial(icon_state)
to_chat(user, "You lower the visor on the pilot helmet.")
update_clothing_icon() //so our mob-overlays update
+
+//////////Talon Pilot Headgear//////////
+
+/obj/item/clothing/head/pilot_vr/talon
+ name = "ITV pilot helmet"
+ desc = "An ITV version of the standard pilot helmet. Protects the head from impacts. This one has a retractable visor"
+ icon_state = "pilot3"
+ item_icons = list(slot_head_str = 'icons/mob/head_vr.dmi')
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/helmet_vr.dmi'
+ )
+ action_button_name = "Toggle Visor"
+
+/obj/item/clothing/head/pilot_vr/alt/attack_self(mob/user as mob)
+ if(src.icon_state == initial(icon_state))
+ src.icon_state = "[icon_state]up"
+ to_chat(user, "You raise the visor on the pilot helmet.")
+ else
+ src.icon_state = initial(icon_state)
+ to_chat(user, "You lower the visor on the pilot helmet.")
+ update_clothing_icon() //so our mob-overlays update
diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm
index 75f5e4af3cf..6ac7ef9a3a5 100644
--- a/code/modules/clothing/spacesuits/rig/rig.dm
+++ b/code/modules/clothing/spacesuits/rig/rig.dm
@@ -585,8 +585,7 @@
/obj/item/weapon/rig/update_icon(var/update_mob_icon)
- //TODO: Maybe consider a cache for this (use mob_icon as blank canvas, use suit icon overlay).
- overlays.Cut()
+ cut_overlays()
if(!mob_icon || update_mob_icon)
var/species_icon = 'icons/mob/rig_back.dmi'
// Since setting mob_icon will override the species checks in
@@ -598,7 +597,7 @@
if(installed_modules.len)
for(var/obj/item/rig_module/module in installed_modules)
if(module.suit_overlay)
- chest.overlays += image("icon" = 'icons/mob/rig_modules.dmi', "icon_state" = "[module.suit_overlay]", "dir" = SOUTH)
+ chest.add_overlay(image('icons/mob/rig_modules.dmi', icon_state = "[module.suit_overlay]", dir = SOUTH))
if(wearer)
wearer.update_inv_shoes()
diff --git a/code/modules/clothing/spacesuits/rig/rig_pieces.dm b/code/modules/clothing/spacesuits/rig/rig_pieces.dm
index cc76771d459..3c1843698c0 100644
--- a/code/modules/clothing/spacesuits/rig/rig_pieces.dm
+++ b/code/modules/clothing/spacesuits/rig/rig_pieces.dm
@@ -9,7 +9,7 @@
body_parts_covered = HEAD|FACE|EYES
heat_protection = HEAD|FACE|EYES
cold_protection = HEAD|FACE|EYES
- brightness_on = 4
+ light_range = 4
sprite_sheets = list(
SPECIES_TAJ = 'icons/mob/species/tajaran/helmet.dmi',
SPECIES_SKRELL = 'icons/mob/species/skrell/helmet.dmi',
diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm
index 162b097aa71..4cd8ade06e2 100644
--- a/code/modules/clothing/spacesuits/spacesuits.dm
+++ b/code/modules/clothing/spacesuits/spacesuits.dm
@@ -29,8 +29,7 @@
action_button_name = "Toggle Helmet Light"
light_overlay = "helmet_light"
- brightness_on = 4
- on = 0
+ light_range = 4
/obj/item/clothing/head/helmet/space/Initialize()
. = ..()
diff --git a/code/modules/clothing/spacesuits/void/ert_vr.dm b/code/modules/clothing/spacesuits/void/ert_vr.dm
index a123238c792..96243290294 100644
--- a/code/modules/clothing/spacesuits/void/ert_vr.dm
+++ b/code/modules/clothing/spacesuits/void/ert_vr.dm
@@ -20,7 +20,7 @@
/obj/item/clothing/suit/space/void/responseteam/command/Initialize()
..()
- helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/command //autoinstall the helmet
+ attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/command) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/medical
name = "Mark VII-M Emergency Medical Response Suit"
@@ -29,7 +29,7 @@
/obj/item/clothing/suit/space/void/responseteam/medical/Initialize()
..()
- helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/medical //autoinstall the helmet
+ attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/medical) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/engineer
name = "Mark VII-E Emergency Engineering Response Suit"
@@ -38,7 +38,7 @@
/obj/item/clothing/suit/space/void/responseteam/engineer/Initialize()
..()
- helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/engineer //autoinstall the helmet
+ attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/engineer) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/security
name = "Mark VII-S Emergency Security Response Suit"
@@ -47,7 +47,7 @@
/obj/item/clothing/suit/space/void/responseteam/security/Initialize()
..()
- helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/security //autoinstall the helmet
+ attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/security) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/janitor
name = "Mark VII-J Emergency Cleanup Response Suit"
@@ -59,7 +59,7 @@
/obj/item/clothing/suit/space/void/responseteam/janitor/Initialize()
..()
- helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/janitor //autoinstall the helmet
+ attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/janitor) //autoinstall the helmet
//override the attackby screwdriver proc so that people can't remove the helmet
diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm
index 3a92bd2be10..926365c5c1b 100644
--- a/code/modules/clothing/spacesuits/void/void.dm
+++ b/code/modules/clothing/spacesuits/void/void.dm
@@ -120,7 +120,6 @@
to_chat(M, "Your suit's cooling unit deploys.")
cooler.canremove = 0
-
/obj/item/clothing/suit/space/void/dropped()
..()
@@ -150,6 +149,22 @@
cooler.canremove = 1
cooler.forceMove(src)
+/obj/item/clothing/suit/space/void/proc/attach_helmet(var/obj/item/clothing/head/helmet/space/void/helm)
+ if(!istype(helm) || helmet)
+ return
+
+ helm.forceMove(src)
+ helm.set_light_flags(helm.light_flags | LIGHT_ATTACHED)
+ helmet = helm
+
+/obj/item/clothing/suit/space/void/proc/remove_helmet()
+ if(!helmet)
+ return
+
+ helmet.forceMove(get_turf(src))
+ helmet.set_light_flags(helmet.light_flags & ~LIGHT_ATTACHED)
+ helmet = null
+
/obj/item/clothing/suit/space/void/verb/toggle_helmet()
set name = "Toggle Helmet"
@@ -243,9 +258,8 @@
src.cooler = null
else if(choice == helmet)
to_chat(user, "You detach \the [helmet] from \the [src]'s helmet mount.")
- helmet.forceMove(get_turf(src))
+ remove_helmet()
playsound(src, W.usesound, 50, 1)
- src.helmet = null
else if(choice == boots)
to_chat(user, "You detach \the [boots] from \the [src]'s boot mounts.")
boots.forceMove(get_turf(src))
@@ -260,8 +274,7 @@
else
to_chat(user, "You attach \the [W] to \the [src]'s helmet mount.")
user.drop_item()
- W.forceMove(src)
- src.helmet = W
+ attach_helmet(W)
return
else if(istype(W,/obj/item/clothing/shoes/magboots))
if(boots)
diff --git a/code/modules/clothing/suits/hooded.dm b/code/modules/clothing/suits/hooded.dm
index 550dfea0d07..cff2cb9ac68 100644
--- a/code/modules/clothing/suits/hooded.dm
+++ b/code/modules/clothing/suits/hooded.dm
@@ -322,6 +322,7 @@
light_range = 3
light_power = 1
light_color = "#B18B25" //clockwork slab background top color
+ light_on = TRUE
/obj/item/clothing/suit/storage/hooded/wintercoat/narsie
name = "runed winter coat"
@@ -336,6 +337,7 @@
hoodtype = /obj/item/clothing/head/hood/winter/cosmic
light_power = 1.8
light_range = 1.2
+ light_on = TRUE
// winter coats end here
diff --git a/code/modules/clothing/suits/hooded_vr.dm b/code/modules/clothing/suits/hooded_vr.dm
index e89a43e50b3..8d0b6a9c38b 100644
--- a/code/modules/clothing/suits/hooded_vr.dm
+++ b/code/modules/clothing/suits/hooded_vr.dm
@@ -67,4 +67,14 @@
name = "crusader's armor"
desc = "ye olde knight, risen again. This one seems slightly faster than the rest, but weaker."
icon_state = "robin"
- hoodtype = /obj/item/clothing/head/hood/robin_costume
\ No newline at end of file
+ hoodtype = /obj/item/clothing/head/hood/robin_costume
+
+// Talon Winter Coat
+/obj/item/clothing/suit/storage/hooded/wintercoat/talon
+ name = "ITV winter coat"
+ desc = "A cozy winter coat, covered in thick fur and baring the colors of ITV."
+ icon = 'icons/obj/clothing/suits_vr.dmi'
+ icon_override = 'icons/mob/suit_vr.dmi'
+ icon_state = "taloncoat"
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
+ hoodtype = /obj/item/clothing/head/hood/winter/talon
diff --git a/code/modules/clothing/suits/miscellaneous_vr.dm b/code/modules/clothing/suits/miscellaneous_vr.dm
index 69af5328bcb..9ff69f6c265 100644
--- a/code/modules/clothing/suits/miscellaneous_vr.dm
+++ b/code/modules/clothing/suits/miscellaneous_vr.dm
@@ -100,3 +100,12 @@
icon_override = 'icons/mob/suit_vr.dmi'
icon_state = "cyberpunksleek_long"
item_state = "cyberpunksleek_long"
+
+//Talon Hoodie
+/obj/item/clothing/suit/storage/toggle/hoodie/talon
+ name = "ITV hoodie"
+ desc = "A warm, blue sweatshirt bearing ITV markings."
+ icon = 'icons/obj/clothing/suits_vr.dmi'
+ icon_override = 'icons/mob/suit_vr.dmi'
+ icon_state = "talonhoodie"
+ item_state_slots = list(slot_r_hand_str = "suit_blue", slot_l_hand_str = "suit_blue")
\ No newline at end of file
diff --git a/code/modules/clothing/under/accessories/accessory_vr.dm b/code/modules/clothing/under/accessories/accessory_vr.dm
index ba532f62a92..85cce94e5fb 100644
--- a/code/modules/clothing/under/accessories/accessory_vr.dm
+++ b/code/modules/clothing/under/accessories/accessory_vr.dm
@@ -366,3 +366,12 @@
item_state = "silverthree"
overlay_state = "silverthree"
desc = "A silver medal awarded to a group which has demonstrated exceptional teamwork to achieve a notable feat. This one has three bronze service stars, denoting that it has been awarded four times."
+
+/obj/item/clothing/accessory/talon
+ name = "ITV pin"
+ desc = "A collectable enamel pin that resembles ITV's company logo."
+ icon = 'icons/obj/clothing/ties_vr.dmi'
+ icon_override = 'icons/mob/ties_vr.dmi'
+ icon_state = "talon_pin"
+ item_state = "talonpin"
+ overlay_state = "talonpin"
\ No newline at end of file
diff --git a/code/modules/clothing/under/miscellaneous_vr.dm b/code/modules/clothing/under/miscellaneous_vr.dm
index aba31abd198..403993c61fa 100644
--- a/code/modules/clothing/under/miscellaneous_vr.dm
+++ b/code/modules/clothing/under/miscellaneous_vr.dm
@@ -146,3 +146,60 @@
icon_state = "pizzadelivery"
item_state = "pizzadelivery"
rolled_down = 0
+
+//////////////////////TALON JUMPSUITS//////////////////////
+
+/obj/item/clothing/under/rank/talon/basic
+ name = "ITV jumpsuit"
+ desc = "A basic jumpsuit that bares the ITV logo on the breast."
+ icon = 'icons/obj/clothing/uniforms_vr.dmi'
+ index = "vr"
+ rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
+ icon_override = 'icons/mob/uniform_vr.dmi'
+ icon_state = "talon_basic"
+ item_state = "talon_basic"
+ rolled_sleeves = 0
+
+/obj/item/clothing/under/rank/talon/proper
+ name = "ITV proper jumpsuit"
+ desc = "A neat and proper uniform for a proper company."
+ icon = 'icons/obj/clothing/uniforms_vr.dmi'
+ index = "vr"
+ rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
+ icon_override = 'icons/mob/uniform_vr.dmi'
+ icon_state = "talon_jumpsuit"
+ item_state = "talon_jumpsuit"
+ rolled_sleeves = 0
+
+/obj/item/clothing/under/rank/talon/security
+ name = "ITV security jumpsuit"
+ desc = "A sleek, streamlined version of ITV's standard jumpsuit that bares security markings."
+ icon = 'icons/obj/clothing/uniforms_vr.dmi'
+ index = "vr"
+ rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
+ icon_override = 'icons/mob/uniform_vr.dmi'
+ icon_state = "talon_security"
+ item_state = "talon_security"
+ rolled_sleeves = 0
+
+/obj/item/clothing/under/rank/talon/pilot
+ name = "ITV pilot jumpsuit"
+ desc = "A sleek, streamlined version of ITV's standard jumpsuit. Made from cushioned fabric to handle intense flight."
+ icon = 'icons/obj/clothing/uniforms_vr.dmi'
+ index = "vr"
+ rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
+ icon_override = 'icons/mob/uniform_vr.dmi'
+ icon_state = "talon_pilot"
+ item_state = "talon_pilot"
+ rolled_sleeves = 0
+
+/obj/item/clothing/under/rank/talon/command
+ name = "ITV command jumpsuit"
+ desc = "A commanding jumpsuit fit for a commanding officer."
+ icon = 'icons/obj/clothing/uniforms_vr.dmi'
+ index = "vr"
+ rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
+ icon_override = 'icons/mob/uniform_vr.dmi'
+ icon_state = "talon_captain"
+ item_state = "talon_captain"
+ rolled_sleeves = 0
\ No newline at end of file
diff --git a/code/modules/compass/compass_holder.dm b/code/modules/compass/compass_holder.dm
index 1a2148d5c42..44f981e8edf 100644
--- a/code/modules/compass/compass_holder.dm
+++ b/code/modules/compass/compass_holder.dm
@@ -75,7 +75,7 @@
var/set_overlays = (compass_static_labels | compass_waypoint_markers)
if(show_heading)
set_overlays |= compass_heading_marker
- overlays = set_overlays
+ overlays = set_overlays // ???
/obj/compass_holder/proc/clear_waypoint(var/id)
LAZYREMOVE(compass_waypoints, id)
diff --git a/code/modules/detectivework/microscope/dnascanner.dm b/code/modules/detectivework/microscope/dnascanner.dm
index b87639cce64..9af65789fee 100644
--- a/code/modules/detectivework/microscope/dnascanner.dm
+++ b/code/modules/detectivework/microscope/dnascanner.dm
@@ -111,7 +111,8 @@
var/obj/item/weapon/paper/P = new(src)
P.name = "[src] report #[++report_num]: [bloodsamp.name]"
P.stamped = list(/obj/item/weapon/stamp)
- P.overlays = list("paper_stamped")
+ P.cut_overlays()
+ P.add_overlay("paper_stamped")
//dna data itself
var/data = "No scan information available."
if(bloodsamp.dna != null)
diff --git a/code/modules/detectivework/tools/evidencebag.dm b/code/modules/detectivework/tools/evidencebag.dm
index 3a651d86695..846528a8f9f 100644
--- a/code/modules/detectivework/tools/evidencebag.dm
+++ b/code/modules/detectivework/tools/evidencebag.dm
@@ -62,8 +62,8 @@
var/image/img = image("icon"=I, "layer"=FLOAT_LAYER) //take a snapshot. (necessary to stop the underlays appearing under our inventory-HUD slots ~Carn
I.pixel_x = xx //and then return it
I.pixel_y = yy
- overlays += img
- overlays += "evidence" //should look nicer for transparent stuff. not really that important, but hey.
+ add_overlay(img)
+ add_overlay("evidence") //should look nicer for transparent stuff. not really that important, but hey.
desc = "An evidence bag containing [I]."
I.loc = src
@@ -77,7 +77,7 @@
var/obj/item/I = contents[1]
user.visible_message("[user] takes [I] out of [src]", "You take [I] out of [src].",\
"You hear someone rustle around in a plastic bag, and remove something.")
- overlays.Cut() //remove the overlays
+ cut_overlays() //remove the overlays
user.put_in_hands(I)
stored_item = null
diff --git a/code/modules/detectivework/tools/uvlight.dm b/code/modules/detectivework/tools/uvlight.dm
index 6d14b48087a..c59b3cb578f 100644
--- a/code/modules/detectivework/tools/uvlight.dm
+++ b/code/modules/detectivework/tools/uvlight.dm
@@ -42,7 +42,7 @@
stored_alpha.Cut()
if(reset_objects.len)
for(var/obj/item/I in reset_objects)
- I.overlays -= I.blood_overlay
+ I.cut_overlay(I.blood_overlay)
if(I.fluorescent == 2) I.fluorescent = 1
reset_objects.Cut()
@@ -66,5 +66,5 @@
if(istype(A, /obj/item))
var/obj/item/O = A
if(O.was_bloodied && !(O.blood_overlay in O.overlays))
- O.overlays |= O.blood_overlay
+ O.add_overlay(O.blood_overlay)
reset_objects |= O
\ No newline at end of file
diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm
index d6224638c38..128dd0e4496 100644
--- a/code/modules/economy/ATM.dm
+++ b/code/modules/economy/ATM.dm
@@ -379,7 +379,7 @@ log transactions
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
- R.overlays += stampoverlay
+ R.add_overlay(stampoverlay)
R.stamps += "This paper has been stamped by the Automatic Teller Machine."
if(prob(50))
@@ -421,7 +421,7 @@ log transactions
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
- R.overlays += stampoverlay
+ R.add_overlay(stampoverlay)
R.stamps += "This paper has been stamped by the Automatic Teller Machine."
if(prob(50))
diff --git a/code/modules/economy/Accounts.dm b/code/modules/economy/Accounts.dm
index 4c1890e78a1..a1cd0d5f300 100644
--- a/code/modules/economy/Accounts.dm
+++ b/code/modules/economy/Accounts.dm
@@ -69,7 +69,7 @@
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
- R.overlays += stampoverlay
+ R.add_overlay(stampoverlay)
R.stamps += "This paper has been stamped by the Accounts Database."
//add the account
diff --git a/code/modules/economy/EFTPOS.dm b/code/modules/economy/EFTPOS.dm
index f526dcf7cec..ecf9ff4688a 100644
--- a/code/modules/economy/EFTPOS.dm
+++ b/code/modules/economy/EFTPOS.dm
@@ -44,7 +44,7 @@
R.offset_y += 0
R.ico += "paper_stamp-cent"
R.stamped += /obj/item/weapon/stamp
- R.overlays += stampoverlay
+ R.add_overlay(stampoverlay)
R.stamps += "This paper has been stamped by the EFTPOS device."
/obj/item/device/eftpos/Destroy()
@@ -64,7 +64,7 @@
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
- R.overlays += stampoverlay
+ R.add_overlay(stampoverlay)
R.stamps += "This paper has been stamped by the EFTPOS device."
var/obj/item/smallDelivery/D = new(R.loc)
R.loc = D
diff --git a/code/modules/economy/cash.dm b/code/modules/economy/cash.dm
index f13684642c6..d84132ca864 100644
--- a/code/modules/economy/cash.dm
+++ b/code/modules/economy/cash.dm
@@ -36,7 +36,7 @@
qdel(src)
/obj/item/weapon/spacecash/update_icon()
- overlays.Cut()
+ cut_overlays()
name = "[worth] [initial_name]\s"
if(worth in list(1000,500,200,100,50,20,10,1))
icon_state = "spacecash[worth]"
@@ -53,14 +53,14 @@
M.Translate(rand(-6, 6), rand(-4, 8))
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
- src.overlays += banknote
+ add_overlay(banknote)
if(num == 0) // Less than one thaler, let's just make it look like 1 for ease
var/image/banknote = image('icons/obj/items.dmi', "spacecash1")
var/matrix/M = matrix()
M.Translate(rand(-6, 6), rand(-4, 8))
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
- src.overlays += banknote
+ add_overlay(banknote)
src.desc = "They are worth [worth] [initial_name]s."
/obj/item/weapon/spacecash/proc/adjust_worth(var/adjust_worth = 0, var/update = 1)
diff --git a/code/modules/economy/cash_register.dm b/code/modules/economy/cash_register.dm
index 8184229c8b6..29ccd38ebb9 100644
--- a/code/modules/economy/cash_register.dm
+++ b/code/modules/economy/cash_register.dm
@@ -50,7 +50,7 @@
if(cash_stored)
spawn_money(cash_stored, loc, user)
cash_stored = 0
- overlays -= "register_cash"
+ cut_overlay("register_cash")
else
open_cash_box()
else
@@ -181,7 +181,7 @@
if(cash_open)
to_chat(user, "You neatly sort the cash into the box.")
cash_stored += SC.worth
- overlays |= "register_cash"
+ add_overlay("register_cash")
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.drop_from_inventory(SC)
@@ -468,15 +468,15 @@
if(cash_open)
cash_open = 0
- overlays -= "register_approve"
- overlays -= "register_open"
- overlays -= "register_cash"
+ cut_overlay("register_approve")
+ cut_overlay("register_open")
+ cut_overlay("register_cash")
else if(!cash_locked)
cash_open = 1
- overlays += "register_approve"
- overlays += "register_open"
+ add_overlay("register_approve")
+ add_overlay("register_open")
if(cash_stored)
- overlays += "register_cash"
+ add_overlay("register_cash")
else
to_chat(usr, "The cash box is locked.")
diff --git a/code/modules/economy/coins.dm b/code/modules/economy/coins.dm
index dd30cc24b66..8f95a424b74 100644
--- a/code/modules/economy/coins.dm
+++ b/code/modules/economy/coins.dm
@@ -65,7 +65,7 @@
to_chat(user, "There already is a string attached to this coin.")
return
if (CC.use(1))
- overlays += image('icons/obj/items.dmi',"coin_string_overlay")
+ add_overlay("coin_string_overlay")
string_attached = 1
to_chat(user, "You attach a string to the coin.")
else
@@ -79,7 +79,7 @@
var/obj/item/stack/cable_coil/CC = new/obj/item/stack/cable_coil(user.loc)
CC.amount = 1
CC.update_icon()
- overlays = list()
+ cut_overlays()
string_attached = null
to_chat(user, "You detach the string from the coin.")
else ..()
diff --git a/code/modules/economy/coins_vr.dm b/code/modules/economy/coins_vr.dm
new file mode 100644
index 00000000000..a042e757081
--- /dev/null
+++ b/code/modules/economy/coins_vr.dm
@@ -0,0 +1,55 @@
+//Weird coins that I would prefer didn't work with normal vending machines. Might use them to make weird vending machines later.
+
+/obj/item/weapon/aliencoin
+ icon = 'icons/obj/aliencoins.dmi'
+ name = "curious coin"
+ desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. "
+ icon_state = "triangle"
+ randpixel = 8
+ force = 0.5
+ throwforce = 0.5
+ w_class = ITEMSIZE_TINY
+ slot_flags = SLOT_EARS
+ var/sides = 2
+ var/value = 1
+ drop_sound = 'sound/items/drop/ring.ogg'
+ pickup_sound = 'sound/items/pickup/ring.ogg'
+
+/obj/item/weapon/aliencoin/New()
+ randpixel_xy()
+
+/obj/item/weapon/aliencoin/gold
+ name = "curious coin"
+ icon_state = "triangle-g"
+ desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. This one's markings appear to reveal a golden material underneath."
+ value = 3
+
+/obj/item/weapon/aliencoin/silver
+ name = "curious coin"
+ icon_state = "triangle-s"
+ desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. This one's markings appear to reveal a silver material underneath."
+ value = 2
+
+/obj/item/weapon/aliencoin/phoron
+ name = "curious coin"
+ icon_state = "triangle-p"
+ desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. This one's markings appear to reveal a purple material underneath."
+ value = 4
+
+
+/obj/item/weapon/aliencoin/attack_self(mob/user as mob)
+ var/result = rand(1, sides)
+ var/comment = ""
+ if(result == 1)
+ comment = "tails"
+ else if(result == 2)
+ comment = "heads"
+ user.visible_message("[user] has thrown [src]. It lands on [comment]! ", runemessage = "[src] landed on [comment]")
+ if(rand(1,20) == 1)
+ user.visible_message("[user] fumbled the [src]!", runemessage = "fumbles [src]")
+ user.remove_from_mob(src)
+
+/obj/item/weapon/aliencoin/examine(var/mob/user)
+ . = ..()
+ if(Adjacent(user))
+ . += "It has some writing along its edge that seems to be some language that you are not familiar with. The face of the coin is very smooth, with what appears to be some kind of angular logo along the left side, and a couple of lines of the alien text along the opposite side. The reverse side is similarly smooth, the top of it features what appears to be some kind of vortex, surrounded by six stars, three on either side, with further swirls and intricate patterns along the bottom sections of this face. Looking closely, you can see that there is more text hidden among the swirls."
diff --git a/code/modules/emotes/definitions/audible.dm b/code/modules/emotes/definitions/audible.dm
index 679b2dd0b3f..c233cc1cccb 100644
--- a/code/modules/emotes/definitions/audible.dm
+++ b/code/modules/emotes/definitions/audible.dm
@@ -12,7 +12,7 @@
emote_message_radio_synthetic = emote_message_synthetic_3p
/decl/emote/audible/deathgasp_alien
- key = "deathgasp"
+ key = "adeathgasp"
emote_message_3p = "lets out a waning guttural screech, green blood bubbling from its maw."
/decl/emote/audible/whimper
@@ -29,7 +29,7 @@
emote_message_3p = "scretches."
/decl/emote/audible/choke
- key ="choke"
+ key = "choke"
emote_message_3p = "chokes."
conscious = FALSE
@@ -63,7 +63,7 @@
emote_message_3p = "boops."
/decl/emote/audible/beep
- key = "beep"
+ key = "bbeep"
emote_message_3p = "You beep."
emote_message_3p = "beeps."
emote_sound = 'sound/machines/twobeep.ogg'
@@ -133,18 +133,18 @@
emote_message_3p = "grunts."
/decl/emote/audible/bug_hiss
- key ="hiss"
+ key = "bhiss"
emote_message_3p_target = "hisses at TARGET."
emote_message_3p = "hisses."
emote_sound = 'sound/voice/BugHiss.ogg'
/decl/emote/audible/bug_buzz
- key ="buzz"
+ key = "bbuzz"
emote_message_3p = "buzzes its wings."
emote_sound = 'sound/voice/BugBuzz.ogg'
/decl/emote/audible/bug_chitter
- key ="chitter"
+ key = "chitter"
emote_message_3p = "chitters."
emote_sound = 'sound/voice/Bug.ogg'
@@ -213,7 +213,7 @@
emote_sound = 'sound/voice/teshsqueak.ogg' // Copyright CC BY 3.0 InspectorJ (freesound.org) for the source audio.
/decl/emote/audible/teshchirp
- key = "tchirp" // VOREStation Edit
+ key = "tchirp"
emote_message_1p = "You chirp!"
emote_message_3p = "chirps!"
emote_message_1p_target = "You chirp at TARGET!"
diff --git a/code/modules/emotes/definitions/slimes.dm b/code/modules/emotes/definitions/slimes.dm
index bde5b580aa4..65f50b069df 100644
--- a/code/modules/emotes/definitions/slimes.dm
+++ b/code/modules/emotes/definitions/slimes.dm
@@ -12,21 +12,21 @@
return ..() && isslime(user)
/decl/emote/slime/pout
- key = "pout"
+ key = "mpout"
mood = "pout"
/decl/emote/slime/sad
- key = "sad"
+ key = "msad"
mood = "sad"
/decl/emote/slime/angry
- key = "angry"
+ key = "mangry"
mood = "angry"
/decl/emote/slime/frown
- key = "frown"
+ key = "mfrown"
mood = "mischevous"
/decl/emote/slime/smile
- key = "smile"
+ key = "msmile"
mood = ":3"
diff --git a/code/modules/emotes/definitions/visible.dm b/code/modules/emotes/definitions/visible.dm
index fa19ac257a3..d37058626d2 100644
--- a/code/modules/emotes/definitions/visible.dm
+++ b/code/modules/emotes/definitions/visible.dm
@@ -1,5 +1,5 @@
/decl/emote/visible
- key ="tail"
+ key = "tail"
emote_message_3p = "waves USER_THEIR tail."
message_type = VISIBLE_MESSAGE
@@ -9,48 +9,48 @@
emote_message_3p = "scratches."
/decl/emote/visible/drool
- key ="drool"
+ key = "drool"
emote_message_3p = "drools."
conscious = FALSE
/decl/emote/visible/nod
- key ="nod"
+ key = "nod"
emote_message_3p_target = "nods USER_THEIR head at TARGET."
emote_message_3p = "nods USER_THEIR head."
/decl/emote/visible/sway
- key ="sway"
+ key = "sways"
emote_message_3p = "sways around dizzily."
/decl/emote/visible/sulk
- key ="sulk"
+ key = "sulk"
emote_message_3p = "sulks down sadly."
/decl/emote/visible/dance
- key ="dance"
+ key = "dance"
check_restraints = TRUE
emote_message_3p = "dances around happily."
/decl/emote/visible/roll
- key ="roll"
+ key = "roll"
check_restraints = TRUE
emote_message_3p = "rolls."
/decl/emote/visible/shake
- key ="shake"
+ key = "shake"
emote_message_3p = "shakes USER_THEIR head."
/decl/emote/visible/jump
- key ="jump"
+ key = "jump"
emote_message_3p = "jumps!"
/decl/emote/visible/shiver
- key ="shiver"
+ key = "shiver"
emote_message_3p = "shivers."
conscious = FALSE
/decl/emote/visible/collapse
- key ="collapse"
+ key = "collapse"
emote_message_3p = "collapses!"
/decl/emote/visible/collapse/do_extra(var/mob/user)
@@ -216,7 +216,7 @@
emote_message_3p = "vibrates!"
/decl/emote/visible/deathgasp_robot
- key = "deathgasp"
+ key = "rdeathgasp"
emote_message_3p = "shudders violently for a moment, then becomes motionless, USER_THEIR eyes slowly darkening."
/decl/emote/visible/handshake
diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm
index bd1dfc0bd6f..d0173258725 100644
--- a/code/modules/emotes/emote_mob.dm
+++ b/code/modules/emotes/emote_mob.dm
@@ -79,7 +79,7 @@
return
if(!use_emote.mob_can_use(src))
- to_chat(src, SPAN_WARNING("You cannot use the emote '[act]'. Type say *help for a list of usable emotes."))
+ to_chat(src, SPAN_WARNING("You cannot use the emote '[act]'. Type say *help for a list of usable emotes."))
return
if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS)
diff --git a/code/modules/fishing/fishing_net.dm b/code/modules/fishing/fishing_net.dm
index ab1e35ea6a3..39c5e92eef3 100644
--- a/code/modules/fishing/fishing_net.dm
+++ b/code/modules/fishing/fishing_net.dm
@@ -78,7 +78,7 @@
/obj/item/weapon/material/fishing_net/update_icon() // Also updates name and desc
underlays.Cut()
- overlays.Cut()
+ cut_overlays()
..()
diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm
index ea4571442f6..ae089d26a2c 100644
--- a/code/modules/fishing/fishing_rod.dm
+++ b/code/modules/fishing/fishing_rod.dm
@@ -78,10 +78,10 @@
return ..()
/obj/item/weapon/material/fishing_rod/update_icon()
- overlays.Cut()
+ cut_overlays()
..()
if(strung)
- overlays += image(icon, "[icon_state]_string")
+ add_overlay("[icon_state]_string")
/obj/item/weapon/material/fishing_rod/proc/update_bait()
if(istype(Bait, bait_type))
diff --git a/code/modules/food/food/drinks/drinkingglass.dm b/code/modules/food/food/drinks/drinkingglass.dm
index 7324dc8ad82..85e8de07058 100644
--- a/code/modules/food/food/drinks/drinkingglass.dm
+++ b/code/modules/food/food/drinks/drinkingglass.dm
@@ -118,7 +118,7 @@
matter = list("glass" = 175)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change()
- overlays.Cut()
+ cut_overlays()
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]1")
@@ -129,7 +129,7 @@
if(8 to INFINITY) filling.icon_state = "[icon_state]12"
filling.color += reagents.get_color()
- overlays += filling
+ add_overlay(filling)
name = "shot glass of " + reagents.get_master_reagent_name() //No matter what, the glass will tell you the reagent's name. Might be too abusable in the future.
else
name = "shot glass"
@@ -146,7 +146,7 @@
icon_state = pick("fitness-cup_black", "fitness-cup_red", "fitness-cup_black")
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/fitnessflask/on_reagent_change()
- overlays.Cut()
+ cut_overlays()
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "fitness-cup10")
@@ -164,7 +164,7 @@
if(90 to INFINITY) filling.icon_state = "fitness-cup100"
filling.color += reagents.get_color()
- overlays += filling
+ add_overlay(filling)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/fitnessflask/proteinshake
name = "protein shake"
diff --git a/code/modules/food/food/sandwich.dm b/code/modules/food/food/sandwich.dm
index 6929586c05e..738e3f4a461 100644
--- a/code/modules/food/food/sandwich.dm
+++ b/code/modules/food/food/sandwich.dm
@@ -46,7 +46,7 @@
var/fullname = "" //We need to build this from the contents of the var.
var/i = 0
- overlays.Cut()
+ cut_overlays()
for(var/obj/item/weapon/reagent_containers/food/snacks/O in ingredients)
@@ -62,12 +62,12 @@
I.color = O.filling_color
I.pixel_x = pick(list(-1,0,1))
I.pixel_y = (i*2)+1
- overlays += I
+ add_overlay(I)
var/image/T = new(src.icon, "sandwich_top")
T.pixel_x = pick(list(-1,0,1))
T.pixel_y = (ingredients.len * 2)+1
- overlays += T
+ add_overlay(T)
name = lowertext("[fullname] sandwich")
if(length(name) > 80) name = "[pick(list("absurd","colossal","enormous","ridiculous"))] sandwich"
diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm
index c0968f3381e..6c7d9186f25 100644
--- a/code/modules/food/food/snacks.dm
+++ b/code/modules/food/food/snacks.dm
@@ -189,11 +189,11 @@
)
src.bitecount++
- U.overlays.Cut()
+ U.cut_overlays()
U.loaded = "[src]"
var/image/I = new(U.icon, "loadedfood")
I.color = src.filling_color
- U.overlays += I
+ U.add_overlay(I)
reagents.trans_to_obj(U, min(reagents.total_volume,5))
@@ -3166,7 +3166,7 @@
/obj/item/pizzabox/update_icon()
- overlays = list()
+ cut_overlays()
// Set appropriate description
if( open && pizza )
@@ -3194,7 +3194,7 @@
if( pizza )
var/image/pizzaimg = image(icon = pizza.icon, icon_state = pizza.icon_state) //VOREStation Edit: Icons for bad pizza
pizzaimg.pixel_y = -3
- overlays += pizzaimg
+ add_overlay(pizzaimg)
return
else
@@ -3211,7 +3211,7 @@
if( doimgtag )
var/image/tagimg = image("food.dmi", icon_state = "pizzabox_tag")
tagimg.pixel_y = boxes.len * 3
- overlays += tagimg
+ add_overlay(tagimg)
icon_state = "pizzabox[boxes.len+1]"
@@ -4238,7 +4238,7 @@
J.alpha = 200
J.blend_mode = BLEND_OVERLAY
J.tag = "coating"
- overlays += J
+ add_overlay(J)
if (user)
user.visible_message(span("notice", "[user] dips \the [src] into \the [coating.name]"), span("notice", "You dip \the [src] into \the [coating.name]"))
@@ -4269,7 +4269,7 @@
var/image/J = image(I)
J.alpha = 200
J.tag = "coating"
- overlays += J
+ add_overlay(J)
if (do_coating_prefix == 1)
diff --git a/code/modules/food/food/thecake.dm b/code/modules/food/food/thecake.dm
index 33876999620..0b45d1eeb63 100644
--- a/code/modules/food/food/thecake.dm
+++ b/code/modules/food/food/thecake.dm
@@ -1,8 +1,8 @@
// Chaos cake
/datum/recipe/chaoscake_layerone
- reagents = list("flour" = 300,"milk" = 200, "sugar" = 100, "egg" = 30)
- fruit = list("poisonberries" = 15, "cherries" = 15)
+ reagents = list("flour" = 30,"milk" = 20, "sugar" = 10, "egg" = 9)
+ fruit = list("poisonberries" = 2, "cherries" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/meat/,
/obj/item/weapon/reagent_containers/food/snacks/meat/,
@@ -12,8 +12,8 @@
result = /obj/structure/chaoscake
/datum/recipe/chaoscake_layertwo
- reagents = list("flour" = 300, "milk" = 200, "sugar" = 100, "egg" = 30, )
- fruit = list("vanilla" = 15, "banana" = 15)
+ reagents = list("flour" = 30, "milk" = 20, "sugar" = 10, "egg" = 9, )
+ fruit = list("vanilla" = 2, "banana" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -23,8 +23,8 @@
result = /obj/item/weapon/chaoscake_layer
/datum/recipe/chaoscake_layerthree
- reagents = list("flour" = 240, "milk" = 150, "sugar" = 80, "egg" = 24, "deathbell" = 100)
- fruit = list("grapes" = 30)
+ reagents = list("flour" = 25, "milk" = 15, "sugar" = 10, "egg" = 6, "deathbell" = 10)
+ fruit = list("grapes" = 3)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -33,8 +33,8 @@
result = /obj/item/weapon/chaoscake_layer/three
/datum/recipe/chaoscake_layerfour
- reagents = list("flour" = 240, "milk" = 150, "sugar" = 80, "egg" = 24, "milkshake" = 300)
- fruit = list("rice" = 30)
+ reagents = list("flour" = 25, "milk" = 15, "sugar" = 10, "egg" = 6, "milkshake" = 30)
+ fruit = list("rice" = 3)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -43,14 +43,14 @@
result = /obj/item/weapon/chaoscake_layer/four
/datum/recipe/chaoscake_layerfive
- reagents = list("flour" = 180, "milk" = 100, "sugar" = 60, "egg" = 18, "blood" = 300)
- fruit = list("tomato" = 20)
+ reagents = list("flour" = 20, "milk" = 10, "sugar" = 10, "egg" = 6, "blood" = 30)
+ fruit = list("tomato" = 2)
items = list() //supposed to be made with lobster, still has to be ported.
result = /obj/item/weapon/chaoscake_layer/five
/datum/recipe/chaoscake_layersix
- reagents = list("flour" = 180, "milk" = 100, "sugar" = 60, "egg" = 18, "sprinkles" = 10)
- fruit = list("apple" = 30)
+ reagents = list("flour" = 20, "milk" = 10, "sugar" = 10, "egg" = 6, "sprinkles" = 5)
+ fruit = list("apple" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -62,8 +62,8 @@
result = /obj/item/weapon/chaoscake_layer/six
/datum/recipe/chaoscake_layerseven
- reagents = list("flour" = 120, "milk" = 50, "sugar" = 40, "egg" = 12, "devilskiss" = 200)
- fruit = list("potato" = 10)
+ reagents = list("flour" = 15, "milk" = 10, "sugar" = 5, "egg" = 3, "devilskiss" = 20)
+ fruit = list("potato" = 1)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -72,8 +72,8 @@
result = /obj/item/weapon/chaoscake_layer/seven
/datum/recipe/chaoscake_layereight
- reagents = list("flour" = 120, "milk" = 50, "sugar" = 40, "egg" = 12, "cream" = 200)
- fruit = list("lemon" = 10)
+ reagents = list("flour" = 15, "milk" = 10, "sugar" = 5, "egg" = 3, "cream" = 20)
+ fruit = list("lemon" = 1)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -82,8 +82,8 @@
result = /obj/item/weapon/chaoscake_layer/eight
/datum/recipe/chaoscake_layernine
- reagents = list("water" = 100, "blood" = 100)
- fruit = list("goldapple" = 50)
+ reagents = list("water" = 10, "blood" = 10)
+ fruit = list("goldapple" = 1)
items = list()
result = /obj/item/weapon/chaoscake_layer/nine
diff --git a/code/modules/food/food/z_custom_food_vr.dm b/code/modules/food/food/z_custom_food_vr.dm
index 9788a1e2b40..b50e99b3288 100644
--- a/code/modules/food/food/z_custom_food_vr.dm
+++ b/code/modules/food/food/z_custom_food_vr.dm
@@ -55,14 +55,14 @@ var/global/ingredientLimit = 20
ingredients += S
if(src.addTop)
- overlays -= topping //thank you Comic
- if(!fullyCustom && !stackIngredients && overlays.len)
- overlays -= filling //we can't directly modify the overlay, so we have to remove it and then add it again
+ cut_overlay(topping)
+ if(!fullyCustom && !stackIngredients && our_overlays.len)
+ cut_overlay(filling) //we can't directly modify the overlay, so we have to remove it and then add it again
var/newcolor = S.filling_color != "#FFFFFF" ? S.filling_color : AverageColor(getFlatIcon(S, S.dir, 0), 1, 1)
filling.color = BlendRGB(filling.color, newcolor, 1/ingredients.len)
- overlays += filling
+ add_overlay(filling)
else
- overlays += generateFilling(S)
+ add_overlay(generateFilling(S))
if(addTop)
drawTopping()
@@ -129,7 +129,7 @@ var/global/ingredientLimit = 20
/obj/item/weapon/reagent_containers/food/snacks/customizable/proc/drawTopping()
var/image/I = topping
I.pixel_y = (ingredients.len+1)*2
- overlays += I
+ add_overlay(I)
// Sandwiches //////////////////////////////////////////////////
diff --git a/code/modules/food/glass/bottle.dm b/code/modules/food/glass/bottle.dm
index f372a2facf5..a3c511df484 100644
--- a/code/modules/food/glass/bottle.dm
+++ b/code/modules/food/glass/bottle.dm
@@ -35,7 +35,7 @@
icon_state = "bottle-[rand(1,4)]"
/obj/item/weapon/reagent_containers/glass/bottle/update_icon()
- overlays.Cut()
+ cut_overlays()
if(reagents.total_volume && (icon_state == "bottle-1" || icon_state == "bottle-2" || icon_state == "bottle-3" || icon_state == "bottle-4"))
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
@@ -51,11 +51,11 @@
if(91 to INFINITY) filling.icon_state = "[icon_state]-100"
filling.color = reagents.get_color()
- overlays += filling
+ add_overlay(filling)
if (!is_open_container())
var/image/lid = image(icon, src, "lid_bottle")
- overlays += lid
+ add_overlay(lid)
/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline
name = "inaprovaline bottle"
diff --git a/code/modules/food/kitchen/cooking_machines/cereal.dm b/code/modules/food/kitchen/cooking_machines/cereal.dm
index ae2516da4aa..b80746add44 100644
--- a/code/modules/food/kitchen/cooking_machines/cereal.dm
+++ b/code/modules/food/kitchen/cooking_machines/cereal.dm
@@ -36,10 +36,10 @@
var/image/food_image = image(CI.object.icon, CI.object.icon_state)
food_image.color = CI.object.color
- food_image.overlays += CI.object.overlays
+ food_image.add_overlay(CI.object.overlays)
food_image.transform *= 0.7
- product.overlays += food_image
+ product.add_overlay(food_image)
*/
/obj/machinery/appliance/mixer/cereal/update_icon()
@@ -83,4 +83,4 @@
result.color = result.filling_color
for (var/i in images)
- result.overlays += images[i]
+ result.add_overlay(images[i])
diff --git a/code/modules/food/kitchen/gibber.dm b/code/modules/food/kitchen/gibber.dm
index 6402a432ae9..cb52a0ca7b6 100644
--- a/code/modules/food/kitchen/gibber.dm
+++ b/code/modules/food/kitchen/gibber.dm
@@ -58,20 +58,20 @@
/obj/machinery/gibber/New()
..()
- src.overlays += image('icons/obj/kitchen.dmi', "grjam")
+ add_overlay("grjam")
/obj/machinery/gibber/update_icon()
- overlays.Cut()
+ cut_overlays()
if (dirty)
- src.overlays += image('icons/obj/kitchen.dmi', "grbloody")
+ add_overlay("grbloody")
if(stat & (NOPOWER|BROKEN))
return
if (!occupant)
- src.overlays += image('icons/obj/kitchen.dmi', "grjam")
+ add_overlay("grjam")
else if (operating)
- src.overlays += image('icons/obj/kitchen.dmi', "gruse")
+ add_overlay("gruse")
else
- src.overlays += image('icons/obj/kitchen.dmi', "gridle")
+ add_overlay("gridle")
/obj/machinery/gibber/relaymove(mob/user as mob)
src.go_out()
diff --git a/code/modules/food/kitchen/icecream.dm b/code/modules/food/kitchen/icecream.dm
index 2b53b657ce1..02335c8a9e5 100644
--- a/code/modules/food/kitchen/icecream.dm
+++ b/code/modules/food/kitchen/icecream.dm
@@ -183,7 +183,7 @@
/obj/item/weapon/reagent_containers/food/snacks/icecream/proc/add_ice_cream(var/flavour_name)
name = "[flavour_name] icecream"
- src.overlays += "icecream_[flavour_name]"
+ add_overlay("icecream_[flavour_name]")
desc = "Delicious [cone_type] cone with a dollop of [flavour_name] ice cream."
ice_creamed = 1
diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm
index 0b58b5110fb..0165c9315fb 100644
--- a/code/modules/games/cards.dm
+++ b/code/modules/games/cards.dm
@@ -410,7 +410,7 @@
name = "a playing card"
desc = "A playing card."
- overlays.Cut()
+ cut_overlays()
if(cards.len == 1)
@@ -418,7 +418,7 @@
var/image/I = new(src.icon, (concealed ? "[P.back_icon]" : "[P.card_icon]") )
I.pixel_x += (-5+rand(10))
I.pixel_y += (-5+rand(10))
- overlays += I
+ add_overlay(I)
return
var/offset = FLOOR(20/cards.len, 1)
@@ -450,7 +450,7 @@
else
I.pixel_x = -7+(offset*i)
I.transform = M
- overlays += I
+ add_overlay(I)
i++
/obj/item/weapon/hand/dropped(mob/user as mob)
diff --git a/code/modules/holomap/holomap_datum.dm b/code/modules/holomap/holomap_datum.dm
index af4cc6f2744..f6d4f61bba5 100644
--- a/code/modules/holomap/holomap_datum.dm
+++ b/code/modules/holomap/holomap_datum.dm
@@ -20,15 +20,15 @@
legend.pixel_x = HOLOMAP_LEGEND_X(T.z)
legend.pixel_y = HOLOMAP_LEGEND_Y(T.z)
- station_map.overlays |= cursor
- station_map.overlays |= legend
+ station_map.add_overlay(cursor)
+ station_map.add_overlay(legend)
/datum/station_holomap/proc/initialize_holomap_bogus()
station_map = image('icons/480x480.dmi', "stationmap")
legend = image('icons/effects/64x64.dmi', "notfound")
legend.pixel_x = 7 * WORLD_ICON_SIZE
legend.pixel_y = 7 * WORLD_ICON_SIZE
- station_map.overlays |= legend
+ station_map.add_overlay(legend)
// TODO - Strategic Holomap support
// /datum/station_holomap/strategic/initialize_holomap(var/turf/T, var/isAI=null, var/mob/user=null)
@@ -37,4 +37,4 @@
// legend = image('icons/effects/64x64.dmi', "strategic")
// legend.pixel_x = 3*WORLD_ICON_SIZE
// legend.pixel_y = 3*WORLD_ICON_SIZE
-// station_map.overlays |= legend
+// station_map.add_overlay(legend)
diff --git a/code/modules/holomap/mapper.dm b/code/modules/holomap/mapper.dm
index 47460208688..430a4176ba4 100644
--- a/code/modules/holomap/mapper.dm
+++ b/code/modules/holomap/mapper.dm
@@ -265,7 +265,7 @@
markerImage.appearance_flags = RESET_COLOR|PIXEL_SCALE
markerImage.pixel_x = holomarker.x+holomarker.offset_x
markerImage.pixel_y = holomarker.y+holomarker.offset_y
- map_app.overlays += markerImage
+ map_app.add_overlay(markerImage)
var/obj/screen/mapper/map/tmp = new()
tmp.appearance = map_app
@@ -286,13 +286,10 @@
continue
var/mob_indicator = HOLOMAP_ERROR
var/turf/TU = get_turf(HC)
- if(TU.z != T_z)
+ // Mapper not on a turf or elsewhere
+ if(!TU || (TU.z != T_z))
continue
-
- // Marker not on a turf
- if(!TU)
- continue
-
+
// We're the marker
if(HC == src)
mob_indicator = HOLOMAP_YOU
@@ -342,26 +339,27 @@
handle_marker(mark,TU.x,TU.y)
extras += mark
- // Marker beacon items
- for(var/hb in mapping_beacons)
- var/obj/item/device/holomap_beacon/HB = hb
- if(HB.mapper_filter != mapper_filter)
- continue
-
- var/turf/TB = get_turf(HB)
- if(TU.z != T_z)
- continue
-
- var/marker_cache_key = "\ref[HB]_marker"
- if(!(marker_cache_key in icon_image_cache))
- var/obj/screen/mapper/marker/mark = new()
- mark.icon_state = "beacon"
- mark.layer = 1
- icon_image_cache[marker_cache_key] = mark
-
- var/obj/screen/mapper/marker/mark = icon_image_cache[marker_cache_key]
- handle_marker(mark,TB.x,TB.y)
- extras += mark
+ // Marker beacon items
+ for(var/hb in mapping_beacons)
+ var/obj/item/device/holomap_beacon/HB = hb
+ if(HB.mapper_filter != mapper_filter)
+ continue
+
+ var/turf/TB = get_turf(HB)
+ // Marker beacon not on a turf or elsewhere
+ if(!TB || (TB.z != T_z))
+ continue
+
+ var/marker_cache_key = "\ref[HB]_marker"
+ if(!(marker_cache_key in icon_image_cache))
+ var/obj/screen/mapper/marker/mark = new()
+ mark.icon_state = "beacon"
+ mark.layer = 1
+ icon_image_cache[marker_cache_key] = mark
+
+ var/obj/screen/mapper/marker/mark = icon_image_cache[marker_cache_key]
+ handle_marker(mark,TB.x,TB.y)
+ extras += mark
if(badmap)
var/obj/O = icon_image_cache["bad"]
@@ -419,7 +417,7 @@
else
in_list = FALSE
mapping_beacons -= src
- icon_state = initial(icon_state) + in_list ? "_on" : ""
+ icon_state = "[initial(icon_state)][in_list ? "_on" : ""]"
to_chat(user,SPAN_NOTICE("The [src] is now [in_list ? "broadcasting" : "disabled"]."))
/obj/item/device/holomap_beacon/Destroy()
diff --git a/code/modules/holomap/station_holomap.dm b/code/modules/holomap/station_holomap.dm
index dc15dabb465..9d56943856d 100644
--- a/code/modules/holomap/station_holomap.dm
+++ b/code/modules/holomap/station_holomap.dm
@@ -169,7 +169,7 @@
if(!holomap_datum)
return //Not yet.
- overlays.Cut()
+ cut_overlays()
if(stat & BROKEN)
icon_state = "station_mapb"
else if((stat & NOPOWER) || !anchored)
@@ -180,8 +180,8 @@
if(bogus)
holomap_datum.initialize_holomap_bogus()
else
- small_station_map.icon = SSholomaps.extraMiniMaps["[HOLOMAP_EXTRA_STATIONMAPSMALL]_[original_zLevel]"]
- overlays |= small_station_map
+ small_station_map = image(SSholomaps.extraMiniMaps["[HOLOMAP_EXTRA_STATIONMAPSMALL]_[original_zLevel]"], dir = src.dir)
+ add_overlay(small_station_map)
holomap_datum.initialize_holomap(get_turf(src))
// Put the little "map" overlay down where it looks nice
@@ -189,12 +189,12 @@
floor_markings.dir = src.dir
floor_markings.pixel_x = -src.pixel_x
floor_markings.pixel_y = -src.pixel_y
- overlays += floor_markings
+ add_overlay(floor_markings)
if(panel_open)
- overlays += "station_map-panel"
+ add_overlay("station_map-panel")
else
- overlays -= "station_map-panel"
+ cut_overlay("station_map-panel")
/obj/machinery/station_map/attackby(obj/item/weapon/W as obj, mob/user as mob)
src.add_fingerprint(user)
diff --git a/code/modules/hydroponics/beekeeping/beehive.dm b/code/modules/hydroponics/beekeeping/beehive.dm
index dcef997e365..f514ff8b6a8 100644
--- a/code/modules/hydroponics/beekeeping/beehive.dm
+++ b/code/modules/hydroponics/beekeeping/beehive.dm
@@ -13,22 +13,22 @@
var/maxFrames = 5
/obj/machinery/beehive/update_icon()
- overlays.Cut()
+ cut_overlays()
icon_state = "beehive"
if(closed)
- overlays += "lid"
+ add_overlay("lid")
if(frames)
- overlays += "empty[frames]"
+ add_overlay("empty[frames]")
if(honeycombs >= 100)
- overlays += "full[round(honeycombs / 100)]"
+ add_overlay("full[round(honeycombs / 100)]")
if(!smoked)
switch(bee_count)
if(1 to 40)
- overlays += "bees1"
+ add_overlay("bees1")
if(41 to 80)
- overlays += "bees2"
+ add_overlay("bees2")
if(81 to 100)
- overlays += "bees3"
+ add_overlay("bees3")
/obj/machinery/beehive/examine(var/mob/user)
. = ..()
@@ -217,7 +217,7 @@
/obj/item/honey_frame/filled/New()
..()
- overlays += "honeycomb"
+ add_overlay("honeycomb")
/obj/item/beehive_assembly
name = "beehive assembly"
@@ -269,18 +269,18 @@ var/global/list/datum/stack_recipe/wax_recipes = list( \
/obj/item/bee_pack/New()
..()
- overlays += "beepack-full"
+ add_overlay("beepack-full")
/obj/item/bee_pack/proc/empty()
full = 0
name = "empty bee pack"
desc = "A stasis pack for moving bees. It's empty."
- overlays.Cut()
- overlays += "beepack-empty"
+ cut_overlays()
+ add_overlay("beepack-empty")
/obj/item/bee_pack/proc/fill()
full = initial(full)
name = initial(name)
desc = initial(desc)
- overlays.Cut()
- overlays += "beepack-full"
\ No newline at end of file
+ cut_overlays()
+ add_overlay("beepack-full")
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 96b4385a08c..8e262bb69f9 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -125,7 +125,7 @@
/obj/item/weapon/reagent_containers/food/snacks/grown/update_icon()
if(!seed || !SSplants || !SSplants.plant_icon_cache)
return
- overlays.Cut()
+ cut_overlays()
var/image/plant_icon
var/icon_key = "fruit-[seed.get_trait(TRAIT_PRODUCT_ICON)]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"
if(SSplants.plant_icon_cache[icon_key])
@@ -134,13 +134,13 @@
plant_icon = image('icons/obj/hydroponics_products.dmi',"blank")
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
+ plant_icon.add_overlay(fruit_base)
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
+ add_overlay(fruit_leaves)
SSplants.plant_icon_cache[icon_key] = plant_icon
- overlays |= plant_icon
+ add_overlay(plant_icon)
/obj/item/weapon/reagent_containers/food/snacks/grown/Crossed(var/mob/living/M)
if(M.is_incorporeal())
@@ -363,9 +363,9 @@ var/list/fruit_icon_cache = list()
var/image/I = image(icon,"fruit_rind")
I.color = rind_colour
fruit_icon_cache["rind-[rind_colour]"] = I
- overlays |= fruit_icon_cache["rind-[rind_colour]"]
+ add_overlay(fruit_icon_cache["rind-[rind_colour]"])
if(!fruit_icon_cache["slice-[rind_colour]"])
var/image/I = image(icon,"fruit_slice")
I.color = flesh_colour
fruit_icon_cache["slice-[rind_colour]"] = I
- overlays |= fruit_icon_cache["slice-[rind_colour]"]
+ add_overlay(fruit_icon_cache["slice-[rind_colour]"])
diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm
index cb5bb5c68f6..08eea609bfb 100644
--- a/code/modules/hydroponics/seed_packets.dm
+++ b/code/modules/hydroponics/seed_packets.dm
@@ -28,7 +28,7 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds)
if(!seed) return
// Update icon.
- overlays.Cut()
+ cut_overlays()
var/is_seeds = ((seed.seed_noun in list("seeds","pits","nodes")) ? 1 : 0)
var/image/seed_mask
var/seed_base_key = "base-[is_seeds ? seed.get_trait(TRAIT_PLANT_COLOUR) : "spores"]"
@@ -49,8 +49,8 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds)
seed_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR)
plant_seed_sprites[seed_overlay_key] = seed_overlay
- overlays |= seed_mask
- overlays |= seed_overlay
+ add_overlay(seed_mask)
+ add_overlay(seed_overlay)
if(is_seeds)
src.name = "packet of [seed.seed_name] [seed.seed_noun]"
diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm
index 392accde8fe..8034e3d9ff1 100644
--- a/code/modules/hydroponics/seed_storage.dm
+++ b/code/modules/hydroponics/seed_storage.dm
@@ -405,9 +405,9 @@
panel_open = !panel_open
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
playsound(src, O.usesound, 50, 1)
- overlays.Cut()
+ cut_overlays()
if(panel_open)
- overlays += image(icon, "[initial(icon_state)]-panel")
+ add_overlay("[initial(icon_state)]-panel")
else if((O.is_wirecutter() || istype(O, /obj/item/device/multitool)) && panel_open)
wires.Interact(user)
diff --git a/code/modules/lighting/emissive_blocker.dm b/code/modules/lighting/emissive_blocker.dm
new file mode 100644
index 00000000000..690b9b52163
--- /dev/null
+++ b/code/modules/lighting/emissive_blocker.dm
@@ -0,0 +1,46 @@
+/**
+ * Internal atom that copies an appearance on to the blocker plane
+ *
+ * Copies an appearance vis render_target and render_source on to the emissive blocking plane.
+ * This means that the atom in question will block any emissive sprites.
+ * This should only be used internally. If you are directly creating more of these, you're
+ * almost guaranteed to be doing something wrong.
+ */
+/atom/movable/emissive_blocker
+ name = "emissive blocker"
+ plane = PLANE_EMISSIVE
+ layer = FLOAT_LAYER
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ //Why?
+ //render_targets copy the transform of the target as well, but vis_contents also applies the transform
+ //to what's in it. Applying RESET_TRANSFORM here makes vis_contents not apply the transform.
+ //Since only render_target handles transform we don't get any applied transform "stacking"
+ appearance_flags = RESET_TRANSFORM
+
+/atom/movable/emissive_blocker/Initialize(mapload, source)
+ . = ..()
+ verbs.Cut() //Cargo culting from lighting object, this maybe affects memory usage?
+
+ render_source = source
+ color = GLOB.em_block_color
+
+
+/atom/movable/emissive_blocker/ex_act(severity)
+ return FALSE
+
+/atom/movable/emissive_blocker/singularity_act()
+ return
+
+/atom/movable/emissive_blocker/singularity_pull()
+ return
+
+/atom/movable/emissive_blocker/blob_act()
+ return
+
+/atom/movable/emissive_blocker/onTransitZ()
+ return
+
+//Prevents people from moving these after creation, because they shouldn't be.
+/atom/movable/emissive_blocker/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE)
+ if(harderforce)
+ return ..()
diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm
index 39894b13947..ec33bc962ac 100644
--- a/code/modules/lighting/lighting_atom.dm
+++ b/code/modules/lighting/lighting_atom.dm
@@ -1,110 +1,218 @@
/atom
- var/light_power = 1 // intensity of the light
- var/light_range = 0 // range in tiles of the light
- var/light_color // Hexadecimal RGB string representing the colour of the light
+ ///Light systems, both shouldn't be active at the same time.
+ var/light_system = STATIC_LIGHT
+ ///Range of the light in tiles. Zero means no light.
+ var/light_range = 0
+ ///Intensity of the light. The stronger, the less shadows you will see on the lit area.
+ var/light_power = 1
+ ///Hexadecimal RGB string representing the colour of the light. White by default.
+ var/light_color = COLOR_WHITE
+ ///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values.
+ var/light_on = FALSE
+ ///Bitflags to determine lighting-related atom properties.
+ var/light_flags = NONE
+ ///Our light source. Don't fuck with this directly unless you have a good reason!
+ var/tmp/datum/light_source/light
+ ///Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list.
+ var/tmp/list/light_sources
- var/datum/light_source/light
- var/list/light_sources
+/atom/movable
+ ///Hint for directional light cone positioning. X is relevant when facing north/south (this setting is for south and inverted for north)
+ var/light_cone_x_offset // When facing south, inverted when facing north
+ ///Hint for directional light cone positioning. Y is relevant when facing east/west (same value used for both east and west)
+ var/light_cone_y_offset // When facing east/west, ignored for north/south (uses 16 in those cases)
+ ///Highest-intensity light affecting us, which determines our visibility.
+ var/affecting_dynamic_lumi = 0
+ ///Lazylist to keep track on the sources of illumination.
+ var/list/affected_dynamic_lights
+ ///Either FALSE, [EMISSIVE_BLOCK_GENERIC], or [EMISSIVE_BLOCK_UNIQUE]
+ var/blocks_emissive = FALSE
+ ///Internal holder for emissive blocker object, do not use directly use blocks_emissive
+ var/atom/movable/emissive_blocker/em_block
-// Nonsensical value for l_color default, so we can detect if it gets set to null.
+// The proc you should always use to set the light of this atom.
+// Nonesensical value for l_color default, so we can detect if it gets set to null.
#define NONSENSICAL_VALUE -99999
-/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE)
- . = 0 //make it less costly if nothing's changed
+/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_on)
+ if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
+ l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players.
+
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT, l_range, l_power, l_color, l_on) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+
+ // Legacy behavior helper
+ if(l_range == 0)
+ l_on = FALSE
+ else if(l_range > 0)
+ l_on = TRUE
+
+ var/needs_update = FALSE
+ if(!isnull(l_power) && l_power != light_power)
+ if(!isnull(set_light_power(l_power)))
+ needs_update = TRUE
+
+ if(!isnull(l_range) && l_range != light_range)
+ if(!isnull(set_light_range(l_range)))
+ needs_update = TRUE
- if(l_power != null && l_power != light_power)
- light_power = l_power
- . = 1
- if(l_range != null && l_range != light_range)
- light_range = l_range
- . = 1
if(l_color != NONSENSICAL_VALUE && l_color != light_color)
- light_color = l_color
- . = 1
+ if(!isnull(set_light_color(l_color)))
+ needs_update = TRUE
- if(.) update_light()
+ if(!isnull(l_on) && l_on != light_on)
+ if(!isnull(set_light_on(l_on)))
+ needs_update = TRUE
+
+ if(needs_update)
+ update_light()
#undef NONSENSICAL_VALUE
+// Will update the light (duh).
+// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf...
/atom/proc/update_light()
set waitfor = FALSE
+ if (QDELETED(src))
+ return
- if(!light_power || !light_range)
- if(light)
- light.destroy()
- light = null
+ if(light_system != STATIC_LIGHT)
+ CRASH("update_light() for [src] with following light_system value: [light_system]")
+
+ if (!light_on || !light_power || !light_range) // We won't emit light anyways, destroy the light source.
+ QDEL_NULL(light)
else
- if(!istype(loc, /atom/movable))
+ if (!ismovable(loc)) // We choose what atom should be the top atom of the light here.
. = src
else
. = loc
- if(light)
+ if (light) // Update the light or create it if it does not exist.
light.update(.)
else
- light = new /datum/light_source(src, .)
+ light = new/datum/light_source(src, .)
-/atom/New()
- . = ..()
-
- if(light_power && light_range)
- update_light()
-
- if(opacity && isturf(loc))
- var/turf/T = loc
- T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways.
-
-/atom/Destroy()
- if(light)
- light.destroy()
- light = null
- return ..()
-
-/atom/movable/Destroy()
- var/turf/T = loc
- if(opacity && istype(T))
- T.reconsider_lights()
- return ..()
-
-/atom/movable/Moved(atom/old_loc, direction, forced = FALSE)
- . = ..()
-
- for(var/datum/light_source/L in light_sources)
- L.source_atom.update_light()
-
- var/turf/new_turf = loc
- var/turf/old_turf = old_loc
- if(istype(old_turf) && opacity)
- old_turf.reconsider_lights()
-
- if(istype(new_turf) && opacity)
- new_turf.reconsider_lights()
+/**
+ * Updates the atom's opacity value.
+ *
+ * This exists to act as a hook for associated behavior.
+ * It notifies (potentially) affected light sources so they can update (if needed).
+ */
/atom/proc/set_opacity(new_opacity)
if(new_opacity == opacity)
return
-
+ SEND_SIGNAL(src, COMSIG_ATOM_SET_OPACITY, new_opacity)
+ . = opacity
opacity = new_opacity
- var/turf/T = isturf(src) ? src : loc
- if(!isturf(T))
+
+
+/atom/movable/set_opacity(new_opacity)
+ . = ..()
+ if(isnull(.) || !isturf(loc))
return
- if(new_opacity == TRUE)
- T.has_opaque_atom = TRUE
- T.reconsider_lights()
+ if(opacity)
+ AddElement(/datum/element/light_blocking)
else
- var/old_has_opaque_atom = T.has_opaque_atom
- T.recalc_atom_opacity()
- if(old_has_opaque_atom != T.has_opaque_atom)
- T.reconsider_lights()
+ RemoveElement(/datum/element/light_blocking)
-/obj/item/equipped()
- . = ..()
- update_light()
-/obj/item/pickup()
+/turf/set_opacity(new_opacity)
. = ..()
- update_light()
+ if(isnull(.))
+ return
+ recalculate_directional_opacity()
-/obj/item/dropped()
- . = ..()
- update_light()
+/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
+ return
+
+
+/turf/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
+ if(!_duration)
+ stack_trace("Lighting FX obj created on a turf without a duration")
+ new /obj/effect/dummy/lighting_obj (src, _range, _power, _color, _duration)
+
+
+/obj/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
+ if(!_duration)
+ stack_trace("Lighting FX obj created on a obj without a duration")
+ new /obj/effect/dummy/lighting_obj (get_turf(src), _range, _power, _color, _duration)
+
+
+/mob/living/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
+ mob_light(_range, _power, _color, _duration)
+
+
+/mob/living/proc/mob_light(_range, _power, _color, _duration)
+ var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new (src, _range, _power, _color, _duration)
+ return mob_light_obj
+
+/// Setter for the light power of this atom.
+/atom/proc/set_light_power(new_power)
+ if(new_power == light_power)
+ return
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+ . = light_power
+ light_power = new_power
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_POWER, .)
+
+/// Setter for the light range of this atom.
+/atom/proc/set_light_range(new_range)
+ if(new_range == light_range)
+ return
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+ . = light_range
+ light_range = new_range
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .)
+
+/// Setter for the light color of this atom.
+/atom/proc/set_light_color(new_color)
+ if(new_color == light_color)
+ return
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+ . = light_color
+ light_color = new_color
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .)
+
+/// Setter for whether or not this atom's light is on.
+/atom/proc/set_light_on(new_value)
+ if(new_value == light_on)
+ return
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+ . = light_on
+ light_on = new_value
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .)
+
+/// Setter for the light flags of this atom.
+/atom/proc/set_light_flags(new_value)
+ if(new_value == light_flags)
+ return
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+ . = light_flags
+ light_flags = new_value
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .)
+
+///Keeps track of the sources of dynamic luminosity and updates our visibility with the highest.
+/atom/movable/proc/update_dynamic_luminosity()
+ var/highest = 0
+ for(var/i in affected_dynamic_lights)
+ if(affected_dynamic_lights[i] <= highest)
+ continue
+ highest = affected_dynamic_lights[i]
+ if(highest == affecting_dynamic_lumi)
+ return
+ luminosity -= affecting_dynamic_lumi
+ affecting_dynamic_lumi = highest
+ luminosity += affecting_dynamic_lumi
+
+
+///Helper to change several lighting overlay settings.
+/atom/movable/proc/set_light_range_power_color(range, power, color)
+ set_light_range(range)
+ set_light_power(power)
+ set_light_color(color)
diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm
index 30230a69e04..e02e04b0f7c 100644
--- a/code/modules/lighting/lighting_corner.dm
+++ b/code/modules/lighting/lighting_corner.dm
@@ -1,41 +1,37 @@
-/var/total_lighting_corners = 0
-/var/datum/lighting_corner/dummy/dummy_lighting_corner = new
-// Because we can control each corner of every lighting overlay.
+// Because we can control each corner of every lighting object.
// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't).
// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting.
-// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list.
-/var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)
-
/datum/lighting_corner
- var/list/turf/masters = list()
- var/list/datum/light_source/affecting = list() // Light sources affecting us.
- var/active = FALSE // TRUE if one of our masters has dynamic lighting.
+ var/list/datum/light_source/affecting // Light sources affecting us.
- var/x = 0
- var/y = 0
- var/z = 0
+ var/x = 0
+ var/y = 0
+ var/turf/master_NE
+ var/turf/master_SE
+ var/turf/master_SW
+ var/turf/master_NW
+
+ //"raw" color values, changed by update_lumcount()
var/lum_r = 0
var/lum_g = 0
var/lum_b = 0
+ //true color values, guaranteed to be between 0 and 1
+ var/cache_r = LIGHTING_SOFT_THRESHOLD
+ var/cache_g = LIGHTING_SOFT_THRESHOLD
+ var/cache_b = LIGHTING_SOFT_THRESHOLD
+
+ ///the maximum of lum_r, lum_g, and lum_b. if this is > 1 then the three cached color values are divided by this
+ var/largest_color_luminosity = 0
+
+ ///whether we are to be added to SSlighting's corners_queue list for an update
var/needs_update = FALSE
- var/cache_r = LIGHTING_SOFT_THRESHOLD
- var/cache_g = LIGHTING_SOFT_THRESHOLD
- var/cache_b = LIGHTING_SOFT_THRESHOLD
- var/cache_mx = 0
-
- var/update_gen = 0
-
-/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
+/datum/lighting_corner/New(turf/new_turf, diagonal)
. = ..()
-
- total_lighting_corners++
-
- masters[new_turf] = turn(diagonal, 180)
- z = new_turf.z
+ save_master(new_turf, turn(diagonal, 180))
var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction.
var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one.
@@ -46,69 +42,75 @@
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
// Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered.
// So we'll have this hardcode instead.
- var/turf/T
- var/i
+ var/turf/new_master_turf
// Diagonal one is easy.
- T = get_step(new_turf, diagonal)
- if (T) // In case we're on the map's border.
- if (!T.corners)
- T.corners = list(null, null, null, null)
-
- masters[T] = diagonal
- i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180))
- T.corners[i] = src
+ new_master_turf = get_step(new_turf, diagonal)
+ if (new_master_turf) // In case we're on the map's border.
+ save_master(new_master_turf, diagonal)
// Now the horizontal one.
- T = get_step(new_turf, horizontal)
- if (T) // Ditto.
- if (!T.corners)
- T.corners = list(null, null, null, null)
-
- masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
- i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
- T.corners[i] = src
+ new_master_turf = get_step(new_turf, horizontal)
+ if (new_master_turf) // Ditto.
+ save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
// And finally the vertical one.
- T = get_step(new_turf, vertical)
- if (T)
- if (!T.corners)
- T.corners = list(null, null, null, null)
+ new_master_turf = get_step(new_turf, vertical)
+ if (new_master_turf)
+ save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
- masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
- i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
- T.corners[i] = src
+/datum/lighting_corner/proc/save_master(turf/master, dir)
+ switch (dir)
+ if (NORTHEAST)
+ master_NE = master
+ master.lighting_corner_SW = src
+ if (SOUTHEAST)
+ master_SE = master
+ master.lighting_corner_NW = src
+ if (SOUTHWEST)
+ master_SW = master
+ master.lighting_corner_NE = src
+ if (NORTHWEST)
+ master_NW = master
+ master.lighting_corner_SE = src
- update_active()
+/datum/lighting_corner/proc/self_destruct_if_idle()
+ if (!LAZYLEN(affecting))
+ qdel(src, force = TRUE)
-/datum/lighting_corner/proc/update_active()
- active = FALSE
- for (var/turf/T in masters)
- if (T.lighting_overlay)
- active = TRUE
+/datum/lighting_corner/proc/vis_update()
+ for (var/datum/light_source/light_source as anything in affecting)
+ light_source.vis_update()
+
+/datum/lighting_corner/proc/full_update()
+ for (var/datum/light_source/light_source as anything in affecting)
+ light_source.recalc_corner(src)
// God that was a mess, now to do the rest of the corner code! Hooray!
-/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b)
+/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b)
+ if (!(delta_r || delta_g || delta_b)) // 0 is falsey ok
+ return
+
lum_r += delta_r
lum_g += delta_g
lum_b += delta_b
if (!needs_update)
needs_update = TRUE
- lighting_update_corners += src
+ SSlighting.corners_queue += src
-/datum/lighting_corner/proc/update_overlays()
- // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually.
- var/lum_r = src.lum_r > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_r) : src.lum_r
- var/lum_g = src.lum_g > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_g) : src.lum_g
- var/lum_b = src.lum_b > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_b) : src.lum_b
- var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1.
+/datum/lighting_corner/proc/update_objects()
+ // Cache these values ahead of time so 4 individual lighting objects don't all calculate them individually.
+ var/lum_r = src.lum_r
+ var/lum_g = src.lum_g
+ var/lum_b = src.lum_b
+ var/largest_color_luminosity = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1.
. = 1 // factor
- if (mx > 1)
- . = 1 / mx
+ if (largest_color_luminosity > 1)
+ . = 1 / largest_color_luminosity
#if LIGHTING_SOFT_THRESHOLD != 0
- else if (mx < LIGHTING_SOFT_THRESHOLD)
+ else if (largest_color_luminosity < LIGHTING_SOFT_THRESHOLD)
. = 0 // 0 means soft lighting.
cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
@@ -119,21 +121,56 @@
cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE)
cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE)
#endif
- cache_mx = round(mx, LIGHTING_ROUND_VALUE)
- for (var/TT in masters)
- var/turf/T = TT
- if (T.lighting_overlay)
- if (!T.lighting_overlay.needs_update)
- T.lighting_overlay.needs_update = TRUE
- lighting_update_overlays += T.lighting_overlay
+ src.largest_color_luminosity = round(largest_color_luminosity, LIGHTING_ROUND_VALUE)
+
+ var/datum/lighting_object/lighting_object = master_NE?.lighting_object
+ if (lighting_object && !lighting_object.needs_update)
+ lighting_object.needs_update = TRUE
+ SSlighting.objects_queue += lighting_object
+
+ lighting_object = master_SE?.lighting_object
+ if (lighting_object && !lighting_object.needs_update)
+ lighting_object.needs_update = TRUE
+ SSlighting.objects_queue += lighting_object
+
+ lighting_object = master_SW?.lighting_object
+ if (lighting_object && !lighting_object.needs_update)
+ lighting_object.needs_update = TRUE
+ SSlighting.objects_queue += lighting_object
+
+ lighting_object = master_NW?.lighting_object
+ if (lighting_object && !lighting_object.needs_update)
+ lighting_object.needs_update = TRUE
+ SSlighting.objects_queue += lighting_object
+
+ self_destruct_if_idle()
/datum/lighting_corner/dummy/New()
return
-/datum/lighting_corner/Destroy(var/force)
+/datum/lighting_corner/Destroy(force)
if (!force)
return QDEL_HINT_LETMELIVE
- crash_with("Who decided to force qdel() a lighting corner? Why did you do this?")
+
+ for (var/datum/light_source/light_source as anything in affecting)
+ LAZYREMOVE(light_source.effect_str, src)
+ affecting = null
+
+ if (master_NE)
+ master_NE.lighting_corner_SW = null
+ master_NE.lighting_corners_initialised = FALSE
+ if (master_SE)
+ master_SE.lighting_corner_NW = null
+ master_SE.lighting_corners_initialised = FALSE
+ if (master_SW)
+ master_SW.lighting_corner_NE = null
+ master_SW.lighting_corners_initialised = FALSE
+ if (master_NW)
+ master_NW.lighting_corner_SE = null
+ master_NW.lighting_corners_initialised = FALSE
+ if(needs_update)
+ SSlighting.corners_queue -= src
+
return ..()
diff --git a/code/modules/lighting/lighting_fake_sun_vr.dm b/code/modules/lighting/lighting_fake_sun_vr.dm
index 898532d8c22..15b743578e7 100644
--- a/code/modules/lighting/lighting_fake_sun_vr.dm
+++ b/code/modules/lighting/lighting_fake_sun_vr.dm
@@ -3,6 +3,7 @@
desc = "Deletes itself, but first updates all the lighting on outdoor turfs."
icon = 'icons/effects/effects_vr.dmi'
icon_state = "fakesun"
+ var/datum/light_source/sun/fake_sun
var/list/possible_light_setups = list(
list(
@@ -17,6 +18,22 @@
"brightness" = 2.5,
"color" = "#EE9AC6"
),
+ list(
+ "brightness" = 1.5,
+ "color" = "#F07AD8"
+ ),
+ list(
+ "brightness" = 1.5,
+ "color" = "#61AEF3"
+ ),
+ list(
+ "brightness" = 1,
+ "color" = "#f3932d"
+ ),
+ list(
+ "brightness" = 1,
+ "color" = "#631E8A"
+ ),
list(
"brightness" = 1.0,
"color" = "#A3A291"
@@ -66,28 +83,97 @@
/obj/effect/fake_sun/LateInitialize()
. = ..()
+ var/list/choice = pick(possible_light_setups)
+ if(choice["brightness"] <= LIGHTING_SOFT_THRESHOLD) // dark!
+ return
- var/list/our_choice = pick(possible_light_setups)
+ fake_sun = new
+ fake_sun.light_color = choice["color"]
+ fake_sun.light_power = choice["brightness"]
+
+ var/list/zees = GetConnectedZlevels()
+ var/min = z
+ var/max = z
+ for(var/zee in zees)
+ if(zee < min)
+ min = z
+ if(zee > max)
+ max = z
+
+ var/list/all_turfs = block(locate(1, 1, min), locate(world.maxx, world.maxy, max))
+ var/list/turfs_to_use = list()
+ for(var/turf/T as anything in all_turfs)
+ if(T.outdoors)
+ turfs_to_use += T
- // Calculate new values to apply
- var/new_brightness = our_choice["brightness"]
- var/new_color = our_choice["color"]
- var/lum_r = new_brightness * GetRedPart (new_color) / 255
- var/lum_g = new_brightness * GetGreenPart(new_color) / 255
- var/lum_b = new_brightness * GetBluePart (new_color) / 255
- var/static/update_gen = -1 // Used to prevent double-processing corners. Otherwise would happen when looping over adjacent turfs.
-
- var/list/turfs = block(locate(1,1,z),locate(world.maxx,world.maxy,z))
-
- for(var/turf/simulated/T as anything in turfs)
- if(!T.lighting_overlay)
- T.lighting_build_overlay()
- if(!T.outdoors)
- continue
- for(var/C in T.get_corners())
- var/datum/lighting_corner/LC = C
- if(LC.update_gen != update_gen && LC.active)
- LC.update_gen = update_gen
- LC.update_lumcount(lum_r, lum_g, lum_b)
- update_gen--
- qdel(src)
\ No newline at end of file
+ if(!turfs_to_use.len)
+ warning("Fake sun placed on a level where it can't find any outdoor turfs to color at [x],[y],[z].")
+ return
+
+ fake_sun.update_corners(turfs_to_use)
+
+/obj/effect/fake_sun/warm
+ name = "warm fake sun"
+ desc = "Deletes itself, but first updates all the lighting on outdoor turfs to warm colors."
+
+ possible_light_setups = list(
+
+ list(
+ "brightness" = 6.0,
+ "color" = "#E9FFB8"
+ ),
+
+ list(
+ "brightness" = 4.0,
+ "color" = "#F4EA55"
+ ),
+ list(
+ "brightness" = 1.0,
+ "color" = "#F07AD8"
+ ),
+ list(
+ "brightness" = 1.0,
+ "color" = "#b4361f"
+ ),
+
+ list(
+ "brightness" = 0.7,
+ "color" = "#f3932d"
+ ),
+
+ list(
+ "brightness" = 0.1,
+ "color" = "#B92B00"
+ )
+ )
+
+/obj/effect/fake_sun/cool
+ name = "fake sun"
+ desc = "Deletes itself, but first updates all the lighting on outdoor turfs to cool colors."
+ possible_light_setups = list(
+
+ list(
+ "brightness" = 6.0,
+ "color" = "#abfff7"
+ ),
+ list(
+ "brightness" = 4.0,
+ "color" = "#2e30c9"
+ ),
+ list(
+ "brightness" = 1.0,
+ "color" = "#61AEF3"
+ ),
+ list(
+ "brightness" = 1.0,
+ "color" = "#61ddf3"
+ ),
+ list(
+ "brightness" = 0.3,
+ "color" = "#253682"
+ ),
+ list(
+ "brightness" = 0.1,
+ "color" = "#27024B"
+ )
+ )
diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm
index eb5097cf5b2..abf3c39ba6a 100644
--- a/code/modules/lighting/lighting_overlay.dm
+++ b/code/modules/lighting/lighting_overlay.dm
@@ -1,51 +1,51 @@
-/var/total_lighting_overlays = 0
-/atom/movable/lighting_overlay
- name = ""
- mouse_opacity = 0
- simulated = 0
- anchored = 1
- icon = LIGHTING_ICON
- plane = PLANE_LIGHTING
- //invisibility = INVISIBILITY_LIGHTING
- color = LIGHTING_BASE_MATRIX
- icon_state = "light1"
- //auto_init = 0 // doesn't need special init
- blend_mode = BLEND_OVERLAY
-
- var/lum_r = 0
- var/lum_g = 0
- var/lum_b = 0
+/datum/lighting_object
+ ///the underlay we are currently applying to our turf to apply light
+ var/mutable_appearance/current_underlay
+ ///whether we are already in the SSlighting.objects_queue list
var/needs_update = FALSE
-/atom/movable/lighting_overlay/Initialize()
- // doesn't need special init
- initialized = TRUE
- return INITIALIZE_HINT_NORMAL
+ ///the turf that our light is applied to
+ var/turf/affected_turf
-/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE)
- . = ..()
- verbs.Cut()
- total_lighting_overlays++
-
- var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays outside of turfs.
- T.lighting_overlay = src
- T.luminosity = 0
- if(no_update)
+/datum/lighting_object/New(turf/source)
+ if(!SSlighting.subsystem_initialized)
+ stack_trace("lighting_object created before SSlighting up!")
return
- update_overlay()
-
-/atom/movable/lighting_overlay/proc/update_overlay()
- set waitfor = FALSE
- var/turf/T = loc
-
- if(!istype(T))
- if(loc)
- log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!")
- else
- log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!")
+ if(!isturf(source))
qdel(src, force=TRUE)
+ stack_trace("a lighting object was assigned to [source], a non turf! ")
return
+ . = ..()
+
+ current_underlay = mutable_appearance(LIGHTING_ICON, "transparent", source.z, PLANE_LIGHTING, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM)
+
+ affected_turf = source
+ if (affected_turf.lighting_object)
+ qdel(affected_turf.lighting_object, force = TRUE)
+ stack_trace("a lighting object was assigned to a turf that already had a lighting object!")
+
+ affected_turf.lighting_object = src
+ affected_turf.luminosity = 0
+
+ for(var/turf/space/space_tile in RANGE_TURFS(1, affected_turf))
+ space_tile.update_starlight()
+
+ needs_update = TRUE
+ SSlighting.objects_queue += src
+
+/datum/lighting_object/Destroy(force)
+ if (!force)
+ return QDEL_HINT_LETMELIVE
+ SSlighting.objects_queue -= src
+ if (isturf(affected_turf))
+ affected_turf.lighting_object = null
+ affected_turf.luminosity = 1
+ affected_turf.underlays -= current_underlay
+ affected_turf = null
+ return ..()
+
+/datum/lighting_object/proc/update()
// To the future coder who sees this and thinks
// "Why didn't he just use a loop?"
@@ -55,50 +55,54 @@
// Oh it's also shorter line wise.
// Including with these comments.
- // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are.
- // No I seriously cannot think of a more efficient method, fuck off Comic.
+ var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
- var/datum/lighting_corner/cr = LAZYACCESS(T.corners,3) || dummy_lighting_corner
- var/datum/lighting_corner/cg = LAZYACCESS(T.corners,2) || dummy_lighting_corner
- var/datum/lighting_corner/cb = LAZYACCESS(T.corners,4) || dummy_lighting_corner
- var/datum/lighting_corner/ca = LAZYACCESS(T.corners,1) || dummy_lighting_corner
+ var/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner
+ var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner
+ var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner
+ var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner
- var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
+ var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity)
- var/rr = cr.cache_r
- var/rg = cr.cache_g
- var/rb = cr.cache_b
+ var/rr = red_corner.cache_r
+ var/rg = red_corner.cache_g
+ var/rb = red_corner.cache_b
- var/gr = cg.cache_r
- var/gg = cg.cache_g
- var/gb = cg.cache_b
+ var/gr = green_corner.cache_r
+ var/gg = green_corner.cache_g
+ var/gb = green_corner.cache_b
- var/br = cb.cache_r
- var/bg = cb.cache_g
- var/bb = cb.cache_b
+ var/br = blue_corner.cache_r
+ var/bg = blue_corner.cache_g
+ var/bb = blue_corner.cache_b
- var/ar = ca.cache_r
- var/ag = ca.cache_g
- var/ab = ca.cache_b
+ var/ar = alpha_corner.cache_r
+ var/ag = alpha_corner.cache_g
+ var/ab = alpha_corner.cache_b
#if LIGHTING_SOFT_THRESHOLD != 0
var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD
#else
- // Because of floating points, it won't even be a flat 0.
+ // Because of floating points™?, it won't even be a flat 0.
// This number is mostly arbitrary.
var/set_luminosity = max > 1e-6
#endif
if((rr & gr & br & ar) && (rg + gg + bg + ag + rb + gb + bb + ab == 8))
- //anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
- icon_state = "transparent"
- color = null
+ //anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
+ affected_turf.underlays -= current_underlay
+ current_underlay.icon_state = "transparent"
+ current_underlay.color = null
+ affected_turf.underlays += current_underlay
else if(!set_luminosity)
- icon_state = LIGHTING_ICON_STATE_DARK
- color = null
+ affected_turf.underlays -= current_underlay
+ current_underlay.icon_state = "dark"
+ current_underlay.color = null
+ affected_turf.underlays += current_underlay
else
- icon_state = null
- color = list(
+ affected_turf.underlays -= current_underlay
+ current_underlay.icon_state = "gradient"
+ current_underlay.color = list(
rr, rg, rb, 00,
gr, gg, gb, 00,
br, bg, bb, 00,
@@ -106,38 +110,12 @@
00, 00, 00, 01
)
- luminosity = set_luminosity
+ affected_turf.underlays += current_underlay
-// Variety of overrides so the overlays don't get affected by weird things.
-/atom/movable/lighting_overlay/ex_act()
- return
+ affected_turf.luminosity = set_luminosity
-/atom/movable/lighting_overlay/singularity_act()
- return
+/datum/lighting_object/proc/removefromturf()
+ affected_turf.underlays -= current_underlay
-/atom/movable/lighting_overlay/singularity_pull()
- return
-
-/atom/movable/lighting_overlay/forceMove()
- return 0 //should never move
-
-/atom/movable/lighting_overlay/Move()
- return 0
-
-/atom/movable/lighting_overlay/throw_at()
- return 0
-
-/atom/movable/lighting_overlay/Destroy(var/force)
- if (force)
- total_lighting_overlays--
- global.lighting_update_overlays -= src
- LAZYREMOVE(SSlighting.currentrun, src)
-
- var/turf/T = loc
- if(istype(T))
- T.lighting_overlay = null
- T.luminosity = 1
-
- return ..()
- else
- return QDEL_HINT_LETMELIVE
+/datum/lighting_object/proc/addtoturf()
+ affected_turf.underlays += current_underlay
diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm
index ad014b013d3..b6473f36ddf 100644
--- a/code/modules/lighting/lighting_setup.dm
+++ b/code/modules/lighting/lighting_setup.dm
@@ -1,24 +1,6 @@
// Create lighting overlays on all turfs with dynamic lighting in areas with dynamic lighting.
-/proc/create_all_lighting_overlays()
- for(var/area/A in world)
- if(!A.dynamic_lighting)
- continue
- for(var/turf/T in A)
- if(!T.dynamic_lighting)
- continue
- new /atom/movable/lighting_overlay(T, TRUE)
- CHECK_TICK
+/proc/create_all_lighting_objects()
+ var/list/all_turfs = block(locate(1,1,1), locate(world.maxx, world.maxy, world.maxz))
+ for(var/turf/T as anything in all_turfs)
+ T.lighting_build_overlay()
CHECK_TICK
-
-/proc/create_lighting_overlays_zlevel(var/zlevel)
- ASSERT(zlevel)
-
- for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
- if(!T.dynamic_lighting)
- continue
-
- var/area/A = T.loc
- if(!A.dynamic_lighting)
- continue
-
- new /atom/movable/lighting_overlay(T, TRUE)
\ No newline at end of file
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index 451b8273c84..4f863bf34ae 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -1,15 +1,22 @@
-/var/total_lighting_sources = 0
// This is where the fun begins.
// These are the main datums that emit light.
/datum/light_source
- var/atom/top_atom // The atom we're emitting light from(for example a mob if we're from a flashlight that's being held).
- var/atom/source_atom // The atom that we belong to.
+ ///The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
+ var/atom/top_atom
+ ///The atom that we belong to.
+ var/atom/source_atom
- var/turf/source_turf // The turf under the above.
- var/light_power // Intensity of the emitter light.
- var/light_range // The range of the emitted light.
- var/light_color // The colour of the light, string, decomposed by parse_light_color()
+ ///The turf under the source atom.
+ var/turf/source_turf
+ ///The turf the top_atom appears to over.
+ var/turf/pixel_turf
+ ///Intensity of the emitter light.
+ var/light_power
+ /// The range of the emitted light.
+ var/light_range
+ /// The colour of the light, string, decomposed by parse_light_color()
+ var/light_color
// Variables for keeping track of the colour.
var/lum_r
@@ -21,142 +28,83 @@
var/tmp/applied_lum_g
var/tmp/applied_lum_b
- var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners.
- var/list/turf/affecting_turfs
+ /// List used to store how much we're affecting corners.
+ var/list/datum/lighting_corner/effect_str
- var/applied = FALSE // Whether we have applied our light yet or not.
+ /// Whether we have applied our light yet or not.
+ var/applied = FALSE
- var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became(in)visible to us.
- var/needs_update // Whether we are queued for an update.
- var/destroyed // Whether we are destroyed and need to stop emitting light.
- var/force_update
+ /// whether we are to be added to SSlighting's sources_queue list for an update
+ var/needs_update = LIGHTING_NO_UPDATE
-/datum/light_source/New(var/atom/owner, var/atom/top)
- total_lighting_sources++
+
+/datum/light_source/New(atom/owner, atom/top)
source_atom = owner // Set our new owner.
- if(!source_atom.light_sources)
- source_atom.light_sources = list()
-
- source_atom.light_sources += src // Add us to the lights of our owner.
+ LAZYADD(source_atom.light_sources, src)
top_atom = top
- if(top_atom != source_atom)
- if(!top.light_sources)
- top.light_sources = list()
-
- top_atom.light_sources += src
+ if (top_atom != source_atom)
+ LAZYADD(top_atom.light_sources, src)
source_turf = top_atom
+ pixel_turf = get_turf_pixel(top_atom) || source_turf
+
light_power = source_atom.light_power
light_range = source_atom.light_range
light_color = source_atom.light_color
- parse_light_color()
-
- effect_str = list()
- affecting_turfs = list()
+ PARSE_LIGHT_COLOR(src)
update()
+/datum/light_source/Destroy(force)
+ remove_lum()
+ if (source_atom)
+ LAZYREMOVE(source_atom.light_sources, src)
+
+ if (top_atom)
+ LAZYREMOVE(top_atom.light_sources, src)
+
+ if (needs_update)
+ SSlighting.sources_queue -= src
+
+ top_atom = null
+ source_atom = null
+ source_turf = null
+ pixel_turf = null
return ..()
-// Kill ourselves.
-/datum/light_source/proc/destroy()
- total_lighting_sources--
- destroyed = TRUE
- force_update()
- if(source_atom)
- if(!source_atom.light_sources)
- log_runtime(EXCEPTION("Atom [source_atom] was a light source, but lacked a light source list!\n"), source_atom)
- else
- source_atom.light_sources -= src
+// Yes this doesn't align correctly on anything other than 4 width tabs.
+// If you want it to go switch everybody to elastic tab stops.
+// Actually that'd be great if you could!
+#define EFFECT_UPDATE(level) \
+ if (needs_update == LIGHTING_NO_UPDATE) \
+ SSlighting.sources_queue += src; \
+ if (needs_update < level) \
+ needs_update = level; \
- if(top_atom)
- top_atom.light_sources -= src
-
-// Call it dirty, I don't care.
-// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates.
-// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a() macro that has no arguments :|.
-#define effect_update(BYOND) \
- if(!needs_update) \
- { \
- lighting_update_lights += src; \
- needs_update = TRUE; \
- }
// This proc will cause the light source to update the top atom, and add itself to the update queue.
-/datum/light_source/proc/update(var/atom/new_top_atom)
+/datum/light_source/proc/update(atom/new_top_atom)
// This top atom is different.
- if(new_top_atom && new_top_atom != top_atom)
- if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom.
- top_atom.light_sources -= src
+ if (new_top_atom && new_top_atom != top_atom)
+ if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom.
+ LAZYREMOVE(top_atom.light_sources, src)
top_atom = new_top_atom
- if(top_atom != source_atom)
- if(!top_atom.light_sources)
- top_atom.light_sources = list()
+ if (top_atom != source_atom)
+ LAZYADD(top_atom.light_sources, src) // Add ourselves to the light sources of our new top atom.
- top_atom.light_sources += src // Add ourselves to the light sources of our new top atom.
-
- effect_update(null)
+ EFFECT_UPDATE(LIGHTING_CHECK_UPDATE)
// Will force an update without checking if it's actually needed.
/datum/light_source/proc/force_update()
- force_update = 1
-
- effect_update(null)
+ EFFECT_UPDATE(LIGHTING_FORCE_UPDATE)
// Will cause the light source to recalculate turfs that were removed or added to visibility only.
/datum/light_source/proc/vis_update()
- vis_update = 1
-
- effect_update(null)
-
-// Will check if we actually need to update, and update any variables that may need to be updated.
-/datum/light_source/proc/check()
- if(!source_atom || !light_range || !light_power)
- destroy()
- return 1
-
- if(!top_atom)
- top_atom = source_atom
- . = 1
-
- if(isturf(top_atom))
- if(source_turf != top_atom)
- source_turf = top_atom
- . = 1
- else if(top_atom.loc != source_turf)
- source_turf = top_atom.loc
- . = 1
-
- if(source_atom.light_power != light_power)
- light_power = source_atom.light_power
- . = 1
-
- if(source_atom.light_range != light_range)
- light_range = source_atom.light_range
- . = 1
-
- if(light_range && light_power && !applied)
- . = 1
-
- if(source_atom.light_color != light_color)
- light_color = source_atom.light_color
- parse_light_color()
- . = 1
-
-// Decompile the hexadecimal colour into lumcounts of each perspective.
-/datum/light_source/proc/parse_light_color()
- if(light_color)
- lum_r = GetRedPart (light_color) / 255
- lum_g = GetGreenPart(light_color) / 255
- lum_b = GetBluePart (light_color) / 255
- else
- lum_r = 1
- lum_g = 1
- lum_b = 1
+ EFFECT_UPDATE(LIGHTING_VIS_UPDATE)
// Macro that applies light to a new corner.
// It is a macro in the interest of speed, yet not having to copy paste it.
@@ -164,127 +112,264 @@
// As such this all gets counted as a single line.
// The braces and semicolons are there to be able to do this on a single line.
-#define APPLY_CORNER(C) \
- . = LUM_FALLOFF(C, source_turf); \
- \
- . *= light_power; \
- \
- effect_str[C] = .; \
- \
- C.update_lumcount \
- ( \
- . * applied_lum_r, \
- . * applied_lum_g, \
- . * applied_lum_b \
+// /tg/ falloff alg
+#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range)))
+
+// Bay/Polaris falloff alg
+//#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range)))
+
+#define APPLY_CORNER(C) \
+ . = LUM_FALLOFF(C, pixel_turf); \
+ . *= light_power; \
+ var/OLD = effect_str[C]; \
+ \
+ C.update_lumcount \
+ ( \
+ (. * lum_r) - (OLD * applied_lum_r), \
+ (. * lum_g) - (OLD * applied_lum_g), \
+ (. * lum_b) - (OLD * applied_lum_b) \
+ ); \
+
+#define REMOVE_CORNER(C) \
+ . = -effect_str[C]; \
+ C.update_lumcount \
+ ( \
+ . * applied_lum_r, \
+ . * applied_lum_g, \
+ . * applied_lum_b \
);
-// I don't need to explain what this does, do I?
-#define REMOVE_CORNER(C) \
- . = -effect_str[C]; \
- C.update_lumcount \
- ( \
- . * applied_lum_r, \
- . * applied_lum_g, \
- . * applied_lum_b \
- );
+#define APPLY_CORNER_SIMPLE(C) \
+ . = light_power; \
+ var/OLD = effect_str[C]; \
+ \
+ C.update_lumcount \
+ ( \
+ (. * lum_r) - (OLD * applied_lum_r), \
+ (. * lum_g) - (OLD * applied_lum_g), \
+ (. * lum_b) - (OLD * applied_lum_b) \
+ ); \
-// This is the define used to calculate falloff.
-#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range)))
-/datum/light_source/proc/apply_lum()
- var/static/update_gen = 1
- applied = 1
+/datum/light_source/proc/remove_lum()
+ applied = FALSE
+ for (var/datum/lighting_corner/corner as anything in effect_str)
+ REMOVE_CORNER(corner)
+ LAZYREMOVE(corner.affecting, src)
+
+ effect_str = null
+
+/datum/light_source/proc/recalc_corner(datum/lighting_corner/corner)
+ LAZYINITLIST(effect_str)
+ if (effect_str[corner]) // Already have one.
+ REMOVE_CORNER(corner)
+ effect_str[corner] = 0
+
+ APPLY_CORNER(corner)
+ effect_str[corner] = .
+
+/datum/light_source/proc/get_turfs_in_range()
+ return view(CEILING(light_range, 1), source_turf)
+
+/datum/light_source/proc/update_corners()
+ var/update = FALSE
+ var/atom/source_atom = src.source_atom
+
+ if (QDELETED(source_atom))
+ qdel(src)
+ return
+
+ if (source_atom.light_power != light_power)
+ light_power = source_atom.light_power
+ update = TRUE
+
+ if (source_atom.light_range != light_range)
+ light_range = source_atom.light_range
+ update = TRUE
+
+ if (!top_atom)
+ top_atom = source_atom
+ update = TRUE
+
+ if (!light_range || !light_power)
+ qdel(src)
+ return
+
+ if (isturf(top_atom))
+ if (source_turf != top_atom)
+ source_turf = top_atom
+ pixel_turf = source_turf
+ update = TRUE
+ else if (top_atom.loc != source_turf)
+ source_turf = top_atom.loc
+ pixel_turf = get_turf_pixel(top_atom)
+ update = TRUE
+ else
+ var/pixel_loc = get_turf_pixel(top_atom)
+ if (pixel_loc != pixel_turf)
+ pixel_turf = pixel_loc
+ update = TRUE
+
+ if (!isturf(source_turf))
+ if (applied)
+ remove_lum()
+ return
+
+ if (light_range && light_power && !applied)
+ update = TRUE
+
+ if (source_atom.light_color != light_color)
+ light_color = source_atom.light_color
+ PARSE_LIGHT_COLOR(src)
+ update = TRUE
+
+ else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
+ update = TRUE
+
+ if (update)
+ needs_update = LIGHTING_CHECK_UPDATE
+ applied = TRUE
+ else if (needs_update == LIGHTING_CHECK_UPDATE)
+ return //nothing's changed
+
+ var/list/datum/lighting_corner/corners = list()
+ var/list/turf/turfs = list()
+
+ if (source_turf)
+ var/oldlum = source_turf.luminosity
+ source_turf.luminosity = CEILING(light_range, 1)
+ for(var/turf/T in get_turfs_in_range())
+ if(!IS_OPAQUE_TURF(T))
+ if (!T.lighting_corners_initialised)
+ T.generate_missing_corners()
+ corners[T.lighting_corner_NE] = 0
+ corners[T.lighting_corner_SE] = 0
+ corners[T.lighting_corner_SW] = 0
+ corners[T.lighting_corner_NW] = 0
+ turfs += T
+ source_turf.luminosity = oldlum
+
+ var/list/datum/lighting_corner/new_corners = (corners - effect_str)
+ LAZYINITLIST(effect_str)
+ if (needs_update == LIGHTING_VIS_UPDATE)
+ for (var/datum/lighting_corner/corner as anything in new_corners)
+ APPLY_CORNER(corner)
+ if (. != 0)
+ LAZYADD(corner.affecting, src)
+ effect_str[corner] = .
+ else
+ for (var/datum/lighting_corner/corner as anything in new_corners)
+ APPLY_CORNER(corner)
+ if (. != 0)
+ LAZYADD(corner.affecting, src)
+ effect_str[corner] = .
+
+ for (var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners
+ APPLY_CORNER(corner)
+ if (. != 0)
+ effect_str[corner] = .
+ else
+ LAZYREMOVE(corner.affecting, src)
+ effect_str -= corner
+
+ var/list/datum/lighting_corner/gone_corners = effect_str - corners
+ for (var/datum/lighting_corner/corner as anything in gone_corners)
+ REMOVE_CORNER(corner)
+ LAZYREMOVE(corner.affecting, src)
+ effect_str -= gone_corners
- // Keep track of the last applied lum values so that the lighting can be reversed
applied_lum_r = lum_r
applied_lum_g = lum_g
applied_lum_b = lum_b
- FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
+ UNSETEMPTY(effect_str)
- for(var/datum/lighting_corner/C in T.get_corners())
- if(C.update_gen == update_gen)
- continue
+// For planets and fake suns
+/datum/light_source/sun
+ light_range = 1
+ light_color = "#FFFFFF"
+ light_power = 2
+ var/applied_power = 2
- C.update_gen = update_gen
- C.affecting += src
+/datum/light_source/sun/New()
+ return
- if(!C.active)
- effect_str[C] = 0
- continue
+/datum/light_source/sun/force_update()
+ return
- APPLY_CORNER(C)
+/datum/light_source/sun/vis_update()
+ return
- if(!T.affecting_lights)
- T.affecting_lights = list()
+/datum/light_source/sun/update_corners(var/list/turfs_to_update)
+ if(!LAZYLEN(turfs_to_update))
+ stack_trace("Planet sun tried to update with no turfs given")
+ return
- T.affecting_lights += src
- affecting_turfs += T
+ // Update lum_r/g/b from our light_color
+ PARSE_LIGHT_COLOR(src)
+
+ // Noop update
+ if(lum_r == applied_lum_r && lum_g == applied_lum_g && lum_b == applied_lum_b && light_power == applied_power)
+ return
+
+ // No reason to unapply on the first run or if previous run was 0 power
+ if(applied)
+ remove_lum()
- update_gen++
+ // Entirely dark, just stop now that we've remove_lum()'d
+ if(!light_power)
+ applied = FALSE
+ return
-/datum/light_source/proc/remove_lum()
- applied = FALSE
+ LAZYINITLIST(effect_str)
- for(var/turf/T in affecting_turfs)
- if(!T.affecting_lights)
- T.affecting_lights = list()
- else
- T.affecting_lights -= src
-
- affecting_turfs.Cut()
-
- for(var/datum/lighting_corner/C in effect_str)
- REMOVE_CORNER(C)
-
- C.affecting -= src
-
- effect_str.Cut()
-
-/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C)
- if(effect_str.Find(C)) // Already have one.
- REMOVE_CORNER(C)
-
- APPLY_CORNER(C)
-
-/datum/light_source/proc/smart_vis_update()
var/list/datum/lighting_corner/corners = list()
- var/list/turf/turfs = list()
- FOR_DVIEW(var/turf/T, light_range, source_turf, 0)
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
- corners |= T.get_corners()
- turfs += T
+ for(var/turf/T as anything in turfs_to_update)
+ if(!IS_OPAQUE_TURF(T))
+ if(!T.lighting_corners_initialised)
+ T.generate_missing_corners()
+
+ var/datum/lighting_corner/LC = T.lighting_corner_NE
+ if(!corners[LC])
+ corners[LC] = 1
+ APPLY_CORNER_SIMPLE(LC)
+ LAZYADD(LC.affecting, src)
+ effect_str[LC] = .
+
+ LC = T.lighting_corner_SE
+ if(!corners[LC])
+ corners[LC] = 1
+ APPLY_CORNER_SIMPLE(LC)
+ LAZYADD(LC.affecting, src)
+ effect_str[LC] = .
+
+ LC = T.lighting_corner_NW
+ if(!corners[LC])
+ corners[LC] = 1
+ APPLY_CORNER_SIMPLE(LC)
+ LAZYADD(LC.affecting, src)
+ effect_str[LC] = .
+
+ LC = T.lighting_corner_SW
+ if(!corners[LC])
+ corners[LC] = 1
+ APPLY_CORNER_SIMPLE(LC)
+ LAZYADD(LC.affecting, src)
+ effect_str[LC] = .
- var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them.
- affecting_turfs += L
- for(var/turf/T in L)
- if(!T.affecting_lights)
- T.affecting_lights = list(src)
- else
- T.affecting_lights += src
+ CHECK_TICK
- L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights.
- affecting_turfs -= L
- for(var/turf/T in L)
- T.affecting_lights -= src
+ applied_lum_r = lum_r
+ applied_lum_g = lum_g
+ applied_lum_b = lum_b
+ applied_power = light_power
+ applied = TRUE // remove_lum() now necessary in the future
- for(var/datum/lighting_corner/C in corners - effect_str) // New corners
- C.affecting += src
- if(!C.active)
- effect_str[C] = 0
- continue
+ UNSETEMPTY(effect_str)
- APPLY_CORNER(C)
-
- for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners.
- REMOVE_CORNER(C)
- C.affecting -= src
- effect_str -= C
-
-#undef effect_update
+#undef EFFECT_UPDATE
#undef LUM_FALLOFF
#undef REMOVE_CORNER
#undef APPLY_CORNER
+#undef REMOVE_CORNER_SIMPLE
+#undef APPLY_CORNER_SIMPLE
\ No newline at end of file
diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm
index b8a29fc43a1..59732b5d60e 100644
--- a/code/modules/lighting/lighting_turf.dm
+++ b/code/modules/lighting/lighting_turf.dm
@@ -1,96 +1,142 @@
/turf
- var/dynamic_lighting = TRUE // Does the turf use dynamic lighting?
- luminosity = 1
+ ///Lumcount added by sources other than lighting datum objects, such as the overlay lighting component.
+ var/dynamic_lumcount = 0
+
+ var/dynamic_lighting = TRUE
var/tmp/lighting_corners_initialised = FALSE
- var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
- var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay.
- var/tmp/list/datum/lighting_corner/corners
- var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
+ ///Our lighting object.
+ var/tmp/datum/lighting_object/lighting_object
+ ///Lighting Corner datums.
+ var/tmp/datum/lighting_corner/lighting_corner_NE
+ var/tmp/datum/lighting_corner/lighting_corner_SE
+ var/tmp/datum/lighting_corner/lighting_corner_SW
+ var/tmp/datum/lighting_corner/lighting_corner_NW
+
+ ///Which directions does this turf block the vision of, taking into account both the turf's opacity and the movable opacity_sources.
+ var/directional_opacity = NONE
+ ///Lazylist of movable atoms providing opacity sources.
+ var/list/atom/movable/opacity_sources
// Causes any affecting light sources to be queued for a visibility update, for example a door got opened.
/turf/proc/reconsider_lights()
- for(var/datum/light_source/L in affecting_lights)
- L.vis_update()
+ lighting_corner_NE?.vis_update()
+ lighting_corner_SE?.vis_update()
+ lighting_corner_SW?.vis_update()
+ lighting_corner_NW?.vis_update()
/turf/proc/lighting_clear_overlay()
- if(lighting_overlay)
- qdel(lighting_overlay, force = TRUE)
+ if(lighting_object)
+ qdel(lighting_object, force=TRUE)
- for(var/datum/lighting_corner/C in corners)
- C.update_active()
-
-// Builds a lighting overlay for us, but only if our area is dynamic.
+// Builds a lighting object for us, but only if our area is dynamic.
/turf/proc/lighting_build_overlay()
- if(lighting_overlay)
+ if(!has_dynamic_lighting())
return
- var/area/A = loc
- if(A.dynamic_lighting && dynamic_lighting)
- if(!lighting_corners_initialised)
- generate_missing_corners()
-
- new /atom/movable/lighting_overlay(src)
-
- for(var/datum/lighting_corner/C in corners)
- if(!C.active) // We would activate the corner, calculate the lighting for it.
- for(var/L in C.affecting)
- var/datum/light_source/S = L
- S.recalc_corner(C)
-
- C.active = TRUE
+ lighting_clear_overlay()
+ new/datum/lighting_object(src)
// Used to get a scaled lumcount.
-/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1)
- if(!lighting_overlay)
+/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
+ if (!lighting_object)
return 1
var/totallums = 0
- for(var/datum/lighting_corner/L in corners)
- totallums += max(L.lum_r, L.lum_g, L.lum_b)
+ var/datum/lighting_corner/L
+ L = lighting_corner_NE
+ if (L)
+ totallums += L.lum_r + L.lum_b + L.lum_g
+ L = lighting_corner_SE
+ if (L)
+ totallums += L.lum_r + L.lum_b + L.lum_g
+ L = lighting_corner_SW
+ if (L)
+ totallums += L.lum_r + L.lum_b + L.lum_g
+ L = lighting_corner_NW
+ if (L)
+ totallums += L.lum_r + L.lum_b + L.lum_g
- totallums /= 4 // 4 corners, max channel selected, return the average
- totallums =(totallums - minlum) /(maxlum - minlum)
+ totallums /= 12 // 4 corners, each with 3 channels, get the average.
+
+ totallums = (totallums - minlum) / (maxlum - minlum)
+
+ totallums += dynamic_lumcount
return CLAMP01(totallums)
-// Can't think of a good name, this proc will recalculate the has_opaque_atom variable.
-/turf/proc/recalc_atom_opacity()
- has_opaque_atom = FALSE
- for(var/atom/A in src.contents + src) // Loop through every movable atom on our tile PLUS ourselves (we matter too...)
- if(A.opacity)
- has_opaque_atom = TRUE
+// Returns a boolean whether the turf is on soft lighting.
+// Soft lighting being the threshold at which point the overlay considers
+// itself as too dark to allow sight and see_in_dark becomes useful.
+// So basically if this returns true the tile is unlit black.
+/turf/proc/is_softly_lit()
+ if (!lighting_object)
+ return FALSE
-// If an opaque movable atom moves around we need to potentially update visibility.
-/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc)
- . = ..()
+ return !(luminosity || dynamic_lumcount)
- if(Obj && Obj.opacity)
- has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
- reconsider_lights()
-/turf/Exited(var/atom/movable/Obj, var/atom/newloc)
- . = ..()
+///Proc to add movable sources of opacity on the turf and let it handle lighting code.
+/turf/proc/add_opacity_source(atom/movable/new_source)
+ LAZYADD(opacity_sources, new_source)
+ if(opacity)
+ return
+ recalculate_directional_opacity()
- if(Obj && Obj.opacity)
- recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates.
- reconsider_lights()
-/turf/proc/get_corners()
- if(has_opaque_atom)
- return null // Since this proc gets used in a for loop, null won't be looped though.
+///Proc to remove movable sources of opacity on the turf and let it handle lighting code.
+/turf/proc/remove_opacity_source(atom/movable/old_source)
+ LAZYREMOVE(opacity_sources, old_source)
+ if(opacity) //Still opaque, no need to worry on updating.
+ return
+ recalculate_directional_opacity()
- return corners
+
+///Calculate on which directions this turfs block view.
+/turf/proc/recalculate_directional_opacity()
+ . = directional_opacity
+ if(opacity)
+ directional_opacity = ALL_CARDINALS
+ if(. != directional_opacity)
+ reconsider_lights()
+ return
+ directional_opacity = NONE
+ for(var/atom/movable/opacity_source as anything in opacity_sources)
+ if(opacity_source.flags & ON_BORDER)
+ directional_opacity |= opacity_source.dir
+ else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking.
+ directional_opacity = ALL_CARDINALS
+ break
+ if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS))
+ reconsider_lights() //The lighting system only cares whether the tile is fully concealed from all directions or not.
+
+
+/turf/proc/change_area(area/old_area, area/new_area)
+ if(SSlighting.subsystem_initialized)
+ if (new_area.dynamic_lighting != old_area.dynamic_lighting)
+ if (new_area.dynamic_lighting)
+ lighting_build_overlay()
+ else
+ lighting_clear_overlay()
+
+/turf/proc/has_dynamic_lighting()
+ var/area/A = loc
+ return (IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
/turf/proc/generate_missing_corners()
+
+ if (!lighting_corner_NE)
+ lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST)
+
+ if (!lighting_corner_SE)
+ lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST)
+
+ if (!lighting_corner_SW)
+ lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST)
+
+ if (!lighting_corner_NW)
+ lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST)
+
lighting_corners_initialised = TRUE
- if(!corners)
- corners = list(null, null, null, null)
-
- for(var/i = 1 to 4)
- if(corners[i]) // Already have a corner on this direction.
- continue
-
- corners[i] = new /datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i])
diff --git a/code/modules/lighting/~lighting_undefs.dm b/code/modules/lighting/~lighting_undefs.dm
deleted file mode 100644
index 2f863b73d5b..00000000000
--- a/code/modules/lighting/~lighting_undefs.dm
+++ /dev/null
@@ -1,7 +0,0 @@
-#undef LIGHTING_FALLOFF
-#undef LIGHTING_LAMBERTIAN
-#undef LIGHTING_HEIGHT
-
-#undef LIGHTING_ICON
-
-#undef LIGHTING_BASE_MATRIX
diff --git a/code/modules/maps/tg/map_template_vr.dm b/code/modules/maps/tg/map_template_vr.dm
index 6f12c85ba90..77424f5ec23 100644
--- a/code/modules/maps/tg/map_template_vr.dm
+++ b/code/modules/maps/tg/map_template_vr.dm
@@ -4,7 +4,7 @@
for(var/turf/simulated/T in block(locate(1,1,z), locate(world.maxx, world.maxy, z)))
T.update_air_properties()
//We missed sslighting init!
- if(lighting_overlays_initialised)
+ if(SSlighting.subsystem_initialized)
for(var/Trf in block(locate(1,1,z), locate(world.maxx, world.maxy, z)))
var/turf/T = Trf //faster than implicit istype with typed for loop
T.lighting_build_overlay()
diff --git a/code/modules/maps/tg/reader.dm b/code/modules/maps/tg/reader.dm
index aa0bd51b899..542a0b9582c 100644
--- a/code/modules/maps/tg/reader.dm
+++ b/code/modules/maps/tg/reader.dm
@@ -159,7 +159,6 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
var/model_key = copytext(line, tpos, tpos + key_len)
line_keys[++line_keys.len] = model_key
#ifdef TESTING
- else
++turfsSkipped
#endif
CHECK_TICK
diff --git a/code/modules/materials/sheets/organic/tanning/tanning_rack.dm b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
index 96d70d90967..885b65dd8fe 100644
--- a/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
+++ b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
@@ -27,14 +27,12 @@
. += "\The [drying] is [drying.get_dryness_text()]."
/obj/structure/tanning_rack/update_icon()
- overlays.Cut()
+ cut_overlays()
if(drying)
- var/image/I
if(drying.wetness)
- I = image(icon, "leather_wet")
+ add_overlay("leather_wet")
else
- I = image(icon, "leather_dry")
- add_overlay(I)
+ add_overlay("leather_dry")
/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user)
if(istype(A, /obj/item/stack/wetleather))
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index e74c241ffb1..1d62a20a61a 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -4,7 +4,7 @@
name = "lantern"
icon_state = "lantern"
desc = "A mining lantern."
- brightness_on = 6 // luminosity when on
+ light_range = 6 // luminosity when on
light_color = "FF9933" // A slight yellow/orange color.
/*****************************Pickaxe********************************/
diff --git a/code/modules/mining/mine_outcrops.dm b/code/modules/mining/mine_outcrops.dm
index 5ce5c5bc942..989b172e1e0 100644
--- a/code/modules/mining/mine_outcrops.dm
+++ b/code/modules/mining/mine_outcrops.dm
@@ -14,7 +14,7 @@
/obj/structure/outcrop/Initialize()
. = ..()
if(prob(1))
- overlays += image(icon, "[initial(icon_state)]-egg")
+ add_overlay("[initial(icon_state)]-egg")
/obj/structure/outcrop/diamond
name = "shiny outcrop"
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index fd41dc7e137..6ef8200455e 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -125,7 +125,7 @@ turf/simulated/mineral/floor/light_corner
/turf/simulated/mineral/proc/update_general()
update_icon(1)
- recalc_atom_opacity()
+ recalculate_directional_opacity()
if(ticker && ticker.current_state == GAME_STATE_PLAYING)
reconsider_lights()
if(air_master)
diff --git a/code/modules/mining/shelter_atoms_vr.dm b/code/modules/mining/shelter_atoms_vr.dm
index 09bd7911c85..66e237147da 100644
--- a/code/modules/mining/shelter_atoms_vr.dm
+++ b/code/modules/mining/shelter_atoms_vr.dm
@@ -266,6 +266,7 @@ GLOBAL_LIST_EMPTY(unique_deployable)
light_range = 5
light_power = 1.2
light_color = "#DDFFD3"
+ light_on = TRUE
pixel_y = -4
max_n_of_items = 100
@@ -330,6 +331,7 @@ GLOBAL_LIST_EMPTY(unique_deployable)
light_range = 3
light_power = 1
light_color = "#FFFFFF"
+ light_on = TRUE
/obj/structure/fans/hardlight/ex_act()
return
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index c4484d40072..f574f8cee5e 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -905,7 +905,7 @@ mob/observer/dead/MayRespawn(var/feedback = 0)
if(choice)
icon = 'icons/mob/ghost.dmi'
- overlays.Cut()
+ cut_overlays()
if(icon_state && icon)
previous_state = icon_state
@@ -936,9 +936,9 @@ mob/observer/dead/MayRespawn(var/feedback = 0)
if(PP.pai == null)
count++
PP.icon = 'icons/obj/pda_vr.dmi' // VOREStation Edit
- PP.overlays += "pai-ghostalert"
+ PP.add_overlay("pai-ghostalert")
spawn(54)
- PP.overlays.Cut()
+ PP.cut_overlays()
to_chat(usr,"Flashing the displays of [count] unoccupied PAIs.")
else
to_chat(usr,"You have 'Be pAI' disabled in your character prefs, so we can't help you.")
diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm
index 22e57ff15ed..44ce0dc0f16 100644
--- a/code/modules/mob/holder.dm
+++ b/code/modules/mob/holder.dm
@@ -87,14 +87,14 @@ var/list/holder_mob_icon_cache = list()
/obj/item/weapon/holder/proc/sync(var/mob/living/M)
dir = 2
- overlays.Cut()
+ overlays.Cut() // Not using SSoverlays for this due to performance
icon = M.icon
icon_state = M.icon_state
item_state = M.item_state
color = M.color
name = M.name
desc = M.desc
- overlays |= M.overlays
+ overlays |= M.overlays // Not using SSoverlays for this due to performance
var/mob/living/carbon/human/H = loc
if(istype(H))
if(H.l_hand == src)
diff --git a/code/modules/mob/living/bot/medbot.dm b/code/modules/mob/living/bot/medbot.dm
index 6592c37e0c2..42f3bff06ce 100644
--- a/code/modules/mob/living/bot/medbot.dm
+++ b/code/modules/mob/living/bot/medbot.dm
@@ -187,9 +187,9 @@
update_icons()
/mob/living/bot/medbot/update_icons()
- overlays.Cut()
+ cut_overlays()
if(skin)
- overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
+ add_overlay("medskin_[skin]")
if(busy)
icon_state = "medibots"
else
@@ -530,7 +530,7 @@
/obj/item/weapon/firstaid_arm_assembly/Initialize()
. = ..()
if(skin)
- overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]")
+ add_overlay("kit_skin_[src.skin]")
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
@@ -550,7 +550,7 @@
build_step++
to_chat(user, "You add the health sensor to [src].")
name = "First aid/robot arm/health analyzer assembly"
- overlays += image('icons/obj/aibots.dmi', "na_scanner")
+ add_overlay("na_scanner")
if(1)
if(isprox(W))
diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm
index 04878bf7272..d36dda3cd24 100644
--- a/code/modules/mob/living/bot/mulebot.dm
+++ b/code/modules/mob/living/bot/mulebot.dm
@@ -303,7 +303,7 @@
C.pixel_y += 9
if(C.layer < layer)
C.layer = layer + 0.1
- overlays += C
+ add_overlay(C)
busy = 0
@@ -312,7 +312,7 @@
return
busy = 1
- overlays.Cut()
+ cut_overlays()
load.forceMove(loc)
load.pixel_y -= 9
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index 9e2ce96412e..9855d0efd4c 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -367,7 +367,7 @@
var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
Sa.build_step = 1
- Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole")
+ Sa.add_overlay("hs_hole")
Sa.created_name = name
new /obj/item/device/assembly/prox_sensor(Tsec)
new used_weapon(Tsec)
@@ -439,14 +439,14 @@
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0, user))
build_step = 1
- overlays += image('icons/obj/aibots.dmi', "hs_hole")
+ add_overlay("hs_hole")
to_chat(user, "You weld a hole in \the [src].")
else if(isprox(W) && (build_step == 1))
user.drop_item()
build_step = 2
to_chat(user, "You add \the [W] to [src].")
- overlays += image('icons/obj/aibots.dmi', "hs_eye")
+ add_overlay("hs_eye")
name = "helmet/signaler/prox sensor assembly"
qdel(W)
@@ -455,7 +455,7 @@
build_step = 3
to_chat(user, "You add \the [W] to [src].")
name = "helmet/signaler/prox sensor/robot arm assembly"
- overlays += image('icons/obj/aibots.dmi', "hs_arm")
+ add_overlay("hs_arm")
qdel(W)
else if(istype(W, /obj/item/weapon/melee/baton) && build_step == 3)
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index 03a878e32d1..132be558597 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -7,6 +7,7 @@
health = 100
maxHealth = 100
mob_size = 4
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
inventory_panel_type = null // Disable inventory
diff --git a/code/modules/mob/living/carbon/alien/diona/update_icons.dm b/code/modules/mob/living/carbon/alien/diona/update_icons.dm
index 1d694cf6247..9fc10ab4a87 100644
--- a/code/modules/mob/living/carbon/alien/diona/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/diona/update_icons.dm
@@ -7,6 +7,6 @@
else
icon_state = "[initial(icon_state)]"
- overlays.Cut()
+ cut_overlays()
if(hat)
- overlays |= get_hat_icon(hat, 0, -8)
\ No newline at end of file
+ add_overlay(get_hat_icon(hat, 0, -8))
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm
index 7bb90a4d9e2..a91445cc44a 100644
--- a/code/modules/mob/living/carbon/alien/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/update_icons.dm
@@ -1,5 +1,5 @@
/mob/living/carbon/alien/regenerate_icons()
- overlays = list()
+ cut_overlays()
update_icons()
/mob/living/carbon/alien/update_icons()
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 07cd72fce99..a5230484ed2 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -1,5 +1,6 @@
/mob/living/carbon
gender = MALE
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE // BLEH, this could be improved for transparent species and stuff! And blocks glowing eyes?!
var/datum/species/species //Contains icon generation and language information, set during New().
var/list/stomach_contents = list()
var/list/datum/disease2/disease/virus2 = list()
diff --git a/code/modules/mob/living/carbon/human/death_vr.dm b/code/modules/mob/living/carbon/human/death_vr.dm
index 78a2c4ea48d..ca319be6e4a 100644
--- a/code/modules/mob/living/carbon/human/death_vr.dm
+++ b/code/modules/mob/living/carbon/human/death_vr.dm
@@ -28,3 +28,10 @@
//Hooks need to return true otherwise they're considered having failed
return TRUE
+
+//For making sure that if a mob is able to be joined by ghosts, that ghosts can't join it if it dies
+/mob/living/simple_mob/death()
+ ..()
+ ghostjoin = 0
+ active_ghost_pods -= src
+ ghostjoin_icon()
diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm
index 90949f401f8..3c6451fc99a 100644
--- a/code/modules/mob/living/carbon/human/human_species.dm
+++ b/code/modules/mob/living/carbon/human/human_species.dm
@@ -2,6 +2,7 @@
real_name = "Test Dummy"
status_flags = GODMODE|CANPUSH
has_huds = FALSE
+ blocks_emissive = FALSE
/mob/living/carbon/human/dummy/Initialize()
. = ..()
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 4d2f350cc66..5cfaf0ec208 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -1252,7 +1252,7 @@
else if(no_damage)
health_images += image('icons/mob/screen1_health.dmi',"fullhealth")
- healths_ma.overlays += health_images
+ healths_ma.add_overlay(health_images)
healths.appearance = healths_ma
diff --git a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm
index 16f620ce20c..739d456bad0 100644
--- a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm
+++ b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm
@@ -93,7 +93,7 @@
var/obj/belly/B = belly
B.escapable = initial(B.escapable)
- //overlays.Cut()
+ //cut_overlays()
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
incorporeal_move = initial(incorporeal_move)
@@ -148,7 +148,7 @@
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
see_invisible = INVISIBILITY_LEVEL_TWO
- //overlays.Cut()
+ //cut_overlays()
update_icon()
alpha = 127
diff --git a/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm b/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm
index c5d2d72fff6..6d098687074 100644
--- a/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm
@@ -175,4 +175,5 @@
var/obj/item/organ/external/L = limb
L.transparent = !L.transparent
visible_message("\The [src]'s interal composition seems to change.")
- update_icons_body()
\ No newline at end of file
+ update_icons_body()
+ update_hair()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm
index 59ba73446d5..88efb6d3551 100644
--- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm
@@ -90,9 +90,9 @@
return
if(affected_mob.lying)
- affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_lie")
+ affected_mob.add_overlay("burst_lie")
else
- affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand")
+ affected_mob.add_overlay("burst_stand")
spawn(6)
var/mob/living/carbon/alien/larva/new_xeno = new(affected_mob.loc)
new_xeno.key = picked
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index b4836d168f8..8f57d6443dd 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -207,7 +207,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
else
DI = damage_icon_parts[cache_index]
- standing_image.overlays += DI
+ standing_image.add_overlay(DI)
overlays_standing[DAMAGE_LAYER] = standing_image
apply_layer(DAMAGE_LAYER)
@@ -472,14 +472,21 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
face_standing.Blend(hair_s, ICON_OVERLAY)
- if(head_organ.nonsolid || head_organ.transparent)
+ if(head_organ.transparent) //VOREStation Edit: Prometheans are not ALWAYS transparent
face_standing += rgb(,,,120)
var/icon/ears_s = get_ears_overlay()
+ var/image/em_block_ears
if(ears_s)
face_standing.Blend(ears_s, ICON_OVERLAY)
+ if(ear_style?.em_block)
+ em_block_ears = em_block_image_generic(image(ears_s))
+
+ var/image/semifinal = image(face_standing, layer = BODY_LAYER+HAIR_LAYER, "pixel_y" = head_organ.head_offset)
+ if(em_block_ears)
+ semifinal.overlays += em_block_ears // Leaving this as overlays +=
- overlays_standing[HAIR_LAYER] = image(face_standing, layer = BODY_LAYER+HAIR_LAYER, "pixel_y" = head_organ.head_offset)
+ overlays_standing[HAIR_LAYER] = semifinal
apply_layer(HAIR_LAYER)
//return //VOREStation Edit
@@ -532,6 +539,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
else
eyes_icon.Blend(rgb(128,0,0), ICON_ADD)
+ // Convert to emissive at some point
var/image/eyes_image = image(eyes_icon)
eyes_image.plane = PLANE_LIGHTING_ABOVE
eyes_image.appearance_flags = appearance_flags
@@ -566,7 +574,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
for(var/mut in mutations)
if(mut == LASER)
- standing.overlays += "lasereyes_s" //TODO
+ standing.overlays += "lasereyes_s" // Leaving this as overlays +=
overlays_standing[MUTATIONS_LAYER] = standing
apply_layer(MUTATIONS_LAYER)
@@ -1067,7 +1075,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
for(var/datum/modifier/M in modifiers)
if(M.mob_overlay_state)
var/image/I = image(icon = 'icons/mob/modifier_effects.dmi', icon_state = M.mob_overlay_state)
- effects.overlays += I //TODO, this compositing is annoying.
+ effects.overlays += I // Leaving this as overlays +=
overlays_standing[MODIFIER_EFFECTS_LAYER] = effects
@@ -1113,7 +1121,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
for(var/obj/item/organ/external/E in organs)
if(E.open)
var/image/I = image(icon = 'icons/mob/surgery.dmi', icon_state = "[E.icon_name][round(E.open)]", layer = BODY_LAYER+SURGERY_LAYER)
- total.overlays += I //TODO: This compositing is annoying
+ total.overlays += I // Leaving this as overlays +=
if(total.overlays.len)
overlays_standing[SURGERY_LAYER] = total
@@ -1127,7 +1135,9 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
if(synthetic && synthetic.includes_wing && !wing_style && !wings_hidden) //VOREStation Edit
var/icon/wing_s = new/icon("icon" = synthetic.icon, "icon_state" = "wing") //I dunno. If synths have some custom wing?
wing_s.Blend(rgb(src.r_skin, src.g_skin, src.b_skin), species.color_mult ? ICON_MULTIPLY : ICON_ADD)
- return image(wing_s)
+ var/image/working = image(wing_s)
+ working.overlays += em_block_image_generic(working) // Leaving this as overlays +=
+ return working
//If you have custom wings selected
if(wing_style && !(wear_suit && wear_suit.flags_inv & HIDETAIL) && !wings_hidden) //VOREStation Edit
@@ -1150,7 +1160,10 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
overlay.Blend(rgb(src.r_wing3, src.g_wing3, src.b_wing3), wing_style.color_blend_mode)
wing_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
- return image(wing_s)
+ var/image/working = image(wing_s)
+ if(wing_style.em_block)
+ working.overlays += em_block_image_generic(working) // Leaving this as overlays +=
+ return working
/mob/living/carbon/human/proc/get_ears_overlay()
if(ear_style && !(head && (head.flags_inv & BLOCKHEADHAIR)))
@@ -1208,15 +1221,20 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
tail_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
+ var/image/working = image(tail_s)
+ if(tail_style.em_block)
+ working.overlays += em_block_image_generic(working) // Leaving this as overlays +=
+
if(isTaurTail(tail_style))
var/datum/sprite_accessory/tail/taur/taurtype = tail_style
+ working.pixel_x = -16
if(taurtype.can_ride && !riding_datum)
riding_datum = new /datum/riding/taur(src)
verbs |= /mob/living/carbon/human/proc/taur_mount
verbs |= /mob/living/proc/toggle_rider_reins
- return image(tail_s, "pixel_x" = -16)
+ return working
else
- return image(tail_s)
+ return working
return null
// TODO - Move this to where it should go ~Leshana
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index a88a434d968..90bec77cb7d 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -238,10 +238,6 @@
set_light(distance, distance * 4, l_color = "#660066")
return TRUE
- else if(on_fire)
- set_light(min(round(fire_stacks), 3), round(fire_stacks), l_color = "#FF9933")
- return TRUE
-
else if(glow_toggle)
set_light(glow_range, glow_intensity, glow_color)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index b6e6ffc03fd..589d9ac6a31 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -366,7 +366,7 @@
/mob/living/proc/IgniteMob()
if(fire_stacks > 0 && !on_fire)
on_fire = 1
- handle_light()
+ new/obj/effect/dummy/lighting_obj/moblight/fire(src)
throw_alert("fire", /obj/screen/alert/fire)
update_fire()
@@ -374,7 +374,8 @@
if(on_fire)
on_fire = 0
fire_stacks = 0
- handle_light()
+ for(var/obj/effect/dummy/lighting_obj/moblight/fire/F in src)
+ qdel(F)
clear_alert("fire")
update_fire()
diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm
index c6fd56cb6e8..6f83805372c 100644
--- a/code/modules/mob/living/silicon/ai/multicam.dm
+++ b/code/modules/mob/living/silicon/ai/multicam.dm
@@ -70,7 +70,7 @@
M.Scale(x_scale, y_scale)
M.Translate(x_off, y_off)
dir.transform = M
- overlays += dir
+ add_overlay(dir)
/obj/screen/movable/pic_in_pic/ai/set_view_size(width, height, do_refresh = TRUE)
if(!aiEye) // Exploit fix
@@ -102,7 +102,7 @@
qdel(src)
return
highlighted = TRUE
- overlays.Cut()
+ cut_overlays()
add_background()
add_buttons()
@@ -113,7 +113,7 @@
qdel(src)
return
highlighted = FALSE
- overlays.Cut()
+ cut_overlays()
add_background()
add_buttons()
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index b578f18c230..802da6788f9 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -143,13 +143,13 @@ var/list/mob_hat_cache = list()
/mob/living/silicon/robot/drone/updateicon()
- overlays.Cut()
+ cut_overlays()
if(stat == 0)
- overlays += "eyes-[icon_state]"
+ add_overlay("eyes-[icon_state]")
else
- overlays -= "eyes"
+ cut_overlay("eyes")
if(hat) // Let the drones wear hats.
- overlays |= get_hat_icon(hat, hat_x_offset, hat_y_offset)
+ add_overlay(get_hat_icon(hat, hat_x_offset, hat_y_offset))
/mob/living/silicon/robot/drone/choose_icon()
return
diff --git a/code/modules/mob/living/silicon/robot/examine_vr.dm b/code/modules/mob/living/silicon/robot/examine_vr.dm
index 9ea0c6c1da3..2bebab2665b 100644
--- a/code/modules/mob/living/silicon/robot/examine_vr.dm
+++ b/code/modules/mob/living/silicon/robot/examine_vr.dm
@@ -3,7 +3,9 @@
var/list/message_list = list()
for(var/belly in vore_organs)
var/obj/belly/B = belly
- message_list += B.get_examine_msg()
- message_list += B.get_examine_msg_absorbed()
+ var/bellymessage = B.get_examine_msg()
+ if(bellymessage) message_list += bellymessage
+ bellymessage = B.get_examine_msg_absorbed()
+ if(bellymessage) message_list += bellymessage
- return message_list
\ No newline at end of file
+ return message_list
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index a34d2f65e71..83bf0a8b1ea 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -359,9 +359,9 @@
return canmove
/mob/living/silicon/robot/update_fire()
- overlays -= image("icon"='icons/mob/OnFire.dmi', "icon_state" = get_fire_icon_state())
+ cut_overlay(image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state()))
if(on_fire)
- overlays += image("icon"='icons/mob/OnFire.dmi', "icon_state" = get_fire_icon_state())
+ add_overlay(image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state()))
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 82bc2e24989..4164b13e24b 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -12,6 +12,8 @@
mob_swap_flags = ~HEAVY
mob_push_flags = ~HEAVY //trundle trundle
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
+
var/lights_on = 0 // Is our integrated light on?
var/used_power_this_tick = 0
var/sight_mode = 0
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index e8077db22f3..cbf2caf765a 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -211,7 +211,7 @@
I.loc = src
carrying.Add(I)
- overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer)
+ add_overlay(image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer))
addedSomething = 1
if ( addedSomething )
user.visible_message("[user] loads some items onto their service tray.")
diff --git a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm
index 23e4aa81ea7..684dd9feee8 100644
--- a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm
+++ b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm
@@ -14,7 +14,7 @@
mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone.
module = new /obj/item/weapon/robot_module/robot/gravekeeper(src)
- overlays.Cut()
+ cut_overlays()
init_id()
updatename("Gravekeeper")
diff --git a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm
index 0460226f3f5..a485d9cc8a4 100644
--- a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm
+++ b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm
@@ -13,7 +13,7 @@
mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone.
module = new /obj/item/weapon/robot_module/robot/lost(src)
- overlays.Cut()
+ cut_overlays()
init_id()
updatename("Lost")
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 3d671dd19b8..86fc492c541 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
@@ -13,7 +13,7 @@
mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone.
module = new /obj/item/weapon/robot_module/robot/stray(src)
- overlays.Cut()
+ cut_overlays()
init_id()
updatename("Stray")
diff --git a/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm b/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm
index 00e75248c71..630e0e7cd5e 100644
--- a/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm
@@ -12,7 +12,7 @@
aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src)
mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone.
- overlays.Cut()
+ cut_overlays()
init_id()
updatename("Syndicate")
diff --git a/code/modules/mob/living/silicon/robot/syndicate.dm b/code/modules/mob/living/silicon/robot/syndicate.dm
index c52755e6965..18d2b9ce80d 100644
--- a/code/modules/mob/living/silicon/robot/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/syndicate.dm
@@ -18,7 +18,7 @@
aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src)
laws = new /datum/ai_laws/syndicate_override
- overlays.Cut()
+ cut_overlays()
init_id()
new /obj/item/weapon/robot_module/robot/syndicate(src)
diff --git a/code/modules/mob/living/simple_mob/simple_hud.dm b/code/modules/mob/living/simple_mob/simple_hud.dm
index 5f0c2b3746b..513ac1d4e0e 100644
--- a/code/modules/mob/living/simple_mob/simple_hud.dm
+++ b/code/modules/mob/living/simple_mob/simple_hud.dm
@@ -166,8 +166,8 @@
zone_sel.icon = ui_style
zone_sel.color = ui_color
zone_sel.alpha = ui_alpha
- zone_sel.overlays.Cut()
- zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]")
+ zone_sel.cut_overlays()
+ zone_sel.add_overlay(image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]"))
hud_elements |= zone_sel
//Hand things
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish.dm
index fe23b86bf77..a4fb4f40785 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish.dm
@@ -180,7 +180,7 @@
update_icon()
/mob/living/simple_mob/animal/passive/fish/icebass/update_icon()
- overlays.Cut()
+ cut_overlays()
..()
if(!dorsal_image)
@@ -253,7 +253,7 @@
update_icon()
/mob/living/simple_mob/animal/passive/fish/rockfish/update_icon()
- overlays.Cut()
+ cut_overlays()
..()
if(!head_image)
head_image = image(icon, "[icon_state]_mask")
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat_vr.dm
index a63140ac8ac..cac9780d9be 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat_vr.dm
@@ -74,7 +74,7 @@
//Emergency teleport - Until a spriter makes something better
/mob/living/simple_mob/animal/passive/cat/tabiranth/death(gibbed, deathmessage = "teleports away!")
- overlays = list()
+ cut_overlays()
icon_state = ""
flick("kphaseout",src)
spawn(1 SECOND)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm
index 3825146832e..63c66aad70d 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm
@@ -41,7 +41,7 @@
..()
/mob/living/simple_mob/animal/passive/dog/regenerate_icons()
- overlays = list()
+ cut_overlays()
if(inventory_head)
var/head_icon_state = inventory_head.icon_state
@@ -50,7 +50,7 @@
var/icon/head_icon = image('icons/mob/corgi_head.dmi',head_icon_state)
if(head_icon)
- overlays += head_icon
+ add_overlay(head_icon)
if(inventory_back)
var/back_icon_state = inventory_back.icon_state
@@ -59,7 +59,7 @@
var/icon/back_icon = image('icons/mob/corgi_back.dmi',back_icon_state)
if(back_icon)
- overlays += back_icon
+ add_overlay(back_icon)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm
index 19573d78f11..8c0e653ee9c 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm
@@ -140,7 +140,7 @@
..()
/mob/living/simple_mob/animal/sif/sakimm/update_icon()
- overlays.Cut()
+ cut_overlays()
..()
if(hat)
var/hat_state = hat.item_state ? hat.item_state : hat.icon_state
diff --git a/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm b/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm
index 879db190d86..fa48f57ecf2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm
@@ -87,12 +87,10 @@
if(is_infesting)
icon = infested.icon
copy_overlays(infested)
- // overlays = infested.overlays
var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
if(overmind)
blob_head_overlay.color = overmind.blob_type.complementary_color
color = initial(color)//looks better.
- // overlays += blob_head_overlay
add_overlay(blob_head_overlay, TRUE)
/mob/living/simple_mob/blob/spore/handle_special()
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm
index ac9e3d20ff5..0a0f36d5163 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm
@@ -150,9 +150,9 @@
/mob/living/simple_mob/construct/proc/add_glow()
var/image/eye_glow = image(icon,"glow-[icon_state]")
eye_glow.plane = PLANE_LIGHTING_ABOVE
- overlays += eye_glow
+ add_overlay(eye_glow)
set_light(2, -2, l_color = "#FFFFFF")
/mob/living/simple_mob/construct/proc/remove_glow()
- overlays.Cut()
+ cut_overlays()
*/
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
index 87200c0cafb..56214bf58cd 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
@@ -36,7 +36,7 @@
var/obj/belly/B = belly
B.escapable = initial(B.escapable)
- overlays.Cut()
+ cut_overlays()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
@@ -93,7 +93,7 @@
var/obj/belly/B = belly
B.escapable = FALSE
- overlays.Cut()
+ cut_overlays()
flick("phaseout",src)
sleep(30)
invisibility = INVISIBILITY_LEVEL_TWO
@@ -149,7 +149,7 @@
var/obj/belly/B = belly
B.escapable = FALSE
- overlays.Cut()
+ cut_overlays()
flick("phaseout",src)
sleep(30)
invisibility = INVISIBILITY_LEVEL_TWO
@@ -170,7 +170,7 @@
var/obj/belly/B = belly
B.escapable = initial(B.escapable)
- overlays.Cut()
+ cut_overlays()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
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 319c063f9b7..660631471bc 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
@@ -66,11 +66,11 @@
name = "Virgo 3b Fauna - Phoron Dragon"
desc = "Classification: Phoron Draconinae\
\
- A cousin to the dragons of space, Phoron Dragons are a rare and rather unique site to see in the wilds of Virgo 3b. \
+ A cousin to the dragons of space, Phoron Dragons are a rare and rather unique sight to see in the wilds of Virgo 3b. \
Their terrifying appearance isn't just for looks, the black scales with mutated Phoron deposits in the skin are meant \
- to intimidate and frighten potential prey. They are mainly carnivorus in nature but can survive off of a mixed diet \
- of meats and plant based foods in certain circumstances - usually these circumstances are not ideal for the preadator. \
- It is unknown still how the Phoron Dragon came to be but scientist speculate that common Dragons such as Red Dragons \
+ to intimidate and frighten potential prey. They are mainly carnivorous in nature but can survive off of a mixed diet \
+ of meats and plant based foods in certain circumstances - usually these circumstances are not ideal for the predator. \
+ It is unknown still how the Phoron Dragon came to be but scientists speculate that common Dragons such as Red Dragons \
somehow ended up on Virgo 3b and through a period of evolutionary mutation became the modern day Phoron Dragon.\
\
Female dragons will often lay a clutch of eggs similar to that of other reptilian species after she is properly mated. \
@@ -78,8 +78,8 @@
this time of season have been known to be increasingly hostile. Travellers are warned against traversing in the wilds \
during these seasons because of the increased hostility.\
\
- Unlike their more fiery cousins, these dragons do not breathe flame as it would ignite both the surrounding Phoron and \
- the internal Phoron deposits of its body. Scientist still do not know how or when in the evolutionary chain they devolved \
+ Unlike their more fiery cousins, these dragons do not breathe flames as it would ignite both the surrounding Phoron and \
+ the internal Phoron deposits of its body. Scientists still do not know how or when in the evolutionary chain they lost \
their signature fire breath but it was likely very early in the chain otherwise the entire species would be extinct."
value = CATALOGUER_REWARD_HARD
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/c_shift.dm b/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/c_shift.dm
index 5c37f269d76..bf56fd4e0e9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/c_shift.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/c_shift.dm
@@ -26,7 +26,7 @@
name = real_name
- overlays.Cut()
+ cut_overlays()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
@@ -60,7 +60,7 @@
real_name = name
name = "Something"
- overlays.Cut()
+ cut_overlays()
flick("tp_out",src)
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
index 7020fccd341..689f6cce7b0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
@@ -25,7 +25,7 @@
var/obj/belly/B = belly
B.escapable = initial(B.escapable)
- overlays.Cut()
+ cut_overlays()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
@@ -80,7 +80,7 @@
var/obj/belly/B = belly
B.escapable = FALSE
- overlays.Cut()
+ cut_overlays()
flick("tp_out",src)
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm
index a494d00590a..2f275db0f1e 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm
@@ -221,7 +221,7 @@
//They phase back to the dark when killed
/mob/living/simple_mob/shadekin/death(gibbed, deathmessage = "phases to somewhere far away!")
- overlays = list()
+ cut_overlays()
icon_state = ""
flick("tp_out",src)
spawn(1 SECOND)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm b/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm
index 6eeeff5c7fb..61147bf9b40 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/softdog.dm
@@ -129,7 +129,7 @@
B.digest_brute = 0.05
B.digest_burn = 0.05
B.mode_flags = 8
- B.belly_fullscreen = "base"
+ B.belly_fullscreen = "a_tumby"
B.struggle_messages_inside = list(
"Your struggling only causes %pred's doughy gut to smother you against those wrinkled walls...",
"As you squirm, %pred's %belly flexxes over you heavily, forming you back into a small ball...",
@@ -169,6 +169,7 @@
icon_living = "cass"
icon_dead = "cass_dead"
icon_rest = "cass_rest"
+ ic_revivable = 0
faction = "theatre"
gender = PLURAL
@@ -244,4 +245,21 @@
ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting/threatening/woof
projectiletype = /obj/item/projectile/forcebolt/harmless/awoobolt
- projectilesound = 'sound/voice/long_awoo.ogg'
\ No newline at end of file
+ projectilesound = 'sound/voice/long_awoo.ogg'
+
+/mob/living/simple_mob/vore/woof/cass/attack_hand(mob/living/carbon/human/M as mob)
+ if(stat != DEAD)
+ return ..()
+ if(M.a_intent == I_HELP)
+ M.visible_message("[M] pets [src].", runemessage = "pets [src]")
+ if(do_after(M, 30 SECONDS, exclusive = 1, target = src))
+ faction = M.faction
+ revive()
+ sight = initial(sight)
+ see_in_dark = initial(see_in_dark)
+ see_invisible = initial(see_invisible)
+ update_icon()
+ visible_message("[src] stops playing dead.", runemessage = "[src] stops playing dead")
+ else
+ M.visible_message("The petting was interrupted!!!", runemessage = "The petting was interrupted")
+ return
\ No newline at end of file
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 90f6943a8c8..a0ca4cd4922 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -3,6 +3,7 @@
layer = MOB_LAYER
plane = MOB_PLANE
animate_movement = 2
+ blocks_emissive = EMISSIVE_BLOCK_GENERIC
var/datum/mind/mind
var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak
diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm
index 1d557e4e519..cfd4a917296 100644
--- a/code/modules/mob/mob_planes.dm
+++ b/code/modules/mob/mob_planes.dm
@@ -16,6 +16,8 @@
// 'Utility' planes
plane_masters[VIS_FULLBRIGHT] = new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects)
plane_masters[VIS_LIGHTING] = new /obj/screen/plane_master/lighting //Lighting system (but different!)
+ plane_masters[VIS_O_LIGHT] = new /obj/screen/plane_master/o_light_visual //Object lighting (using masks)
+ plane_masters[VIS_EMISSIVE] = new /obj/screen/plane_master/emissive //Emissive overlays
plane_masters[VIS_GHOSTS] = new /obj/screen/plane_master/ghosts //Ghosts!
plane_masters[VIS_AI_EYE] = new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye!
@@ -48,6 +50,9 @@
..()
+ for(var/obj/screen/plane_master/PM as anything in plane_masters)
+ PM.backdrop(my_mob)
+
/datum/plane_holder/Destroy()
my_mob = null
QDEL_LIST_NULL(plane_masters) //Goodbye my children, be free
@@ -106,14 +111,17 @@
for(var/SP in subplanes)
alter_values(SP, values)
+
+
+
////////////////////
// The Plane Master
////////////////////
/obj/screen/plane_master
- screen_loc = "1,1"
+ screen_loc = "CENTER"
plane = -100 //Dodge just in case someone instantiates one of these accidentally, don't end up on 0 with plane_master
appearance_flags = PLANE_MASTER
- mouse_opacity = 0 //Normally unclickable
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT //Normally unclickable
alpha = 0 //Hidden from view
var/desired_alpha = 255 //What we go to when we're enabled
var/invis_toggle = FALSE
@@ -122,6 +130,8 @@
/obj/screen/plane_master/New()
..(null) //Never be in anything ever.
+/obj/screen/plane_master/proc/backdrop(mob/mymob)
+
/obj/screen/plane_master/proc/set_desired_alpha(var/new_alpha)
if(new_alpha != alpha && new_alpha > 0 && new_alpha <= 255)
desired_alpha = new_alpha
@@ -176,6 +186,43 @@
blend_mode = BLEND_MULTIPLY
alpha = 255
+/obj/screen/plane_master/lighting/backdrop(mob/mymob)
+ /* I'm unconvinced.
+ mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit)
+ mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit)
+ */
+
+/*!
+ * This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.
+ *
+ * Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.
+ * Emissive blockers are pasted with an atom color that converts them to be entirely some different color.
+ * Emissive overlays and emissive blockers are put onto the same plane.
+ * The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.
+ * A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.
+ * This is then used to alpha mask the lighting plane.
+ */
+
+/obj/screen/plane_master/lighting/Initialize()
+ . = ..()
+ add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE))
+ add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE))
+
+/obj/screen/plane_master/o_light_visual
+ plane = PLANE_O_LIGHTING_VISUAL
+ render_target = O_LIGHTING_VISUAL_RENDER_TARGET
+ blend_mode = BLEND_MULTIPLY
+ alpha = 255
+
+/obj/screen/plane_master/emissive
+ plane = PLANE_EMISSIVE
+ render_target = EMISSIVE_RENDER_TARGET
+ alpha = 255
+
+/obj/screen/plane_master/emissive/Initialize()
+ . = ..()
+ add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix))
+
/////////////////
//Ghosts has a special alpha level
/obj/screen/plane_master/ghosts
diff --git a/code/modules/mob/mob_planes_vr.dm b/code/modules/mob/mob_planes_vr.dm
index 5d41209b196..1c47b13e720 100644
--- a/code/modules/mob/mob_planes_vr.dm
+++ b/code/modules/mob/mob_planes_vr.dm
@@ -1,11 +1,12 @@
/datum/plane_holder/New(mob/this_guy)
- ..()
+ my_mob = this_guy
plane_masters[VIS_CH_STATUS_R] = new /obj/screen/plane_master{plane = PLANE_CH_STATUS_R} //Right-side status icon
plane_masters[VIS_CH_HEALTH_VR] = new /obj/screen/plane_master{plane = PLANE_CH_HEALTH_VR} //Health bar but transparent at 100
plane_masters[VIS_CH_BACKUP] = new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status
plane_masters[VIS_CH_VANTAG] = new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags
plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(my_mob) //Augmented reality
+ ..()
/////////////////
//AR planemaster does some special image handling
diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm
index 1a13a7ed621..1e7184f9655 100644
--- a/code/modules/mob/new_player/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories.dm
@@ -39,6 +39,9 @@
// Ckey of person allowed to use this, if defined.
var/list/ckeys_allowed = null
+ /// Should this sprite block emissives?
+ var/em_block = FALSE
+
/*
////////////////////////////
/ =--------------------= /
@@ -1519,6 +1522,7 @@ shaved
/datum/sprite_accessory/facial_hair
icon = 'icons/mob/Human_face.dmi'
color_blend_mode = ICON_ADD
+ em_block = TRUE
/datum/sprite_accessory/facial_hair/shaved
name = "Shaved"
diff --git a/code/modules/mob/new_player/sprite_accessories_ear.dm b/code/modules/mob/new_player/sprite_accessories_ear.dm
index 24e82043e41..fbf59a0fecc 100644
--- a/code/modules/mob/new_player/sprite_accessories_ear.dm
+++ b/code/modules/mob/new_player/sprite_accessories_ear.dm
@@ -14,6 +14,7 @@
var/extra_overlay // Icon state of an additional overlay to blend in.
var/extra_overlay2
var/desc = "You should not see this..."
+ em_block = TRUE
species_allowed = list(SPECIES_EVENT1, SPECIES_EVENT2, SPECIES_EVENT3)
diff --git a/code/modules/mob/new_player/sprite_accessories_tail.dm b/code/modules/mob/new_player/sprite_accessories_tail.dm
index dec95139744..f2d6fce6360 100644
--- a/code/modules/mob/new_player/sprite_accessories_tail.dm
+++ b/code/modules/mob/new_player/sprite_accessories_tail.dm
@@ -11,6 +11,7 @@
do_colouration = 0 //Set to 1 to enable coloration using the tail color.
color_blend_mode = ICON_ADD // Only appliciable if do_coloration = 1
+ em_block = TRUE
var/extra_overlay // Icon state of an additional overlay to blend in.
var/extra_overlay2 //Tertiary.
var/show_species_tail = 0 // If false, do not render species' tail.
diff --git a/code/modules/mob/new_player/sprite_accessories_taur.dm b/code/modules/mob/new_player/sprite_accessories_taur.dm
index dad54ed188c..59f8f8f4d77 100644
--- a/code/modules/mob/new_player/sprite_accessories_taur.dm
+++ b/code/modules/mob/new_player/sprite_accessories_taur.dm
@@ -123,6 +123,7 @@
icon = 'icons/mob/human_races/sprite_accessories/taurs.dmi'
do_colouration = 1 // Yes color, using tail color
color_blend_mode = ICON_MULTIPLY // The sprites for taurs are designed for ICON_MULTIPLY
+ em_block = TRUE
var/icon/suit_sprites = null //File for suit sprites, if any.
var/icon/under_sprites = null
diff --git a/code/modules/mob/new_player/sprite_accessories_wing.dm b/code/modules/mob/new_player/sprite_accessories_wing.dm
index 486e81f4b10..85bdedd04ae 100644
--- a/code/modules/mob/new_player/sprite_accessories_wing.dm
+++ b/code/modules/mob/new_player/sprite_accessories_wing.dm
@@ -11,6 +11,7 @@
do_colouration = 0 //Set to 1 to enable coloration using the tail color.
color_blend_mode = ICON_ADD // Only appliciable if do_coloration = 1
+ em_block = TRUE
var/extra_overlay // Icon state of an additional overlay to blend in.
var/extra_overlay2 //Tertiary.
var/clothing_can_hide = 1 // If true, clothing with HIDETAIL hides it. If the clothing is bulky enough to hide a tail, it should also hide wings.
diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm
index d4b311e8e25..8639aadb63b 100644
--- a/code/modules/modular_computers/computers/modular_computer/core.dm
+++ b/code/modules/modular_computers/computers/modular_computer/core.dm
@@ -72,22 +72,34 @@
/obj/item/modular_computer/update_icon()
icon_state = icon_state_unpowered
- overlays.Cut()
+ cut_overlays()
+
+ . = list()
+
if(bsod)
- overlays += image(icon = overlay_icon, icon_state = "bsod")
- return
+ . += mutable_appearance(overlay_icon, "bsod")
+ . += emissive_appearance(overlay_icon, "bsod")
+ return add_overlay(.)
if(!enabled)
if(icon_state_screensaver)
- overlays += image(icon = overlay_icon, icon_state = icon_state_screensaver)
+ . += mutable_appearance(overlay_icon, icon_state_screensaver)
+ . += emissive_appearance(overlay_icon, icon_state_screensaver)
set_light(0)
- return
+ return add_overlay(.)
+
set_light(light_strength)
+
if(active_program)
- overlays += image(icon = overlay_icon, icon_state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
+ var/program_state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu
+ . += mutable_appearance(overlay_icon, program_state)
+ . += emissive_appearance(overlay_icon, program_state)
if(active_program.program_key_state)
- overlays += image(icon = overlay_icon, icon_state = active_program.program_key_state)
+ . += mutable_appearance(overlay_icon, active_program.program_key_state)
else
- overlays += image(icon = overlay_icon, icon_state = icon_state_menu)
+ . += mutable_appearance(overlay_icon, icon_state_menu)
+ . += emissive_appearance(overlay_icon, icon_state_menu)
+
+ return add_overlay(.)
/obj/item/modular_computer/proc/turn_on(var/mob/user)
if(bsod)
diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm
index 373d2ad3e1f..59c45f993a2 100644
--- a/code/modules/modular_computers/computers/modular_computer/variables.dm
+++ b/code/modules/modular_computers/computers/modular_computer/variables.dm
@@ -24,6 +24,7 @@
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
icon = null // This thing isn't meant to be used on it's own. Subtypes should supply their own icon.
+ blocks_emissive = FALSE
var/overlay_icon = null // Icon file used for overlays
icon_state = null
center_of_mass = null // No pixelshifting by placing on tables, etc.
diff --git a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm
index 156d67525b5..a09b432af88 100644
--- a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm
+++ b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm
@@ -41,7 +41,7 @@
if(anchored)
..()
else
- overlays.Cut()
+ cut_overlays()
set_light(0) // No glow from closed laptops
icon_state = icon_state_closed
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index 77885e7ce5a..15c000cdc5c 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -127,7 +127,7 @@
temp2.icon_state = null
temp2.plane = src.plane
temp2.color = O.color
- temp2.overlays += O.overlays
+ temp2.overlays = get_overlays(O, TRUE)
// TODO Is pixelx/y needed?
o_img += temp2
add_overlay(o_img)
diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm
index e43ab219395..3b6efa34d0a 100644
--- a/code/modules/multiz/zshadow.dm
+++ b/code/modules/multiz/zshadow.dm
@@ -117,10 +117,10 @@
if(!typing_indicator)
init_typing_indicator("typing")
if(state && !typing)
- overlays += typing_indicator
+ add_overlay(typing_indicator)
typing = 1
else if(!state && typing)
- overlays -= typing_indicator
+ cut_overlay(typing_indicator)
typing = 0
if(shadow)
shadow.set_typing_indicator(state)
diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm
index f1214708f10..f0d1c826ec3 100644
--- a/code/modules/organs/blood.dm
+++ b/code/modules/organs/blood.dm
@@ -361,7 +361,7 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large)
var/obj/effect/decal/cleanable/blood/drip/drop = B
if(istype(drop) && drips && drips.len && !large)
- drop.overlays |= drips
+ drop.add_overlay(drips)
drop.drips |= drips
// If there's no data to copy, call it quits here.
diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm
index 43b4e35788f..7216540734a 100644
--- a/code/modules/organs/organ_icon.dm
+++ b/code/modules/organs/organ_icon.dm
@@ -9,7 +9,7 @@ var/global/list/limb_icon_cache = list()
for(var/obj/item/organ/external/organ in contents)
if(organ.children && organ.children.len)
for(var/obj/item/organ/external/child in organ.children)
- overlays += child.mob_icon
+ add_overlay(child.mob_icon)
add_overlay(organ.mob_icon)
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human)
diff --git a/code/modules/overmap/overmap_planet.dm b/code/modules/overmap/overmap_planet.dm
index 28a8bf10d13..dcb8fc1af39 100644
--- a/code/modules/overmap/overmap_planet.dm
+++ b/code/modules/overmap/overmap_planet.dm
@@ -22,29 +22,29 @@
/obj/effect/overmap/visitable/planet/get_skybox_representation()
var/image/skybox_image = image('icons/skybox/planet.dmi', "")
- skybox_image.overlays += get_base_image()
+ skybox_image.add_overlay(get_base_image())
// for(var/datum/exoplanet_theme/theme in themes)
-// skybox_image.overlays += theme.get_planet_image_extra()
+// skybox_image.add_overlay(theme.get_planet_image_extra())
if(mountain_color)
var/image/mountains = image('icons/skybox/planet.dmi', "mountains")
mountains.color = mountain_color
mountains.appearance_flags = PIXEL_SCALE
- skybox_image.overlays += mountains
+ skybox_image.add_overlay(mountains)
if(water_color)
var/image/water = image('icons/skybox/planet.dmi', "water")
water.color = water_color
water.appearance_flags = PIXEL_SCALE
// water.transform = water.transform.Turn(rand(0,360))
- skybox_image.overlays += water
+ skybox_image.add_overlay(water)
if(icecaps)
var/image/ice = image('icons/skybox/planet.dmi', icecaps)
ice.color = ice_color
ice.appearance_flags = PIXEL_SCALE
- skybox_image.overlays += ice
+ skybox_image.add_overlay(ice)
if(atmosphere && atmosphere.return_pressure() > SOUND_MINIMUM_PRESSURE)
@@ -55,20 +55,20 @@
var/image/clouds = image('icons/skybox/planet.dmi', "weak_clouds")
if(water_color)
- clouds.overlays += image('icons/skybox/planet.dmi', "clouds")
+ clouds.add_overlay(image('icons/skybox/planet.dmi', "clouds"))
clouds.color = atmo_color
- skybox_image.overlays += clouds
+ skybox_image.add_overlay(clouds)
var/image/atmo = image('icons/skybox/planet.dmi', "atmoring")
skybox_image.underlays += atmo
var/image/shadow = image('icons/skybox/planet.dmi', "shadow")
shadow.blend_mode = BLEND_MULTIPLY
- skybox_image.overlays += shadow
+ skybox_image.add_overlay(shadow)
var/image/light = image('icons/skybox/planet.dmi', "lightrim")
- skybox_image.overlays += light
+ skybox_image.add_overlay(light)
if(has_rings)
var/image/rings = image('icons/skybox/planet_rings.dmi')
@@ -79,7 +79,7 @@
rings.color = ring_color
rings.pixel_x = -128
rings.pixel_y = -128
- skybox_image.overlays += rings
+ skybox_image.add_overlay(rings)
skybox_image.pixel_x = rand(0,64) + skybox_offset_x
skybox_image.pixel_y = rand(128,256) + skybox_offset_y
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index 64f02d21887..5aeb72639b0 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -34,13 +34,13 @@
return
/obj/item/weapon/clipboard/update_icon()
- overlays.Cut()
+ cut_overlays()
if(toppaper)
- overlays += toppaper.icon_state
- overlays += toppaper.overlays
+ add_overlay(toppaper.icon_state)
+ add_overlay(toppaper.overlays)
if(haspen)
- overlays += "clipboard_pen"
- overlays += "clipboard_over"
+ add_overlay("clipboard_pen")
+ add_overlay("clipboard_over")
return
/obj/item/weapon/clipboard/attackby(obj/item/weapon/W as obj, mob/user as mob)
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index 49a9cb0b916..2275ef1bd4a 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -57,9 +57,9 @@
icon_state = "folder_hos"
/obj/item/weapon/folder/update_icon()
- overlays.Cut()
+ cut_overlays()
if(contents.len)
- overlays += "folder_paper"
+ add_overlay("folder_paper")
return
/obj/item/weapon/folder/attackby(obj/item/weapon/W as obj, mob/user as mob)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 1ef601fde55..59f2825b72c 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -301,7 +301,7 @@
stamps = null
free_space = MAX_PAPER_MESSAGE_LEN
stamped = list()
- overlays.Cut()
+ cut_overlays()
updateinfolinks()
update_icon()
@@ -608,7 +608,7 @@
if(!stamped)
stamped = new
stamped += P.type
- overlays += stampoverlay
+ add_overlay(stampoverlay)
playsound(src, 'sound/bureaucracy/stamp.ogg', 50, 1)
to_chat(user, "You stamp the paper with your rubber stamp.")
diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm
index 5c5eb14a571..24aeae6c716 100644
--- a/code/modules/paperwork/paper_bundle.dm
+++ b/code/modules/paperwork/paper_bundle.dm
@@ -217,7 +217,7 @@
/obj/item/weapon/paper_bundle/update_icon()
var/obj/item/weapon/paper/P = pages[1]
icon_state = P.icon_state
- overlays = P.overlays
+ copy_overlays(P)
underlays = 0
var/i = 0
var/photo
@@ -235,12 +235,12 @@
var/obj/item/weapon/photo/Ph = O
img = Ph.tiny
photo = 1
- overlays += img
+ add_overlay(img)
if(i>1)
desc = "[i] papers clipped to each other."
else
desc = "A single sheet of paper."
if(photo)
desc += "\nThere is a photo attached to it."
- overlays += image('icons/obj/bureaucracy.dmi', "clip")
+ add_overlay(image('icons/obj/bureaucracy.dmi', "clip"))
return
\ No newline at end of file
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index 3b4833a5332..65c3bff6bf7 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -35,7 +35,7 @@
return ..()
/obj/item/weapon/paperplane/update_icon()
- overlays.Cut()
+ cut_overlays()
var/list/stamped = internalPaper.stamped
if(!stamped)
stamped = new
@@ -43,7 +43,7 @@
for(var/S in stamped)
var/obj/item/weapon/stamp/ = S
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[initial(stamp.icon_state)]")
- overlays += stampoverlay
+ add_overlay(stampoverlay)
/obj/item/weapon/paperplane/attack_self(mob/user)
to_chat(user, "You unfold [src].")
diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm
index f5fae97d83b..223608f0aa7 100644
--- a/code/modules/paperwork/papershredder.dm
+++ b/code/modules/paperwork/papershredder.dm
@@ -126,15 +126,15 @@
update_icon()
/obj/machinery/papershredder/update_icon()
- overlays.Cut()
+ cut_overlays()
if(operable())
icon_state = "shredder-on"
else
icon_state = "shredder-off"
// Fullness overlay
- overlays += "shredder-[max(0,min(5,FLOOR(paperamount/max_paper*5, 1)))]"
+ add_overlay("shredder-[max(0,min(5,FLOOR(paperamount/max_paper*5, 1)))]")
if (panel_open)
- overlays += "panel_open"
+ add_overlay("panel_open")
//
// Shredded Paper Item
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 441b0bcbb60..0ac1a96e198 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -220,7 +220,7 @@
img = image('icons/obj/bureaucracy.dmi', "paper_stamp-dots")
img.pixel_x = copy.offset_x[j]
img.pixel_y = copy.offset_y[j]
- c.overlays += img
+ c.add_overlay(img)
c.updateinfolinks()
if(need_toner)
toner--
diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm
index 99c98220193..93245c2a850 100644
--- a/code/modules/pda/app.dm
+++ b/code/modules/pda/app.dm
@@ -41,14 +41,14 @@
pda.play_ringtone()
if(blink && !(src in pda.notifying_programs))
- pda.overlays += image(icon, "pda-r")
+ pda.add_overlay("pda-r")
pda.notifying_programs |= src
/datum/data/pda/proc/unnotify()
if(src in pda.notifying_programs)
pda.notifying_programs -= src
if(!pda.notifying_programs.len)
- pda.overlays -= image(icon, "pda-r")
+ pda.cut_overlay("pda-r")
// An app has a button on the home screen and its own UI
/datum/data/pda/app
diff --git a/code/modules/pda/pda.dm b/code/modules/pda/pda.dm
index 298e8efd135..2755e09d3f7 100644
--- a/code/modules/pda/pda.dm
+++ b/code/modules/pda/pda.dm
@@ -300,7 +300,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(can_use(usr))
start_program(find_program(/datum/data/pda/app/main_menu))
notifying_programs.Cut()
- overlays -= image(icon, "pda-r")
+ cut_overlay("pda-r")
to_chat(usr, "You press the reset button on \the [src].")
else
to_chat(usr, "You cannot do this while restrained.")
diff --git a/code/modules/persistence/noticeboard.dm b/code/modules/persistence/noticeboard.dm
index 760c0979eda..87304164359 100644
--- a/code/modules/persistence/noticeboard.dm
+++ b/code/modules/persistence/noticeboard.dm
@@ -178,33 +178,33 @@
P.name = "Memo RE: proper analysis procedure"
P.info = " We keep test dummies in pens here for a reason, so standard procedure should be to activate newfound alien artifacts and place the two in close proximity. Promising items I might even approve monkey testing on."
P.stamped = list(/obj/item/weapon/stamp/rd)
- P.overlays = list("paper_stamped_rd")
+ P.add_overlay("paper_stamped_rd")
contents += P
P = new()
P.name = "Memo RE: materials gathering"
P.info = "Corasang, the hands-on approach to gathering our samples may very well be slow at times, but it's safer than allowing the blundering miners to roll willy-nilly over our dig sites in their mechs, destroying everything in the process. And don't forget the escavation tools on your way out there! - R.W"
P.stamped = list(/obj/item/weapon/stamp/rd)
- P.overlays = list("paper_stamped_rd")
+ P.add_overlay("paper_stamped_rd")
contents += P
P = new()
P.name = "Memo RE: ethical quandaries"
P.info = "Darion-
Beyond this point the underground maintenance tunnels are dangerous. Monsters have taken to making their nests in the tunnels. As such we have installed an automatic defense system.
The turrets and supply caches in the tunnels are powered by this facility. Should there be undesired creatures or personnel in the tunnels, the turrets exist to keep them clear.
The turret control system is situated within the local administration building. It is advised that you never enter the tunnels outside of regulatly scheduled maintenance windows, and never without secturity escort.
If you should need to enter the tunnels outside of regularly scheduled maintenance windows, it is advised that you contact the administration building to disable the turrets, and when you are done, contact them again to re-enable them.
Your safety is important to us. Should you end up within the tunnels when dangerous entities are present, it is advised to seek out the supply caches scattered throughout. Survival equipment can be obtained from within.