diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 9c2a1a2883..75efefd8e1 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -3098,7 +3098,9 @@
/turf/open/floor/plating,
/area/maintenance/fore/secondary)
"agd" = (
-/obj/machinery/atmospherics/pipe/manifold4w/general/visible,
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"age" = (
@@ -6473,16 +6475,6 @@
},
/turf/open/floor/plasteel/white,
/area/science/xenobiology)
-"alX" = (
-/obj/machinery/button/door{
- id = "atmos";
- name = "Atmospherics Lockdown";
- pixel_x = 24;
- pixel_y = 4;
- req_access_txt = "24"
- },
-/turf/open/floor/plasteel,
-/area/engine/atmos)
"alY" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -39435,7 +39427,10 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPe" = (
-/obj/machinery/atmospherics/pipe/manifold/yellow/visible,
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Pure to Ports"
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPf" = (
@@ -39453,10 +39448,10 @@
/area/engine/atmos)
"bPh" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/layer_manifold{
dir = 4
},
-/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/engine/atmos)
"bPi" = (
@@ -40719,7 +40714,9 @@
/area/engine/atmos)
"bSM" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/general/visible,
+/obj/machinery/atmospherics/pipe/simple/general/visible{
+ dir = 5
+ },
/turf/open/floor/plating,
/area/engine/atmos)
"bSP" = (
@@ -41475,13 +41472,16 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bUN" = (
-/obj/machinery/atmospherics/pipe/manifold/general/visible,
+/obj/machinery/portable_atmospherics/canister,
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bUO" = (
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "Ports to External"
+/obj/machinery/portable_atmospherics/canister,
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -41912,8 +41912,9 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bVZ" = (
-/obj/machinery/atmospherics/pipe/manifold/general/visible{
- dir = 8
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Ports to External"
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -46658,8 +46659,8 @@
/turf/closed/wall/r_wall,
/area/engine/atmos)
"ciu" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/layer_manifold,
/turf/open/floor/plating,
/area/engine/atmos)
"civ" = (
@@ -46703,8 +46704,7 @@
/obj/structure/reagent_dispensers/watertank,
/obj/item/extinguisher,
/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 4;
- pixel_y = 0
+ dir = 4
},
/turf/open/floor/plasteel,
/area/maintenance/disposal/incinerator)
@@ -53525,8 +53525,9 @@
/turf/open/floor/plasteel,
/area/security/brig)
"daq" = (
-/obj/machinery/atmospherics/components/unary/portables_connector/visible,
-/obj/machinery/portable_atmospherics/canister,
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"daI" = (
@@ -53948,9 +53949,7 @@
/turf/open/floor/plating,
/area/security/prison)
"eqq" = (
-/obj/machinery/atmospherics/pipe/manifold/orange/visible{
- dir = 4
- },
+/obj/machinery/atmospherics/pipe/manifold/orange/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"eqA" = (
@@ -55365,7 +55364,7 @@
"ivJ" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/purple/visible{
+/obj/machinery/atmospherics/pipe/layer_manifold{
dir = 4
},
/turf/open/floor/plating,
@@ -55418,7 +55417,7 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
+/obj/machinery/atmospherics/pipe/layer_manifold,
/turf/open/floor/plating,
/area/engine/atmos)
"iLJ" = (
@@ -55709,11 +55708,7 @@
/turf/closed/wall/r_wall,
/area/engine/gravity_generator)
"jBQ" = (
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "Pure to Ports"
- },
-/obj/machinery/atmospherics/pipe/simple/general/visible,
+/obj/machinery/atmospherics/pipe/manifold4w/general/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"jCq" = (
@@ -56729,6 +56724,10 @@
},
/turf/open/floor/wood,
/area/crew_quarters/bar)
+"moS" = (
+/obj/machinery/atmospherics/pipe/manifold4w/yellow/visible,
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"mps" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -57774,7 +57773,9 @@
/area/crew_quarters/fitness)
"pCj" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 5
+ },
/turf/open/floor/plating,
/area/engine/atmos)
"pDe" = (
@@ -57916,10 +57917,11 @@
/turf/open/floor/plasteel,
/area/security/processing)
"pUP" = (
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
- dir = 5
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 4
},
-/turf/open/floor/plasteel,
+/turf/open/floor/plating,
/area/engine/atmos)
"qaY" = (
/obj/structure/table/reinforced,
@@ -58470,6 +58472,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/maintenance/fore)
+"rTo" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "External to Pumps"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"rTu" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -60035,18 +60044,18 @@
/turf/open/floor/plasteel/white,
/area/science/circuit)
"vPQ" = (
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "External to Pumps"
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 10
},
-/turf/open/floor/plasteel,
+/turf/open/floor/plating,
/area/engine/atmos)
"vQf" = (
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
-/obj/machinery/atmospherics/components/binary/pump/on{
+/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
name = "Mix to External"
},
@@ -93434,7 +93443,7 @@ bQp
alk
gAu
eqq
-pUP
+bOd
bOd
bOd
bOd
@@ -93690,8 +93699,8 @@ bJF
bVX
bRA
bTP
+rTo
bOd
-vPQ
bOd
bOd
bOd
@@ -93948,7 +93957,7 @@ bMQ
bRC
rdl
daq
-bUN
+bUO
bOd
bOd
bOd
@@ -94205,7 +94214,7 @@ cBF
bRD
rdl
daq
-bUN
+bUO
bOd
bOd
bOd
@@ -94461,7 +94470,7 @@ bPc
bQs
cez
ceA
-bOd
+daq
bUO
bOd
bOd
@@ -94719,7 +94728,7 @@ bQv
bRF
bSM
bVZ
-bUN
+bOd
bOd
bOd
bOd
@@ -94974,7 +94983,7 @@ bOc
udT
omk
nTU
-bSM
+pUP
jBQ
agd
cCB
@@ -95488,8 +95497,8 @@ oVN
bPf
bQx
bRH
-bMQ
-bTU
+vPQ
+moS
kGv
bUS
cCE
@@ -96003,15 +96012,15 @@ ivJ
bQy
bRI
bSP
-bPh
+ivJ
jzM
bRI
cCF
-bPh
+ivJ
bQy
bRI
bQy
-bPh
+ivJ
bQy
bRI
bSP
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 75af28d174..9d36d26f6f 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -39336,6 +39336,9 @@
/obj/machinery/atmospherics/pipe/simple/orange/visible{
dir = 4
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"byY" = (
@@ -40124,6 +40127,7 @@
/obj/structure/cable/yellow{
icon_state = "2-4"
},
+/obj/machinery/light/small,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bAI" = (
@@ -41633,7 +41637,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 5
},
-/turf/closed/wall/r_wall,
+/turf/closed/wall,
/area/engine/atmos)
"bDS" = (
/obj/effect/turf_decal/tile/yellow{
@@ -42650,7 +42654,7 @@
/area/engine/atmos)
"bFI" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/closed/wall,
+/turf/closed/wall/r_wall,
/area/engine/atmos)
"bFJ" = (
/obj/structure/disposalpipe/segment{
@@ -42659,7 +42663,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
-/turf/open/floor/plasteel/dark/corner,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bFM" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
@@ -42702,15 +42706,13 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bFR" = (
-/obj/machinery/atmospherics/pipe/simple/purple/visible{
- dir = 6
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
-/turf/open/floor/plasteel,
+/turf/closed/wall,
/area/engine/atmos)
"bFS" = (
-/obj/machinery/atmospherics/pipe/simple/purple/visible{
- dir = 9
- },
+/obj/machinery/atmospherics/pipe/simple/purple/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bFT" = (
@@ -43345,9 +43347,8 @@
/area/engine/atmos)
"bHx" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/purple/visible,
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 4
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
+ dir = 1
},
/turf/open/floor/plating,
/area/engine/atmos)
@@ -44017,7 +44018,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 5
},
-/turf/closed/wall/r_wall,
+/turf/closed/wall,
/area/engine/atmos)
"bIP" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
@@ -44047,27 +44048,29 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bIT" = (
-/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
- dir = 4
- },
/obj/machinery/meter,
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 9
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bIU" = (
-/obj/machinery/atmospherics/pipe/simple/purple/visible,
-/obj/machinery/meter,
+/obj/machinery/atmospherics/components/binary/pump{
+ name = "Air to Ports"
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bIV" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 6
+/obj/machinery/atmospherics/components/binary/pump{
+ name = "Mix to Ports"
},
-/obj/machinery/meter,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bIW" = (
-/obj/machinery/atmospherics/pipe/manifold/yellow/visible,
-/turf/open/floor/plasteel,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
+/turf/closed/wall,
/area/engine/atmos)
"bIX" = (
/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
@@ -44786,8 +44789,12 @@
/turf/open/floor/plasteel,
/area/storage/tcom)
"bKu" = (
-/obj/effect/turf_decal/bot,
-/turf/closed/wall/r_wall,
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/purple/visible,
+/turf/open/floor/plating,
/area/engine/atmos)
"bKw" = (
/obj/structure/cable/yellow{
@@ -44800,7 +44807,7 @@
/obj/machinery/atmospherics/pipe/simple/orange/visible{
dir = 4
},
-/turf/closed/wall/r_wall,
+/turf/closed/wall,
/area/engine/atmos)
"bKz" = (
/obj/machinery/atmospherics/pipe/simple/orange/visible{
@@ -44830,7 +44837,9 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bKE" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
+/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bKF" = (
@@ -45559,9 +45568,9 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/obj/machinery/atmospherics/components/binary/pump/on{
+/obj/machinery/atmospherics/components/binary/pump{
dir = 1;
- name = "Mix to External"
+ name = "Port to External"
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -45569,7 +45578,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 10
},
-/turf/closed/wall/r_wall,
+/turf/closed/wall,
/area/engine/atmos)
"bMh" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
@@ -46436,7 +46445,12 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
+ dir = 9
+ },
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 6
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bNR" = (
@@ -47128,6 +47142,7 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/machinery/atmospherics/pipe/simple/dark/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPr" = (
@@ -50108,7 +50123,9 @@
},
/area/engine/atmos)
"bVI" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
+ dir = 9
+ },
/turf/open/floor/plasteel/dark/corner{
dir = 1
},
@@ -50860,6 +50877,9 @@
/obj/structure/cable/yellow{
icon_state = "1-8"
},
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 9
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bXq" = (
@@ -53689,9 +53709,7 @@
/obj/machinery/atmospherics/pipe/simple/green/visible{
dir = 4
},
-/obj/machinery/atmospherics/components/binary/pump{
- name = "Mix to Fuel Pipe"
- },
+/obj/machinery/atmospherics/pipe/simple/dark/visible,
/turf/open/floor/plasteel/dark,
/area/engine/atmos)
"ccP" = (
@@ -78788,11 +78806,10 @@
name = "Inner Pipe Access";
req_access_txt = "24"
},
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 4;
- name = "Mix to Engine"
- },
/obj/machinery/atmospherics/pipe/simple/yellow/visible,
+/obj/machinery/atmospherics/pipe/simple/orange/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel/dark,
/area/engine/atmos)
"dhj" = (
@@ -81294,6 +81311,15 @@
},
/turf/open/floor/plating,
/area/quartermaster/storage)
+"dLd" = (
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"dLK" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -81536,6 +81562,12 @@
/obj/item/integrated_circuit_printer,
/turf/open/floor/plasteel/white,
/area/science/circuit)
+"gRX" = (
+/obj/machinery/atmospherics/pipe/simple/orange/visible{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"gXY" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
@@ -81605,6 +81637,13 @@
},
/turf/open/floor/plasteel/white,
/area/science/lab)
+"izM" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Pure to Ports"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"iCn" = (
/obj/machinery/vr_sleeper,
/turf/open/floor/plasteel,
@@ -81613,6 +81652,13 @@
/obj/structure/table,
/turf/open/floor/plating,
/area/maintenance/port/aft)
+"iRL" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 0;
+ name = "Mix to Engine"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"iSt" = (
/obj/machinery/door/airlock/grunge,
/obj/structure/cable/yellow{
@@ -81677,6 +81723,15 @@
},
/turf/open/floor/plating,
/area/maintenance/solars/port/aft)
+"jAj" = (
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 6
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"jBe" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -82064,6 +82119,12 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard)
+"nBn" = (
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"nIb" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/mining{
@@ -82143,6 +82204,13 @@
/obj/structure/table/reinforced,
/turf/open/floor/plasteel/white,
/area/science/circuit)
+"oms" = (
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 1
+ },
+/obj/machinery/meter,
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"omz" = (
/obj/machinery/status_display/supply,
/turf/closed/wall,
@@ -82218,6 +82286,13 @@
/obj/structure/grille,
/turf/open/floor/plating,
/area/maintenance/port/aft)
+"pbF" = (
+/obj/machinery/portable_atmospherics/canister,
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"pmc" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 5
@@ -82403,6 +82478,12 @@
},
/turf/open/floor/plasteel,
/area/security/prison)
+"rpR" = (
+/obj/machinery/atmospherics/pipe/simple/orange/visible{
+ dir = 5
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"rzX" = (
/obj/structure/chair/office/light{
dir = 1;
@@ -82416,6 +82497,12 @@
},
/turf/open/floor/plasteel/white,
/area/science/lab)
+"rAc" = (
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"rLV" = (
/obj/structure/table,
/obj/item/folder,
@@ -82483,6 +82570,13 @@
/obj/structure/grille,
/turf/open/floor/plating/airless,
/area/space/nearstation)
+"siI" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Port to Filter"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"soe" = (
/obj/effect/turf_decal/tile/green,
/obj/effect/turf_decal/tile/green{
@@ -82501,6 +82595,12 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"stP" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ name = "Port to Fuel Pipe"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"syk" = (
/obj/machinery/door/airlock{
id_tag = "AuxShower";
@@ -82649,6 +82749,10 @@
/obj/machinery/cryopod,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
+"uku" = (
+/obj/machinery/atmospherics/pipe/manifold4w/general/visible,
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"upN" = (
/obj/effect/turf_decal/stripes/line{
dir = 5
@@ -82867,6 +82971,12 @@
/obj/machinery/vending/cola/random,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"xgC" = (
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 9
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"xkG" = (
/obj/item/integrated_electronics/wirer,
/obj/structure/table/reinforced,
@@ -122977,7 +123087,7 @@ bpg
brA
bep
bvd
-bxd
+bxc
byR
bAB
bCh
@@ -123234,7 +123344,7 @@ bpg
brB
bep
bve
-bxd
+bxc
byS
bAC
dBJ
@@ -123491,7 +123601,7 @@ bpg
brC
bep
bCK
-bxd
+bxc
byT
bAD
bCj
@@ -124005,7 +124115,7 @@ bpi
brE
btz
bvh
-bxd
+bxc
byV
bAF
bCk
@@ -124013,7 +124123,7 @@ dBJ
bFH
bHq
bCk
-bKu
+bxd
bxc
bxc
bxc
@@ -124522,10 +124632,10 @@ bep
bxc
bKy
bAG
-bxg
+bFR
dBM
bza
-bxl
+bIW
bIO
bMg
bMb
@@ -124536,8 +124646,8 @@ bSg
bDS
bDS
bVI
-dBJ
-bCi
+jAj
+bYw
bYw
cbe
ccO
@@ -124784,7 +124894,7 @@ bDT
bFM
bHu
bIP
-bKw
+dLd
bKw
bNQ
bPq
@@ -125041,9 +125151,9 @@ bDU
bFN
bAO
bIS
+siI
bCi
-bCi
-bCi
+rAc
bCi
bCi
bCi
@@ -125298,9 +125408,9 @@ bDV
bFO
bHv
bIR
-bCi
-bCi
-bCi
+nBn
+stP
+xgC
bCi
bCi
bCi
@@ -125555,8 +125665,8 @@ bMe
bFP
bMe
bMf
-bCi
-bCi
+uku
+pbF
bCi
bCi
bCi
@@ -125812,8 +125922,8 @@ bDW
bFQ
bHw
bIT
-bCi
-bCi
+oms
+pbF
bCi
bCi
bCi
@@ -126066,11 +126176,11 @@ bzc
bAL
ddF
bDX
-bFR
+bCi
bHx
bIU
-bCi
-bCi
+uku
+pbF
bCi
bCi
bKD
@@ -126324,11 +126434,11 @@ bAM
bCt
bDY
bFS
-bHy
+bKu
bIV
-bCi
-bCi
-bCi
+uku
+iRL
+rpR
bCi
bCi
bCi
@@ -126582,10 +126692,10 @@ bCu
bDZ
bFT
bHz
-bIW
+bNR
+izM
bKD
-bCi
-bCi
+gRX
bCi
bCi
bCi
@@ -126842,7 +126952,7 @@ bHy
bIX
bKE
bNR
-bCi
+gRX
bCi
bCi
bCi
diff --git a/byond-extools.dll b/byond-extools.dll
new file mode 100644
index 0000000000..a83ea1e543
Binary files /dev/null and b/byond-extools.dll differ
diff --git a/code/__DEFINES/_tick.dm b/code/__DEFINES/_tick.dm
index 10b815e547..fc6147c430 100644
--- a/code/__DEFINES/_tick.dm
+++ b/code/__DEFINES/_tick.dm
@@ -1,13 +1,28 @@
-#define TICK_LIMIT_RUNNING 80
+/// Percentage of tick to leave for master controller to run
+#define MAPTICK_MC_MIN_RESERVE 70
+/// internal_tick_usage is updated every tick by extools
+#define MAPTICK_LAST_INTERNAL_TICK_USAGE ((GLOB.internal_tick_usage / world.tick_lag) * 100)
+/// Tick limit while running normally
+#define TICK_BYOND_RESERVE 2
+#define TICK_LIMIT_RUNNING (max(100 - TICK_BYOND_RESERVE - MAPTICK_LAST_INTERNAL_TICK_USAGE, MAPTICK_MC_MIN_RESERVE))
+/// Tick limit used to resume things in stoplag
#define TICK_LIMIT_TO_RUN 70
+/// Tick limit for MC while running
#define TICK_LIMIT_MC 70
-#define TICK_LIMIT_MC_INIT_DEFAULT 98
+/// Tick limit while initializing
+#define TICK_LIMIT_MC_INIT_DEFAULT (100 - TICK_BYOND_RESERVE)
-#define TICK_USAGE world.tick_usage //for general usage
-#define TICK_USAGE_REAL world.tick_usage //to be used where the result isn't checked
+/// for general usage of tick_usage
+#define TICK_USAGE world.tick_usage
+/// to be used where the result isn't checked
+#define TICK_USAGE_REAL world.tick_usage
+/// Returns true if tick_usage is above the limit
#define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit )
+/// runs stoplag if tick_usage is above the limit
#define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 )
+/// Returns true if tick usage is above 95, for high priority usage
#define TICK_CHECK_HIGH_PRIORITY ( TICK_USAGE > 95 )
+/// runs stoplag if tick_usage is above 95, for high priority usage
#define CHECK_TICK_HIGH_PRIORITY ( TICK_CHECK_HIGH_PRIORITY? stoplag() : 0 )
diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm
index f4a30cd482..eccae15bff 100644
--- a/code/__DEFINES/layers_planes.dm
+++ b/code/__DEFINES/layers_planes.dm
@@ -89,6 +89,8 @@
#define MASSIVE_OBJ_LAYER 11
#define POINT_LAYER 12
+#define CHAT_LAYER 12.1
+
#define EMISSIVE_BLOCKER_PLANE 12
#define EMISSIVE_BLOCKER_LAYER 12
#define EMISSIVE_BLOCKER_RENDER_TARGET "*EMISSIVE_BLOCKER_PLANE"
diff --git a/code/__DEFINES/materials.dm b/code/__DEFINES/materials.dm
index 89553d9c6c..e2ae22345f 100644
--- a/code/__DEFINES/materials.dm
+++ b/code/__DEFINES/materials.dm
@@ -7,5 +7,5 @@
/// Flag for atoms, this flag ensures it isn't re-colored by materials. Useful for snowflake icons such as default toolboxes.
#define MATERIAL_COLOR (1<<0)
#define MATERIAL_ADD_PREFIX (1<<1)
-#define MATERIAL_NO_EFFECTS (1<<2)
+#define MATERIAL_EFFECTS (1<<2)
#define MATERIAL_AFFECT_STATISTICS (1<<3)
\ No newline at end of file
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 37633ae52f..8bc8c8bebe 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -515,3 +515,17 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define NIGHTSHIFT_AREA_NONE 4 //default/highest.
#define UNTIL(X) while(!(X)) stoplag()
+
+
+//Scavenging element defines for special loot "events".
+#define SCAVENGING_FOUND_NOTHING "found_nothing"
+#define SCAVENGING_SPAWN_MOUSE "spawn_mouse"
+#define SCAVENGING_SPAWN_MICE "spawn_mice"
+#define SCAVENGING_SPAWN_TOM "spawn_tom_the_mouse"
+
+//Scavenging element defines for ckey/mind restrictions.
+#define NO_LOOT_RESTRICTION 0
+#define LOOT_RESTRICTION_MIND 1
+#define LOOT_RESTRICTION_CKEY 2
+#define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile.
+#define LOOT_RESTRICTION_CKEY_PILE 4 //Idem
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index d78de86d25..8284f66f50 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -52,3 +52,4 @@
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
#define ORGAN_VITAL (1<<4) //Currently only the brain
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
+#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index cadc1113c5..3abef3a61c 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -132,8 +132,15 @@
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
-
-
+// SSair run section
+#define SSAIR_PIPENETS 1
+#define SSAIR_ATMOSMACHINERY 2
+#define SSAIR_REACTQUEUE 3
+#define SSAIR_EXCITEDGROUPS 4
+#define SSAIR_HIGHPRESSURE 5
+#define SSAIR_HOTSPOTS 6
+#define SSAIR_SUPERCONDUCTIVITY 7
+#define SSAIR_REBUILD_PIPENETS 8
#define COMPILE_OVERLAYS(A)\
if (TRUE) {\
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 38e25b04c5..bcfaa1bed2 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -88,6 +88,7 @@
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL()
+ INVOKE_ASYNC(GLOBAL_PROC, /proc/setupGenetics)
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
@@ -113,3 +114,25 @@
UNTIL(C.flags_1 & INITIALIZED_1) //we want to make sure the value is calculated and not null.
GLOB.coin_values[path] = C.value
qdel(C)
+
+/proc/setupGenetics()
+ var/list/mutations = subtypesof(/datum/mutation/human)
+ shuffle_inplace(mutations)
+ for(var/A in subtypesof(/datum/generecipe))
+ var/datum/generecipe/GR = A
+ GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result)
+ for(var/i in 1 to LAZYLEN(mutations))
+ var/path = mutations[i] //byond gets pissy when we do it in one line
+ var/datum/mutation/human/B = new path ()
+ B.alias = "Mutation #[i]"
+ GLOB.all_mutations[B.type] = B
+ GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks)
+ if(B.locked)
+ continue
+ if(B.quality == POSITIVE)
+ GLOB.good_mutations |= B
+ else if(B.quality == NEGATIVE)
+ GLOB.bad_mutations |= B
+ else if(B.quality == MINOR_NEGATIVE)
+ GLOB.not_good_mutations |= B
+ CHECK_TICK
\ No newline at end of file
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index d93a89a179..e69052ad8d 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -317,7 +317,7 @@ GLOBAL_LIST_EMPTY(species_list)
else
return "unknown"
-/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = 0)
+/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = FALSE, resume_time = 0 SECONDS)
if(!user || !target)
return 0
var/user_loc = user.loc
@@ -336,10 +336,10 @@ GLOBAL_LIST_EMPTY(species_list)
var/endtime = world.time+time
var/starttime = world.time
. = 1
- while (world.time < endtime)
+ while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
- progbar.update(world.time - starttime)
+ progbar.update(world.time - starttime + resume_time)
if(QDELETED(user) || QDELETED(target))
. = 0
break
@@ -371,7 +371,7 @@ GLOBAL_LIST_EMPTY(species_list)
checked_health["health"] = health
return ..()
-/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE))
+/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE), resume_time = 0 SECONDS)
if(!user)
return 0
var/atom/Tloc = null
@@ -400,10 +400,10 @@ GLOBAL_LIST_EMPTY(species_list)
var/starttime = world.time
. = 1
var/mob/living/L = isliving(user) && user //evals to last thing eval'd
- while (world.time < endtime)
+ while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
- progbar.update(world.time - starttime)
+ progbar.update(world.time - starttime + resume_time)
if(drifting && !user.inertia_dir)
drifting = 0
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index af483bf888..b039e6d114 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -33,3 +33,5 @@ GLOBAL_VAR(bible_icon_state)
GLOBAL_VAR(bible_item_state)
GLOBAL_VAR(holy_weapon_type)
GLOBAL_VAR(holy_armor_type)
+
+GLOBAL_VAR_INIT(internal_tick_usage, 0.2 * world.tick_lag)
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 8772fac5af..db828539af 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -36,6 +36,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/sleep_delta = 1
+ ///Only run ticker subsystems for the next n ticks.
+ var/skip_ticks = 0
+
var/make_runtime = 0
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
@@ -335,7 +338,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
new/datum/controller/failsafe() // (re)Start the failsafe.
//now do the actual stuff
- if (!queue_head || !(iteration % 3))
+ if (!skip_ticks)
var/checking_runlevel = current_runlevel
if(cached_runlevel != checking_runlevel)
//resechedule subsystems
@@ -381,6 +384,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
iteration++
last_run = world.time
+ if (skip_ticks)
+ skip_ticks--
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
current_ticklimit = TICK_LIMIT_RUNNING
if (processing * sleep_delta <= world.tick_lag)
@@ -444,10 +449,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
while (queue_node)
if (ran && TICK_USAGE > TICK_LIMIT_RUNNING)
break
-
queue_node_flags = queue_node.flags
queue_node_priority = queue_node.queued_priority
+ if (!(queue_node_flags & SS_TICKER) && skip_ticks)
+ queue_node = queue_node.queue_next
+ continue
//super special case, subsystems where we can't make them pause mid way through
//if we can't run them this tick (without going over a tick)
//we bump up their priority and attempt to run them next tick
@@ -455,14 +462,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// in those cases, so we just let them run)
if (queue_node_flags & SS_NO_TICK_CHECK)
if (queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker)
- queue_node.queued_priority += queue_priority_count * 0.1
- queue_priority_count -= queue_node_priority
- queue_priority_count += queue_node.queued_priority
- current_tick_budget -= queue_node_priority
- queue_node = queue_node.queue_next
+ if (!(queue_node_flags & SS_BACKGROUND))
+ queue_node.queued_priority += queue_priority_count * 0.1
+ queue_priority_count -= queue_node_priority
+ queue_priority_count += queue_node.queued_priority
+ current_tick_budget -= queue_node_priority
+ queue_node = queue_node.queue_next
continue
- if ((queue_node_flags & SS_BACKGROUND) && !bg_calc)
+ if (!bg_calc && (queue_node_flags & SS_BACKGROUND))
current_tick_budget = queue_priority_count_bg
bg_calc = TRUE
@@ -515,7 +523,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
queue_node.paused_ticks = 0
queue_node.paused_tick_usage = 0
- if (queue_node_flags & SS_BACKGROUND) //update our running total
+ if (bg_calc) //update our running total
queue_priority_count_bg -= queue_node_priority
else
queue_priority_count -= queue_node_priority
@@ -583,14 +591,19 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
log_world("MC: SoftReset: Finished.")
. = 1
+/// Warns us that the end of tick byond map_update will be laggier then normal, so that we can just skip running subsystems this tick.
+/datum/controller/master/proc/laggy_byond_map_update_incoming()
+ if (!skip_ticks)
+ skip_ticks = 1
/datum/controller/master/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
- stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))")
- stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])"))
+ stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)")
+ stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])"))
+
/datum/controller/master/StartLoadingMap()
//disallow more than one map to load at once, multithreading it will just cause race conditions
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index 13facc7666..d8c7724333 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -1,11 +1,3 @@
-#define SSAIR_PIPENETS 1
-#define SSAIR_ATMOSMACHINERY 2
-#define SSAIR_REACTQUEUE 3
-#define SSAIR_EXCITEDGROUPS 4
-#define SSAIR_HIGHPRESSURE 5
-#define SSAIR_HOTSPOTS 6
-#define SSAIR_SUPERCONDUCTIVITY 7
-
SUBSYSTEM_DEF(air)
name = "Atmospherics"
init_order = INIT_ORDER_AIR
@@ -20,6 +12,7 @@ SUBSYSTEM_DEF(air)
var/cost_hotspots = 0
var/cost_superconductivity = 0
var/cost_pipenets = 0
+ var/cost_rebuilds = 0
var/cost_atmos_machinery = 0
var/list/excited_groups = list()
@@ -27,6 +20,7 @@ SUBSYSTEM_DEF(air)
var/list/turf_react_queue = list()
var/list/hotspots = list()
var/list/networks = list()
+ var/list/pipenets_needing_rebuilt = list()
var/list/obj/machinery/atmos_machinery = list()
var/list/pipe_init_dirs_cache = list()
@@ -39,7 +33,7 @@ SUBSYSTEM_DEF(air)
var/list/currentrun = list()
- var/currentpart = SSAIR_PIPENETS
+ var/currentpart = SSAIR_REBUILD_PIPENETS
var/map_loading = TRUE
var/list/queued_for_activation
@@ -52,6 +46,7 @@ SUBSYSTEM_DEF(air)
msg += "HS:[round(cost_hotspots,1)]|"
msg += "SC:[round(cost_superconductivity,1)]|"
msg += "PN:[round(cost_pipenets,1)]|"
+ msg += "RB:[round(cost_rebuilds,1)]|"
msg += "AM:[round(cost_atmos_machinery,1)]"
msg += "} "
msg += "AT:[active_turfs.len]|"
@@ -77,6 +72,18 @@ SUBSYSTEM_DEF(air)
/datum/controller/subsystem/air/fire(resumed = 0)
var/timer = TICK_USAGE_REAL
+ if(currentpart == SSAIR_REBUILD_PIPENETS)
+ var/list/pipenet_rebuilds = pipenets_needing_rebuilt
+ for(var/thing in pipenet_rebuilds)
+ var/obj/machinery/atmospherics/AT = thing
+ AT.build_network()
+ cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ pipenets_needing_rebuilt.Cut()
+ if(state != SS_RUNNING)
+ return
+ resumed = FALSE
+ currentpart = SSAIR_PIPENETS
+
if(currentpart == SSAIR_PIPENETS || !resumed)
process_pipenets(resumed)
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
@@ -137,9 +144,7 @@ SUBSYSTEM_DEF(air)
if(state != SS_RUNNING)
return
resumed = 0
- currentpart = SSAIR_PIPENETS
-
-
+ currentpart = SSAIR_REBUILD_PIPENETS
/datum/controller/subsystem/air/proc/process_pipenets(resumed = 0)
if (!resumed)
@@ -156,6 +161,9 @@ SUBSYSTEM_DEF(air)
if(MC_TICK_CHECK)
return
+/datum/controller/subsystem/air/proc/add_to_rebuild_queue(atmos_machine)
+ if(istype(atmos_machine, /obj/machinery/atmospherics))
+ pipenets_needing_rebuilt += atmos_machine
/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0)
var/seconds = wait * 0.1
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index 35feab6648..c1644df9c9 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -16,7 +16,6 @@ SUBSYSTEM_DEF(atoms)
/datum/controller/subsystem/atoms/Initialize(timeofday)
GLOB.fire_overlay.appearance_flags = RESET_COLOR
- setupGenetics() //to set the mutations' sequence.
initialized = INITIALIZATION_INNEW_MAPLOAD
InitializeAtoms()
return ..()
@@ -107,28 +106,6 @@ SUBSYSTEM_DEF(atoms)
old_initialized = SSatoms.old_initialized
BadInitializeCalls = SSatoms.BadInitializeCalls
-/datum/controller/subsystem/atoms/proc/setupGenetics()
- var/list/mutations = subtypesof(/datum/mutation/human)
- shuffle_inplace(mutations)
- for(var/A in subtypesof(/datum/generecipe))
- var/datum/generecipe/GR = A
- GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result)
- for(var/i in 1 to LAZYLEN(mutations))
- var/path = mutations[i] //byond gets pissy when we do it in one line
- var/datum/mutation/human/B = new path ()
- B.alias = "Mutation #[i]"
- GLOB.all_mutations[B.type] = B
- GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks)
- if(B.locked)
- continue
- if(B.quality == POSITIVE)
- GLOB.good_mutations |= B
- else if(B.quality == NEGATIVE)
- GLOB.bad_mutations |= B
- else if(B.quality == MINOR_NEGATIVE)
- GLOB.not_good_mutations |= B
- CHECK_TICK
-
/datum/controller/subsystem/atoms/proc/InitLog()
. = ""
for(var/path in BadInitializeCalls)
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 89155cefb3..526e4b98e3 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -42,6 +42,13 @@ SUBSYSTEM_DEF(mapping)
var/stat_map_name = "Loading..."
+ /// Lookup list for random generated IDs.
+ var/list/random_generated_ids_by_original = list()
+ /// next id for separating obfuscated ids.
+ var/obfuscation_next_id = 1
+ /// "secret" key
+ var/obfuscation_secret
+
//dlete dis once #39770 is resolved
/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
if(!config)
@@ -52,6 +59,10 @@ SUBSYSTEM_DEF(mapping)
#endif
stat_map_name = config.map_name
+/datum/controller/subsystem/mapping/PreInit()
+ if(!obfuscation_secret)
+ obfuscation_secret = md5(GUID()) //HAH! Guess this!
+
/datum/controller/subsystem/mapping/Initialize(timeofday)
HACK_LoadMapConfig()
if(initialized)
@@ -568,3 +579,15 @@ GLOBAL_LIST_EMPTY(the_station_areas)
LM.load()
if(GLOB.stationroom_landmarks.len)
seedStation() //I'm sure we can trust everyone not to insert a 1x1 rooms which loads a landmark which loads a landmark which loads a la...
+
+/**
+ * Generates an obfuscated but constant id for an original id for cases where you don't want players codediving for an id.
+ * WARNING: MAKE SURE PLAYERS ARE NOT ABLE TO ACCESS THIS. To save performance, it's just secret + an incrementing number. Very guessable if you know what the secret is.
+ */
+/datum/controller/subsystem/mapping/proc/get_obfuscated_id(original, id_type = "GENERAL")
+ if(!original)
+ return //no.
+ var/key = "[original]%[id_type]"
+ if(random_generated_ids_by_original[key])
+ return random_generated_ids_by_original[key]
+ . = random_generated_ids_by_original[key] = "[obfuscation_secret]%[obfuscation_next_id++]"
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index 428f355c31..3f71d192e3 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -150,6 +150,8 @@
friend_talk(message)
/mob/camera/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
+ if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
+ create_chat_message(speaker, message_language, raw_message, spans, message_mode)
to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source))
/mob/camera/imaginary_friend/proc/friend_talk(message)
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
new file mode 100644
index 0000000000..cbcb34ac5e
--- /dev/null
+++ b/code/datums/chatmessage.dm
@@ -0,0 +1,236 @@
+#define CHAT_MESSAGE_SPAWN_TIME 0.2 SECONDS
+#define CHAT_MESSAGE_LIFESPAN 5 SECONDS
+#define CHAT_MESSAGE_EOL_FADE 0.7 SECONDS
+#define CHAT_MESSAGE_EXP_DECAY 0.7 // Messages decay at pow(factor, idx in stack)
+#define CHAT_MESSAGE_HEIGHT_DECAY 0.9 // Increase message decay based on the height of the message
+#define CHAT_MESSAGE_APPROX_LHEIGHT 11 // Approximate height in pixels of an 'average' line, used for height decay
+#define CHAT_MESSAGE_WIDTH 96 // pixels
+#define CHAT_MESSAGE_MAX_LENGTH 110 // characters
+#define WXH_TO_HEIGHT(x) text2num(copytext((x), findtextEx((x), "x") + 1)) // thanks lummox
+
+/**
+ * # Chat Message Overlay
+ *
+ * Datum for generating a message overlay on the map
+ */
+/datum/chatmessage
+ /// The visual element of the chat messsage
+ var/image/message
+ /// The location in which the message is appearing
+ var/atom/message_loc
+ /// The client who heard this message
+ var/client/owned_by
+ /// Contains the scheduled destruction time
+ var/scheduled_destruction
+ /// Contains the approximate amount of lines for height decay
+ var/approx_lines
+
+/**
+ * Constructs a chat message overlay
+ *
+ * Arguments:
+ * * text - The text content of the overlay
+ * * target - The target atom to display the overlay at
+ * * owner - The mob that owns this overlay, only this mob will be able to view it
+ * * extra_classes - Extra classes to apply to the span that holds the text
+ * * lifespan - The lifespan of the message in deciseconds
+ */
+/datum/chatmessage/New(text, atom/target, mob/owner, list/extra_classes = null, lifespan = CHAT_MESSAGE_LIFESPAN)
+ . = ..()
+ if (!istype(target))
+ CRASH("Invalid target given for chatmessage")
+ if(QDELETED(owner) || !istype(owner) || !owner.client)
+ stack_trace("/datum/chatmessage created with [isnull(owner) ? "null" : "invalid"] mob owner")
+ qdel(src)
+ return
+ INVOKE_ASYNC(src, .proc/generate_image, text, target, owner, extra_classes, lifespan)
+
+/datum/chatmessage/Destroy()
+ if (owned_by)
+ if (owned_by.seen_messages)
+ LAZYREMOVEASSOC(owned_by.seen_messages, message_loc, src)
+ owned_by.images.Remove(message)
+ owned_by = null
+ message_loc = null
+ message = null
+ return ..()
+
+/**
+ * Generates a chat message image representation
+ *
+ * Arguments:
+ * * text - The text content of the overlay
+ * * target - The target atom to display the overlay at
+ * * owner - The mob that owns this overlay, only this mob will be able to view it
+ * * extra_classes - Extra classes to apply to the span that holds the text
+ * * lifespan - The lifespan of the message in deciseconds
+ */
+/datum/chatmessage/proc/generate_image(text, atom/target, mob/owner, list/extra_classes, lifespan)
+ // Register client who owns this message
+ owned_by = owner.client
+ RegisterSignal(owned_by, COMSIG_PARENT_QDELETING, .proc/qdel, src)
+
+ // Clip message
+ var/maxlen = owned_by.prefs.max_chat_length
+ if (length_char(text) > maxlen)
+ text = copytext_char(text, 1, maxlen + 1) + "..." // BYOND index moment
+
+ // Calculate target color if not already present
+ if (!target.chat_color || target.chat_color_name != target.name)
+ target.chat_color = colorize_string(target.name)
+ target.chat_color_darkened = colorize_string(target.name, 0.85, 0.85)
+ target.chat_color_name = target.name
+
+ // Get rid of any URL schemes that might cause BYOND to automatically wrap something in an anchor tag
+ var/static/regex/url_scheme = new(@"[A-Za-z][A-Za-z0-9+-\.]*:\/\/", "g")
+ text = replacetext(text, url_scheme, "")
+
+ // Reject whitespace
+ var/static/regex/whitespace = new(@"^\s*$")
+ if (whitespace.Find(text))
+ qdel(src)
+ return
+
+ // Non mobs speakers can be small
+ if (!ismob(target))
+ extra_classes |= "small"
+
+ // Append radio icon if from a virtual speaker
+ if (extra_classes.Find("virtual-speaker"))
+ var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio")
+ text = "\icon[r_icon] " + text
+
+ // We dim italicized text to make it more distinguishable from regular text
+ var/tgt_color = extra_classes.Find("italics") ? target.chat_color_darkened : target.chat_color
+
+ // Approximate text height
+ // Note we have to replace HTML encoded metacharacters otherwise MeasureText will return a zero height
+ // BYOND Bug #2563917
+ // Construct text
+ var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
+ var/complete_text = "[text]"
+ var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
+ approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
+
+ // Translate any existing messages upwards, apply exponential decay factors to timers
+ message_loc = target
+ if (owned_by.seen_messages)
+ var/idx = 1
+ var/combined_height = approx_lines
+ for(var/msg in owned_by.seen_messages[message_loc])
+ var/datum/chatmessage/m = msg
+ animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME)
+ combined_height += m.approx_lines
+ var/sched_remaining = m.scheduled_destruction - world.time
+ if (sched_remaining > CHAT_MESSAGE_SPAWN_TIME)
+ var/remaining_time = (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height)
+ m.scheduled_destruction = world.time + remaining_time
+ addtimer(CALLBACK(m, .proc/end_of_life), remaining_time, TIMER_UNIQUE|TIMER_OVERRIDE)
+
+ // Build message image
+ message = image(loc = message_loc, layer = CHAT_LAYER)
+ message.plane = GAME_PLANE
+ message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
+ message.alpha = 0
+ message.pixel_y = owner.bound_height * 0.95
+ message.maptext_width = CHAT_MESSAGE_WIDTH
+ message.maptext_height = mheight
+ message.maptext_x = (CHAT_MESSAGE_WIDTH - owner.bound_width) * -0.5
+ message.maptext = complete_text
+
+ // View the message
+ LAZYADDASSOC(owned_by.seen_messages, message_loc, src)
+ owned_by.images |= message
+ animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME)
+
+ // Prepare for destruction
+ scheduled_destruction = world.time + (lifespan - CHAT_MESSAGE_EOL_FADE)
+ addtimer(CALLBACK(src, .proc/end_of_life), lifespan - CHAT_MESSAGE_EOL_FADE, TIMER_UNIQUE|TIMER_OVERRIDE)
+
+/**
+ * Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion
+ */
+/datum/chatmessage/proc/end_of_life(fadetime = CHAT_MESSAGE_EOL_FADE)
+ animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL)
+ QDEL_IN(src, fadetime)
+
+/**
+ * Creates a message overlay at a defined location for a given speaker
+ *
+ * Arguments:
+ * * speaker - The atom who is saying this message
+ * * message_language - The language that the message is said in
+ * * raw_message - The text content of the message
+ * * spans - Additional classes to be added to the message
+ * * message_mode - Bitflags relating to the mode of the message
+ */
+/mob/proc/create_chat_message(atom/movable/speaker, datum/language/message_language, raw_message, list/spans, message_mode)
+ // Ensure the list we are using, if present, is a copy so we don't modify the list provided to us
+ spans = spans?.Copy()
+
+ // Check for virtual speakers (aka hearing a message through a radio)
+ var/atom/movable/originalSpeaker = speaker
+ if (istype(speaker, /atom/movable/virtualspeaker))
+ var/atom/movable/virtualspeaker/v = speaker
+ speaker = v.source
+ spans |= "virtual-speaker"
+
+ // Ignore virtual speaker (most often radio messages) from ourself
+ if (originalSpeaker != src && speaker == src)
+ return
+
+ // Display visual above source
+ new /datum/chatmessage(lang_treat(speaker, message_language, raw_message, spans, null, TRUE), speaker, src, spans)
+
+
+// Tweak these defines to change the available color ranges
+#define CM_COLOR_SAT_MIN 0.6
+#define CM_COLOR_SAT_MAX 0.7
+#define CM_COLOR_LUM_MIN 0.65
+#define CM_COLOR_LUM_MAX 0.75
+
+/**
+ * Gets a color for a name, will return the same color for a given string consistently within a round.atom
+ *
+ * Note that this proc aims to produce pastel-ish colors using the HSL colorspace. These seem to be favorable for displaying on the map.
+ *
+ * Arguments:
+ * * name - The name to generate a color for
+ * * sat_shift - A value between 0 and 1 that will be multiplied against the saturation
+ * * lum_shift - A value between 0 and 1 that will be multiplied against the luminescence
+ */
+/datum/chatmessage/proc/colorize_string(name, sat_shift = 1, lum_shift = 1)
+ // seed to help randomness
+ var/static/rseed = rand(1,26)
+
+ // get hsl using the selected 6 characters of the md5 hash
+ var/hash = copytext(md5(name + GLOB.round_id), rseed, rseed + 6)
+ var/h = hex2num(copytext(hash, 1, 3)) * (360 / 255)
+ var/s = (hex2num(copytext(hash, 3, 5)) >> 2) * ((CM_COLOR_SAT_MAX - CM_COLOR_SAT_MIN) / 63) + CM_COLOR_SAT_MIN
+ var/l = (hex2num(copytext(hash, 5, 7)) >> 2) * ((CM_COLOR_LUM_MAX - CM_COLOR_LUM_MIN) / 63) + CM_COLOR_LUM_MIN
+
+ // adjust for shifts
+ s *= clamp(sat_shift, 0, 1)
+ l *= clamp(lum_shift, 0, 1)
+
+ // convert to rgb
+ var/h_int = round(h/60) // mapping each section of H to 60 degree sections
+ var/c = (1 - abs(2 * l - 1)) * s
+ var/x = c * (1 - abs((h / 60) % 2 - 1))
+ var/m = l - c * 0.5
+ x = (x + m) * 255
+ c = (c + m) * 255
+ m *= 255
+ switch(h_int)
+ if(0)
+ return "#[num2hex(c, 2)][num2hex(x, 2)][num2hex(m, 2)]"
+ if(1)
+ return "#[num2hex(x, 2)][num2hex(c, 2)][num2hex(m, 2)]"
+ if(2)
+ return "#[num2hex(m, 2)][num2hex(c, 2)][num2hex(x, 2)]"
+ if(3)
+ return "#[num2hex(m, 2)][num2hex(x, 2)][num2hex(c, 2)]"
+ if(4)
+ return "#[num2hex(x, 2)][num2hex(m, 2)][num2hex(c, 2)]"
+ if(5)
+ return "#[num2hex(c, 2)][num2hex(m, 2)][num2hex(x, 2)]"
diff --git a/code/datums/components/archaeology.dm b/code/datums/components/archaeology.dm
deleted file mode 100644
index b5740650e9..0000000000
--- a/code/datums/components/archaeology.dm
+++ /dev/null
@@ -1,95 +0,0 @@
-/datum/component/archaeology
- dupe_mode = COMPONENT_DUPE_UNIQUE
- var/list/archdrops = list(/obj/item/bikehorn = list(ARCH_PROB = 100, ARCH_MAXDROP = 1)) // honk~
- var/prob2drop
- var/dug
- var/datum/callback/callback
-
-/datum/component/archaeology/Initialize(list/_archdrops = list(), datum/callback/_callback)
- archdrops = _archdrops
- for(var/i in archdrops)
- if(isnull(archdrops[i][ARCH_MAXDROP]))
- archdrops[i][ARCH_MAXDROP] = 1
- stack_trace("ARCHAEOLOGY WARNING: [parent] contained a null max_drop value in [i].")
- if(isnull(archdrops[i][ARCH_PROB]))
- archdrops[i][ARCH_PROB] = 100
- stack_trace("ARCHAEOLOGY WARNING: [parent] contained a null probability value in [i].")
- callback = _callback
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY,.proc/Dig)
- RegisterSignal(parent, COMSIG_ATOM_EX_ACT, .proc/BombDig)
- RegisterSignal(parent, COMSIG_ATOM_SING_PULL, .proc/SingDig)
-
-/datum/component/archaeology/InheritComponent(datum/component/archaeology/A, i_am_original)
- var/list/other_archdrops = A.archdrops
- var/list/_archdrops = archdrops
- for(var/I in other_archdrops)
- _archdrops[I] += other_archdrops[I]
-
-/datum/component/archaeology/proc/Dig(datum/source, obj/item/I, mob/living/user)
- if(dug)
- to_chat(user, "Looks like someone has dug here already.")
- return
-
- if(!isturf(user.loc))
- return
-
- if(I.tool_behaviour == TOOL_SHOVEL || I.tool_behaviour == TOOL_MINING)
- to_chat(user, "You start digging...")
-
- if(I.use_tool(parent, user, 40, volume=50))
- to_chat(user, "You dig a hole.")
- gets_dug()
- dug = TRUE
- SSblackbox.record_feedback("tally", "pick_used_mining", 1, I.type)
- return COMPONENT_NO_AFTERATTACK
-
-/datum/component/archaeology/proc/gets_dug()
- if(dug)
- return
- else
- var/turf/open/OT = get_turf(parent)
- for(var/thing in archdrops)
- var/maxtodrop = archdrops[thing][ARCH_MAXDROP]
- for(var/i in 1 to maxtodrop)
- if(prob(archdrops[thing][ARCH_PROB])) // can't win them all!
- new thing(OT)
-
- if(isopenturf(OT))
- if(OT.postdig_icon_change)
- if(istype(OT, /turf/open/floor/plating/asteroid/) && !OT.postdig_icon)
- var/turf/open/floor/plating/asteroid/AOT = parent
- AOT.icon_plating = "[AOT.environment_type]_dug"
- AOT.icon_state = "[AOT.environment_type]_dug"
- else
- if(isplatingturf(OT))
- var/turf/open/floor/plating/POT = parent
- POT.icon_plating = "[POT.postdig_icon]"
- POT.icon_state = "[OT.postdig_icon]"
-
- if(OT.slowdown) //Things like snow slow you down until you dig them.
- OT.slowdown = 0
- dug = TRUE
- if(callback)
- callback.Invoke()
-
-/datum/component/archaeology/proc/SingDig(datum/source, S, current_size)
- switch(current_size)
- if(STAGE_THREE)
- if(prob(30))
- gets_dug()
- if(STAGE_FOUR)
- if(prob(50))
- gets_dug()
- else
- if(current_size >= STAGE_FIVE && prob(70))
- gets_dug()
-
-/datum/component/archaeology/proc/BombDig(datum/source, severity, target)
- switch(severity)
- if(3)
- return
- if(2)
- if(prob(20))
- gets_dug()
- if(1)
- gets_dug()
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index 9eb3fcaaea..14ab751d2b 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -260,6 +260,15 @@
subcategory = CAT_TOOL
category = CAT_MISC
+/datum/crafting_recipe/electrochromatic_kit
+ name = "Electrochromatic Kit"
+ result = /obj/item/electronics/electrochromatic_kit
+ reqs = list(/obj/item/stack/sheet/metal = 1,
+ /obj/item/stack/cable_coil = 1)
+ time = 5
+ subcategory = CAT_TOOL
+ category = CAT_MISC
+
////////////
//Vehicles//
////////////
diff --git a/code/datums/components/mirage_border.dm b/code/datums/components/mirage_border.dm
index de4425e208..56b41533f5 100644
--- a/code/datums/components/mirage_border.dm
+++ b/code/datums/components/mirage_border.dm
@@ -39,4 +39,5 @@
/obj/effect/abstract/mirage_holder
name = "Mirage holder"
anchored = TRUE
+ plane = PLANE_SPACE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
diff --git a/code/datums/elements/mob_holder.dm b/code/datums/elements/mob_holder.dm
index a5c6e2725d..d770e0f30d 100644
--- a/code/datums/elements/mob_holder.dm
+++ b/code/datums/elements/mob_holder.dm
@@ -164,7 +164,7 @@
release()
/obj/item/clothing/head/mob_holder/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
- if(!ishuman(M)) //monkeys holding monkeys holding monkeys...
+ if(M == held_mob || !ishuman(M)) //monkeys holding monkeys holding monkeys...
return FALSE
return ..()
diff --git a/code/datums/elements/scavenging.dm b/code/datums/elements/scavenging.dm
new file mode 100644
index 0000000000..1993005be7
--- /dev/null
+++ b/code/datums/elements/scavenging.dm
@@ -0,0 +1,215 @@
+ /*
+ * Scavenging element. Its scope shouldn't elude your imagination.
+ * Basically loot piles that can be searched through for some items.
+ * In my opinion, these are more engaging than normal maintenance loot spawners.
+ * The loot doesn't have to be strictly made of items and objects, you could also use it to invoke some "events"
+ * such as mice, rats, an halloween spook, persistent relics, traps, etcetera, go wild.
+ */
+/datum/element/scavenging
+ element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
+ id_arg_index = 3
+
+ var/list/loot_left_per_atom = list() //loot left per attached atom.
+ var/list/loot_table //pickweight list of available loot.
+ var/list/unique_loot //limited loot, once the associated value reaches zero, its key is removed from loot_table
+ var/scavenge_time = 12 SECONDS //how much time it takes
+ var/can_use_hands = TRUE //bare handed scavenge time multiplier. If set to zero, only tools are usable.
+ var/list/tool_types //which tool types the player can use instead of scavenging by hand, associated value is their speed.
+ var/del_atom_on_depletion = FALSE //Will the atom be deleted when there is no loot left?
+ var/list/search_texts = list("starts searching through", "start searching through", "You hear rummaging...")
+ var/loot_restriction = NO_LOOT_RESTRICTION
+ var/maximum_loot_per_player = 1 //only relevant if there is a restriction.
+ var/list/scavenger_restriction_list //used for restrictions.
+
+ var/mean_loot_weight = 0
+ var/list/progress_per_atom = list() //seconds of ditched progress per atom, used to resume the work instead of starting over.
+ var/static/list/players_busy_scavenging = list() //players already busy scavenging.
+
+/datum/element/scavenging/Attach(atom/target, amount = 5, list/loot, list/unique, time = 12 SECONDS, hands = TRUE, list/tools, list/texts, \
+ del_deplete = FALSE, restriction = NO_LOOT_RESTRICTION, max_per_player = 1)
+ . = ..()
+ if(. == ELEMENT_INCOMPATIBLE || !length(loot) || !amount || !istype(target) || isarea(target))
+ return ELEMENT_INCOMPATIBLE
+ loot_left_per_atom[target] = amount
+ if(!loot_table)
+ loot_table = loot
+ for(var/A in loot_table) //tally the list weights
+ mean_loot_weight += loot_table[A]
+ mean_loot_weight /= length(loot_table)
+ if(!unique_loot)
+ unique_loot = unique || list()
+ scavenge_time = time
+ can_use_hands = hands
+ tool_types = tools
+ if(texts)
+ search_texts = texts
+ del_atom_on_depletion = del_deplete
+ loot_restriction = restriction
+ maximum_loot_per_player = max_per_player
+ if(can_use_hands)
+ RegisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW), .proc/scavenge_barehanded)
+ if(tool_types)
+ RegisterSignal(target, COMSIG_PARENT_ATTACKBY, .proc/scavenge_tool)
+ RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
+
+/datum/element/scavenging/Detach(atom/target)
+ . = ..()
+ loot_left_per_atom -= target
+ progress_per_atom -= target
+ if(maximum_loot_per_player == LOOT_RESTRICTION_MIND_PILE || maximum_loot_per_player == LOOT_RESTRICTION_CKEY_PILE)
+ maximum_loot_per_player -= target
+ UnregisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
+
+/datum/element/scavenging/proc/on_examine(atom/source, mob/user, list/examine_list)
+ var/methods = tool_types.Copy()
+ if(can_use_hands)
+ methods += list("bare handed")
+ if(!length(methods))
+ return
+ var/text = english_list(methods, "", " or ")
+ examine_list += "Looks like [source.p_they()] can be scavenged [length(tool_types) ? "with" : ""][length(methods == 1) ? "" : "either "][length(tool_types) ? "a " : ""][text]"
+
+/datum/element/scavenging/proc/scavenge_barehanded(atom/source, mob/user)
+ scavenge(source, user, 1)
+ return COMPONENT_NO_ATTACK_HAND
+
+/datum/element/scavenging/proc/scavenge_tool(atom/source, obj/item/I, mob/user, params)
+ if(user.a_intent == INTENT_HARM || !I.tool_behaviour) //Robust trash disposal techniques!
+ return
+ var/speed_multi = tool_types[I.tool_behaviour]
+ if(!speed_multi)
+ return
+ scavenge(source, user, speed_multi)
+ return COMPONENT_NO_AFTERATTACK
+
+/// This proc has to be asynced (cough cough, do_after) in order to return the comsig values in time to stop the attack chain.
+/datum/element/scavenging/proc/scavenge(atom/source, mob/user, speed_multi = 1)
+ set waitfor = FALSE
+
+ if(players_busy_scavenging[user])
+ return
+ players_busy_scavenging[user] = TRUE
+ var/progress_done = progress_per_atom[source]
+ var/len_messages = length(search_texts)
+ var/msg_first_person
+ if(len_messages >= 2)
+ msg_first_person = "You [progress_done ? ", resume a ditched task and " : ""][search_texts[2]] [source]."
+ var/msg_blind
+ if(len_messages >= 3)
+ msg_blind = "[search_texts[3]]"
+ user.visible_message("[user] [search_texts[1]] [source].", msg_first_person, msg_blind)
+ if(do_after(user, scavenge_time * speed_multi, TRUE, source, TRUE, CALLBACK(src, .proc/set_progress, source, world.time), resume_time = progress_done * speed_multi))
+ spawn_loot(source, user)
+ players_busy_scavenging -= user
+
+/datum/element/scavenging/proc/set_progress(atom/source, start_time)
+ progress_per_atom[source] = world.time - start_time
+ return TRUE
+
+/datum/element/scavenging/proc/spawn_loot(atom/source, mob/user)
+ progress_per_atom -= source
+
+ var/loot = pickweight(loot_table)
+ var/special = TRUE
+ var/free = FALSE
+ if(!loot_left_per_atom[source])
+ to_chat(user, "Looks likes there is nothing worth of interest left in [source], what a shame...")
+ return
+
+ var/num_times = 0
+ switch(loot_restriction)
+ if(LOOT_RESTRICTION_MIND)
+ num_times = LAZYACCESS(scavenger_restriction_list, user.mind)
+ if(LOOT_RESTRICTION_CKEY)
+ num_times = LAZYACCESS(scavenger_restriction_list, user.ckey)
+ if(LOOT_RESTRICTION_MIND_PILE)
+ var/list/L = LAZYACCESS(scavenger_restriction_list, source)
+ if(L)
+ num_times = LAZYACCESS(L, user.mind)
+ if(LOOT_RESTRICTION_CKEY_PILE)
+ var/list/L = LAZYACCESS(scavenger_restriction_list, source)
+ if(L)
+ num_times = LAZYACCESS(L, user.ckey)
+ if(num_times >= maximum_loot_per_player)
+ to_chat(user, "You can't find anything else vaguely useful in [source]. Another set of eyes might, however.")
+ return
+
+ switch(loot) // TODO: datumize these out.
+ if(SCAVENGING_FOUND_NOTHING)
+ to_chat(user, "You found nothing, better luck next time.")
+ free = TRUE //doesn't consume the loot pile.
+ if(SCAVENGING_SPAWN_MOUSE)
+ var/nasty_rodent = pick("mouse", "rodent", "squeaky critter", "stupid pest", "annoying cable chewer", "nasty, ugly, evil, disease-ridden rodent")
+ to_chat(user, "You found something in [source]... no wait, that's just another [nasty_rodent].")
+ new /mob/living/simple_animal/mouse(source.loc)
+ if(SCAVENGING_SPAWN_MICE)
+ user.visible_message("A small gang of mice emerges from [source].", \
+ "You found something in [source]... no wait, that's just another- no wait, that's a lot of damn mice.")
+ for(var/i in 1 to rand(4, 6))
+ new /mob/living/simple_animal/mouse(source.loc)
+ if(SCAVENGING_SPAWN_TOM)
+ if(GLOB.tom_existed) //There can only be one.
+ to_chat(user, "You found nothing, better luck next time.")
+ free = TRUE
+ else
+ to_chat(user, "You found something in [source]... no wait, that's Tom, the mouse! What is he doing here?")
+ new /mob/living/simple_animal/mouse/brown/Tom(source.loc)
+ else
+ special = FALSE
+
+ if(!special) //generic loot. Nothing too strange like more loot spawners anyway.
+ var/atom/A = new loot(source.loc)
+ if(isitem(A) && !user.get_active_held_item())
+ user.put_in_hands(A)
+ var/rarity_append = "."
+ switch(loot_table[loot]/mean_loot_weight*100)
+ if(0 to 1)
+ rarity_append = "! AMAZING!"
+ if(1 to 2)
+ rarity_append = "! Woah!"
+ if(2 to 5)
+ rarity_append = ". Rare!"
+ if(5 to 10)
+ rarity_append = ". Great."
+ if(10 to 25)
+ rarity_append = ". Nice."
+ if(20 to 50)
+ rarity_append = ". Not bad."
+ to_chat(user, "You found something in [source]... it's \a [A][rarity_append]")
+
+ if(unique_loot[loot])
+ var/loot_left = --unique_loot[loot]
+ if(!loot_left)
+ loot_table -= loot
+ unique_loot -= loot
+ mean_loot_weight = 0
+ for(var/A in loot_table) //re-tally the list weights
+ mean_loot_weight += loot_table[A]
+ mean_loot_weight /= length(loot_table)
+
+ if(free)
+ return
+
+ --loot_left_per_atom[source]
+ if(del_atom_on_depletion && !loot_left_per_atom[source])
+ source.visible_message("[source] has been looted clean.")
+ qdel(source)
+ return
+
+ if(!loot_restriction)
+ return
+
+ LAZYINITLIST(scavenger_restriction_list)
+ switch(loot_restriction)
+ if(LOOT_RESTRICTION_MIND)
+ scavenger_restriction_list[user.mind]++
+ if(LOOT_RESTRICTION_CKEY)
+ scavenger_restriction_list[user.ckey]++
+ if(LOOT_RESTRICTION_MIND_PILE)
+ LAZYINITLIST(scavenger_restriction_list[source])
+ var/list/L = scavenger_restriction_list[source]
+ L[user.mind]++
+ if(LOOT_RESTRICTION_CKEY_PILE)
+ LAZYINITLIST(scavenger_restriction_list[source])
+ var/list/L = scavenger_restriction_list[source]
+ L[user.ckey]++
diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm
index d1b6b8bd0d..db9a84bb05 100644
--- a/code/datums/skills/_skill_holder.dm
+++ b/code/datums/skills/_skill_holder.dm
@@ -41,9 +41,7 @@
/datum/skill_holder/proc/get_skill_affinity(skill)
if(!ispath(skill))
CRASH("Invalid get_skill_affinity call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
- if(!skills)
- return 1
- var/affinity = skill_affinities[skill]
+ var/affinity = LAZYACCESS(skill_affinities, skill)
if(isnull(affinity))
return 1
return affinity
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index b71f51bd07..dbb6864028 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -50,6 +50,13 @@
var/list/blood_DNA
var/list/suit_fibers
+ /// Last name used to calculate a color for the chatmessage overlays
+ var/chat_color_name
+ /// Last color calculated for the the chatmessage overlays
+ var/chat_color
+ /// A luminescence-shifted value of the last color calculated for chatmessage overlays
+ var/chat_color_darkened
+
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -965,7 +972,7 @@ Proc for attack log creation, because really why not
for(var/x in materials)
var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
- if(!(material_flags & MATERIAL_NO_EFFECTS))
+ if(material_flags & MATERIAL_EFFECTS)
custom_material.on_applied(src, materials[custom_material] * multiplier * material_modifier, material_flags)
custom_materials[custom_material] += materials[x] * multiplier
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index ad3dd5d720..3a90707bbe 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -16,6 +16,9 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/machinery/button/Initialize(mapload, ndir = 0, built = 0)
+ if(istext(id) && mapload)
+ if(copytext(id, 1, 2) == "!")
+ id = SSmapping.get_obfuscated_id(id)
. = ..()
if(built)
setDir(ndir)
@@ -260,6 +263,11 @@
req_access = list()
id = 1
+/obj/machinery/button/electrochromatic
+ name = "window dim control"
+ desc = "Controls linked electrochromatic windows"
+ device_type = /obj/item/assembly/control/electrochromatic
+
/obj/item/wallframe/button
name = "button frame"
desc = "Used for building buttons."
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 24fd956677..c26c66a55f 100755
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -53,6 +53,11 @@
using_power = FALSE
update_icon()
+/obj/machinery/recharger/Exited(atom/movable/M, atom/newloc)
+ . = ..()
+ if(charging == M)
+ setCharging()
+
/obj/machinery/recharger/attackby(obj/item/G, mob/user, params)
if(istype(G, /obj/item/wrench))
if(charging)
@@ -111,13 +116,11 @@
charging.update_icon()
charging.forceMove(drop_location())
user.put_in_hands(charging)
- setCharging(null)
/obj/machinery/recharger/attack_tk(mob/user)
if(charging)
charging.update_icon()
charging.forceMove(drop_location())
- setCharging(null)
/obj/machinery/recharger/process()
if(stat & (NOPOWER|BROKEN) || !anchored)
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index 7ff8696084..4a4d58ea73 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -530,7 +530,6 @@
equip_cooldown = 0
var/obj/item/gun/medbeam/mech/medigun
custom_materials = list(/datum/material/iron = 15000, /datum/material/glass = 8000, /datum/material/plasma = 3000, /datum/material/gold = 8000, /datum/material/diamond = 2000)
- material_flags = MATERIAL_NO_EFFECTS
/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/Initialize()
. = ..()
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index fb321665bc..93228c7fee 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -188,7 +188,6 @@
var/location = get_step(src,(dir))
var/obj/item/I = new D.build_path(location)
- I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this.
I.set_custom_materials(res_coef)
say("\The [I] is complete.")
being_built = null
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 9d3cc8293b..c0c8f449e8 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -914,11 +914,3 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
. = ..()
if(var_name == NAMEOF(src, slowdown))
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
-
-//Called when the object is constructed by an autolathe
-//Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes
-/obj/item/proc/autolathe_crafted(obj/machinery/autolathe/A)
- return
-
-/obj/item/proc/rnd_crafted(obj/machinery/rnd/production/P)
- return
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 3dad3877b7..f60edf2917 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -726,13 +726,12 @@
to_chat(usr, "A color that dark on an object like this? Surely not...")
return FALSE
- target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
if(istype(target, /obj/structure/window))
- if(color_hex2num(paint_color) < 255)
- target.set_opacity(255)
- else
- target.set_opacity(initial(target.opacity))
+ var/obj/structure/window/W = target
+ W.spraycan_paint(paint_color)
+ else
+ target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
. = use_charges(user, 2)
var/fraction = min(1, . / reagents.maximum_volume)
diff --git a/code/game/objects/items/devices/electrochromatic_kit.dm b/code/game/objects/items/devices/electrochromatic_kit.dm
new file mode 100644
index 0000000000..d582eab00e
--- /dev/null
+++ b/code/game/objects/items/devices/electrochromatic_kit.dm
@@ -0,0 +1,14 @@
+/obj/item/electronics/electrochromatic_kit
+ name = "electrochromatic kit"
+ desc = "A kit for upgrading a window into an electrochromatic one."
+ /// Electrochromatic ID
+ var/id
+
+/obj/item/electronics/electrochromatic_kit/attack_self(mob/user)
+ . = ..()
+ if(.)
+ return
+ var/new_id = input(user, "Set this kit's electrochromatic ID", "Set ID", id) as text|null
+ if(isnull(new_id))
+ return
+ id = new_id
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 63092b5a13..4d0ed362fc 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -68,10 +68,9 @@
update_icon()
/obj/item/multitool/update_icon_state()
+ icon_state = initial(icon_state)
if(selected_io)
- icon_state = "multitool_red"
- else
- icon_state = "multitool"
+ icon_state += "_red"
/obj/item/multitool/proc/wire(var/datum/integrated_io/io, mob/user)
if(!io.holder.assembly)
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 011837d48b..c2db529675 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -648,7 +648,7 @@
item_state = "mace_greyscale"
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Material type changes the prefix as well as the color.
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_EFFECTS //Material type changes the prefix as well as the color.
custom_materials = list(/datum/material/iron = 12000) //Defaults to an Iron Mace.
slot_flags = ITEM_SLOT_BELT
force = 14
diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm
index bdf9ab4270..cd65149f5d 100644
--- a/code/game/objects/items/paint.dm
+++ b/code/game/objects/items/paint.dm
@@ -112,7 +112,7 @@
. = ..()
if(!proximity)
return
- if(!isturf(target) || !isobj(target))
+ if(!isturf(target) && !isobj(target))
return
if(target.color != initial(target.color))
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm
index f7bf659f0a..fc7b196bd2 100644
--- a/code/game/objects/items/shields.dm
+++ b/code/game/objects/items/shields.dm
@@ -107,6 +107,8 @@
return TRUE
/obj/item/shield/proc/user_shieldbash(mob/living/user, atom/target, harmful)
+ if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) //Combat mode has to be enabled for shield bashing
+ return FALSE
if(!(shield_flags & SHIELD_CAN_BASH))
to_chat(user, "[src] can't be used to shield bash!")
return FALSE
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 1648598c4e..c34ad44d5c 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -109,7 +109,6 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
merge_type = /obj/item/stack/sheet/plasmaglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10)
tableVariant = /obj/structure/table/plasmaglass
- material_flags = MATERIAL_NO_EFFECTS
shard_type = /obj/item/shard/plasma
/obj/item/stack/sheet/plasmaglass/fifty
@@ -209,7 +208,6 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
custom_materials = list(/datum/material/plasma=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT, /datum/material/iron=MINERAL_MATERIAL_AMOUNT * 0.5,)
armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
resistance_flags = ACID_PROOF
- material_flags = MATERIAL_NO_EFFECTS
merge_type = /obj/item/stack/sheet/plasmarglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10)
point_value = 23
@@ -259,7 +257,6 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
item_state = "sheet-plastitaniumglass"
custom_materials = list(/datum/material/titanium=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
- material_flags = MATERIAL_NO_EFFECTS
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plastitaniumglass
shard_type = /obj/item/shard
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 4a7156db72..d28ae52b52 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -324,7 +324,6 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \
custom_materials = list(/datum/material/titanium=MINERAL_MATERIAL_AMOUNT, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT)
point_value = 45
merge_type = /obj/item/stack/sheet/mineral/plastitanium
- material_flags = MATERIAL_NO_EFFECTS
/obj/item/stack/sheet/mineral/plastitanium/fifty
amount = 50
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 6ddd7c136a..f19dbb2a6b 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -215,7 +215,6 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
grind_results = list(/datum/reagent/iron = 20, /datum/reagent/toxin/plasma = 20)
point_value = 23
tableVariant = /obj/structure/table/reinforced
- material_flags = MATERIAL_NO_EFFECTS
/obj/item/stack/sheet/plasteel/get_main_recipes()
. = ..()
diff --git a/code/game/objects/items/stacks/tiles/tile_mineral.dm b/code/game/objects/items/stacks/tiles/tile_mineral.dm
index 50edc9d15a..1bcd8d72ca 100644
--- a/code/game/objects/items/stacks/tiles/tile_mineral.dm
+++ b/code/game/objects/items/stacks/tiles/tile_mineral.dm
@@ -78,4 +78,3 @@
turf_type = /turf/open/floor/mineral/plastitanium
mineralType = "plastitanium"
custom_materials = list(/datum/material/titanium=250, /datum/material/plasma=250)
- material_flags = MATERIAL_NO_EFFECTS
\ No newline at end of file
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 5acbb2f231..199f0c51e2 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -315,3 +315,11 @@
current_skin = choice
icon_state = unique_reskin[choice]
to_chat(M, "[src] is now skinned as '[choice]'.")
+
+//Called when the object is constructed by an autolathe
+//Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes
+/obj/proc/autolathe_crafted(obj/machinery/autolathe/A)
+ return
+
+/obj/proc/rnd_crafted(obj/machinery/rnd/production/P)
+ return
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index c593451c24..d3e8ecf0a6 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -153,7 +153,7 @@
///Material chair
/obj/structure/chair/greyscale
icon_state = "chair_greyscale"
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_EFFECTS
item_chair = /obj/item/chair/greyscale
buildstacktype = null //Custom mats handle this
@@ -382,7 +382,7 @@
/obj/item/chair/greyscale
icon_state = "chair_greyscale_toppled"
item_state = "chair_greyscale"
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_EFFECTS
origin_type = /obj/structure/chair/greyscale
/obj/item/chair/stool
diff --git a/code/game/objects/structures/loot_pile.dm b/code/game/objects/structures/loot_pile.dm
new file mode 100644
index 0000000000..b6249ec1e4
--- /dev/null
+++ b/code/game/objects/structures/loot_pile.dm
@@ -0,0 +1,66 @@
+ /*
+ * Loot piles structures, somewhat inspired from Polaris 13 ones but without the one search per pile ckey/mind restriction
+ * because the actual code is located its own element and has enough variables already. the piles themselves merely cosmetical.
+ */
+/obj/structure/loot_pile
+ name = "pile of junk"
+ desc = "Lots of junk lying around. They say one man's trash is another man's treasure."
+ icon = 'icons/obj/loot_piles.dmi'
+ icon_state = "randompile"
+ density = FALSE
+ anchored = TRUE
+ var/loot_amount = 5
+ var/delete_on_depletion = FALSE
+ var/can_use_hands = TRUE
+ var/scavenge_time = 12 SECONDS
+ var/allowed_tools = list(TOOL_SHOVEL = 0.6) //list of tool_behaviours with associated speed multipliers (lower is better)
+ var/icon_states_to_use = list("junk_pile1", "junk_pile2", "junk_pile3", "junk_pile4", "junk_pile5")
+ var/list/loot
+
+ /*
+ * Associated values in this list are not weights but numbers of times the kery can be rolled
+ * before being removed from ALL piles with same kind. This is why I wanted 'scavenging' to be an element and not a component.
+ */
+ var/list/unique_loot
+
+ /*
+ * used for restrictions such as "one per mind", "one per ckey". Depending on the setting, these can be either limited to
+ * the current pile or shared throughout all atoms attached to this element.
+ */
+ var/loot_restriction = NO_LOOT_RESTRICTION
+ var/maximum_loot_per_player = 1
+
+/obj/structure/loot_pile/Initialize()
+ . = ..()
+ icon_state = pick(icon_states_to_use)
+
+/obj/structure/loot_pile/ComponentInitialize()
+ . = ..()
+ if(loot)
+ AddElement(/datum/element/scavenging, loot_amount, loot, unique_loot, scavenge_time, can_use_hands, allowed_tools, null, delete_on_depletion, loot_restriction, maximum_loot_per_player)
+
+//uses the maintenance_loot global list, mostly boring stuff and mices.
+/obj/structure/loot_pile/maint
+ name = "trash pile"
+ desc = "A heap of garbage, but maybe there's something interesting inside?"
+ density = TRUE
+ layer = TABLE_LAYER
+ climbable = TRUE
+ pass_flags = LETPASSTHROW
+ loot = list(
+ SCAVENGING_FOUND_NOTHING = 50,
+ SCAVENGING_SPAWN_MOUSE = 10,
+ SCAVENGING_SPAWN_MICE = 5,
+ SCAVENGING_SPAWN_TOM = 1,
+ /obj/item/clothing/gloves/color/yellow = 0.5)
+ unique_loot = list(/obj/item/clothing/gloves/color/yellow = 5, SCAVENGING_SPAWN_TOM = 1)
+
+/obj/structure/loot_pile/maint/ComponentInitialize()
+ var/static/safe_maint_items
+ if(!safe_maint_items)
+ safe_maint_items = list()
+ for(var/A in GLOB.maintenance_loot)
+ if(ispath(A, /obj/item))
+ safe_maint_items[A] = GLOB.maintenance_loot[A]
+ loot += safe_maint_items
+ return ..()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index bbdf6925f9..30e451aa14 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -211,7 +211,7 @@
/obj/structure/table/greyscale
icon = 'icons/obj/smooth_structures/table_greyscale.dmi'
icon_state = "table"
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_EFFECTS
buildstack = null //No buildstack, so generate from mat datums
/*
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 5dd4e7d987..e4d93ea8de 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -1,3 +1,18 @@
+#define NOT_ELECTROCHROMATIC 0
+#define ELECTROCHROMATIC_OFF 1
+#define ELECTROCHROMATIC_DIMMED 2
+
+GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
+
+/proc/do_electrochromatic_toggle(new_status, id)
+ var/list/windows = GLOB.electrochromatic_window_lookup["[id]"]
+ if(!windows)
+ return
+ var/obj/structure/window/W //define outside for performance because obviously this matters.
+ for(var/i in windows)
+ W = i
+ new_status? W.electrochromatic_dim() : W.electrochromatic_off()
+
/obj/structure/window
name = "window"
desc = "A window."
@@ -28,8 +43,15 @@
rad_insulation = RAD_VERY_LIGHT_INSULATION
rad_flags = RAD_PROTECT_CONTENTS
+ /// Electrochromatic status
+ var/electrochromatic_status = NOT_ELECTROCHROMATIC
+ /// Electrochromatic ID. Set the first character to ! to replace with a SSmapping generated pseudorandom obfuscated ID for mapping purposes.
+ var/electrochromatic_id
+
/obj/structure/window/examine(mob/user)
. = ..()
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC)
+ . += "The window has electrochromatic circuitry on it."
if(reinf)
if(anchored && state == WINDOW_SCREWED_TO_FRAME)
. += "The window is screwed to the frame."
@@ -52,6 +74,10 @@
if(reinf && anchored)
state = WINDOW_SCREWED_TO_FRAME
+ if(mapload && electrochromatic_id)
+ if(copytext(electrochromatic_id, 1, 2) == "!")
+ electrochromatic_id = SSmapping.get_obfuscated_id(electrochromatic_id)
+
ini_dir = dir
air_update_turf(1)
@@ -62,6 +88,12 @@
real_explosion_block = explosion_block
explosion_block = EXPLOSION_BLOCK_PROC
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC)
+ var/old = electrochromatic_status
+ make_electrochromatic()
+ if(old == ELECTROCHROMATIC_DIMMED)
+ electrochromatic_dim()
+
/obj/structure/window/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS ,null,CALLBACK(src, .proc/can_be_rotated),CALLBACK(src,.proc/after_rotation))
@@ -177,6 +209,24 @@
to_chat(user, "[src] is already in good condition!")
return
+ if(istype(I, /obj/item/electronics/electrochromatic_kit) && user.a_intent == INTENT_HELP)
+ var/obj/item/electronics/electrochromatic_kit/K = I
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC)
+ to_chat(user, "[src] is already electrochromatic!")
+ return
+ if(anchored)
+ to_chat(user, "[src] must not be attached to the floor!")
+ return
+ if(!K.id)
+ to_chat(user, "[K] has no ID set!")
+ return
+ if(!user.temporarilyRemoveItemFromInventory(K))
+ to_chat(user, "[K] is stuck to your hand!")
+ return
+ user.visible_message("[user] upgrades [src] with [I].", "You upgrade [src] with [I].")
+ make_electrochromatic(K.id)
+ qdel(K)
+
if(!(flags_1&NODECONSTRUCT_1))
if(istype(I, /obj/item/screwdriver))
I.play_tool_sound(src, 75)
@@ -224,6 +274,91 @@
air_update_turf(TRUE)
update_nearby_icons()
+/obj/structure/window/proc/spraycan_paint(paint_color)
+ if(color_hex2num(paint_color) < 255)
+ set_opacity(255)
+ else
+ set_opacity(initial(opacity))
+ add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
+
+/obj/structure/window/proc/electrochromatic_dim()
+ if(electrochromatic_status == ELECTROCHROMATIC_DIMMED)
+ return
+ electrochromatic_status = ELECTROCHROMATIC_DIMMED
+ animate(src, color = "#222222", time = 2)
+ set_opacity(TRUE)
+
+/obj/structure/window/proc/electrochromatic_off()
+ if(electrochromatic_status == ELECTROCHROMATIC_OFF)
+ return
+ electrochromatic_status = ELECTROCHROMATIC_OFF
+ var/current = color
+ update_atom_colour()
+ var/newcolor = color
+ color = current
+ animate(src, color = newcolor, time = 2)
+
+/obj/structure/window/proc/remove_electrochromatic()
+ electrochromatic_off()
+ electrochromatic_status = NOT_ELECTROCHROMATIC
+ if(!electrochromatic_id)
+ return
+ var/list/L = GLOB.electrochromatic_window_lookup["[electrochromatic_id]"]
+ if(L)
+ L -= src
+ electrochromatic_id = null
+
+/obj/structure/window/vv_edit_var(var_name, var_value)
+ var/check_status
+ if(var_name == NAMEOF(src, electrochromatic_id))
+ if(electrochromatic_id && GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] -= src
+ if(var_name == NAMEOF(src, electrochromatic_status))
+ check_status = TRUE
+ . = ..() //do this first incase it runtimes.
+ if(var_name == NAMEOF(src, electrochromatic_id))
+ if((electrochromatic_status != NOT_ELECTROCHROMATIC) && electrochromatic_id)
+ LAZYINITLIST(GLOB.electrochromatic_window_lookup[electrochromatic_id])
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] += src
+ if(check_status)
+ if(electrochromatic_status == NOT_ELECTROCHROMATIC)
+ remove_electrochromatic()
+ return
+ else if(electrochromatic_status == ELECTROCHROMATIC_OFF)
+ if(!electrochromatic_id)
+ return
+ else
+ make_electrochromatic()
+ electrochromatic_off()
+ return
+ else if(electrochromatic_status == ELECTROCHROMATIC_DIMMED)
+ if(!electrochromatic_id)
+ return
+ else
+ make_electrochromatic()
+ electrochromatic_dim()
+ return
+ else
+ remove_electrochromatic()
+
+/obj/structure/window/proc/make_electrochromatic(new_id = electrochromatic_id)
+ remove_electrochromatic()
+ if(!new_id)
+ CRASH("Attempted to make electrochromatic with null ID.")
+ electrochromatic_id = new_id
+ electrochromatic_status = ELECTROCHROMATIC_OFF
+ LAZYINITLIST(GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] |= src
+
+/obj/structure/window/update_atom_colour()
+ if((electrochromatic_status != ELECTROCHROMATIC_OFF) && (electrochromatic_status != ELECTROCHROMATIC_DIMMED))
+ return FALSE
+ . = ..()
+ if(color && (color_hex2num(color) < 255))
+ set_opacity(255)
+ else
+ set_opacity(FALSE)
+
/obj/structure/window/proc/check_state(checked_state)
if(state == checked_state)
return TRUE
@@ -263,7 +398,6 @@
if(BURN)
playsound(src, 'sound/items/Welder.ogg', 100, 1)
-
/obj/structure/window/deconstruct(disassembled = TRUE)
if(QDELETED(src))
return
@@ -272,6 +406,9 @@
if(!(flags_1 & NODECONSTRUCT_1))
for(var/obj/item/shard/debris in spawnDebris(drop_location()))
transfer_fingerprints_to(debris) // transfer fingerprints to shards only
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC) //eh fine keep your kit.
+ new /obj/item/electronics/electrochromatic_kit(drop_location())
+ // Intentionally not setting the ID so you can't decon one to know all of the IDs.
qdel(src)
update_nearby_icons()
@@ -315,9 +452,9 @@
density = FALSE
air_update_turf(1)
update_nearby_icons()
+ remove_electrochromatic()
return ..()
-
/obj/structure/window/Move()
var/turf/T = loc
. = ..()
@@ -731,7 +868,6 @@
set_opacity(TRUE)
queue_smooth(src)
-
/obj/structure/window/paperframe/attackby(obj/item/W, mob/user)
if(W.get_temperature())
fire_act(W.get_temperature())
@@ -749,3 +885,7 @@
return
..()
update_icon()
+
+#undef NOT_ELECTROCHROMATIC
+#undef ELECTROCHROMATIC_OFF
+#undef ELECTROCHROMATIC_DIMMED
diff --git a/code/game/say.dm b/code/game/say.dm
index 85ae9f0681..5fa5a2b35d 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -96,21 +96,26 @@ GLOBAL_LIST_INIT(freqtospan, list(
return "[say_mod(input, message_mode)][spanned ? ", \"[spanned]\"" : ""]"
// Citadel edit [spanned ? ", \"[spanned]\"" : ""]"
-/atom/movable/proc/lang_treat(atom/movable/speaker, datum/language/language, raw_message, list/spans, message_mode)
+/// Quirky citadel proc for our custom sayverbs to strip the verb out. Snowflakey as hell, say rewrite 3.0 when?
+/atom/movable/proc/quoteless_say_quote(input, list/spans = list(speech_span), message_mode)
+ var/pos = findtext(input, "*")
+ return pos? copytext(input, pos + 1) : input
+
+/atom/movable/proc/lang_treat(atom/movable/speaker, datum/language/language, raw_message, list/spans, message_mode, no_quote = FALSE)
if(has_language(language))
var/atom/movable/AM = speaker.GetSource()
if(AM) //Basically means "if the speaker is virtual"
- return AM.say_quote(raw_message, spans, message_mode)
+ return no_quote ? AM.quoteless_say_quote(raw_message, spans, message_mode) : AM.say_quote(raw_message, spans, message_mode)
else
- return speaker.say_quote(raw_message, spans, message_mode)
+ return no_quote ? speaker.quoteless_say_quote(raw_message, spans, message_mode) : speaker.say_quote(raw_message, spans, message_mode)
else if(language)
var/atom/movable/AM = speaker.GetSource()
var/datum/language/D = GLOB.language_datum_instances[language]
raw_message = D.scramble(raw_message)
if(AM)
- return AM.say_quote(raw_message, spans, message_mode)
+ return no_quote ? AM.quoteless_say_quote(raw_message, spans, message_mode) : AM.say_quote(raw_message, spans, message_mode)
else
- return speaker.say_quote(raw_message, spans, message_mode)
+ return no_quote ? speaker.quoteless_say_quote(raw_message, spans, message_mode) : speaker.say_quote(raw_message, spans, message_mode)
else
return "makes a strange sound."
diff --git a/code/game/world.dm b/code/game/world.dm
index 1d719ee138..94cfb0baca 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -8,6 +8,8 @@ GLOBAL_LIST(topic_status_cache)
//This happens after the Master subsystem new(s) (it's a global datum)
//So subsystems globals exist, but are not initialised
/world/New()
+ if(fexists("byond-extools.dll"))
+ call("byond-extools.dll", "maptick_initialize")()
enable_debugger()
world.Profile(PROFILE_START)
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index a20a9cef85..e876beb5dc 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -128,6 +128,9 @@ the new instance inside the host to be updated to the template's stats.
link = FOLLOW_LINK(src, to_follow)
else
link = ""
+ // Create map text prior to modifying message for goonchat
+ if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
+ create_chat_message(speaker, message_language, raw_message, spans, message_mode)
// Recompose the message, because it's scrambled by default
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
to_chat(src, "[link] [message]")
diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm
index 1c9c1a0203..32e262ce65 100644
--- a/code/modules/assembly/doorcontrol.dm
+++ b/code/modules/assembly/doorcontrol.dm
@@ -3,14 +3,35 @@
desc = "A small electronic device able to control a blast door remotely."
icon_state = "control"
attachable = TRUE
- var/id = null
- var/can_change_id = 0
+ /// Our ID. Make the first character ! if you want to obfuscate it as a mapper via randomization.
+ var/id
+ /// Can the ID be changed if used in hand?
+ var/can_change_id = FALSE
+ /// Show ID?
+ var/show_id = TRUE
var/cooldown = FALSE //Door cooldowns
+/obj/item/assembly/control/Initialize(mapload)
+ if(mapload && id)
+ if(copytext(id, 1, 2) == "!")
+ id = SSmapping.get_obfuscated_id(id)
+ return ..()
+
/obj/item/assembly/control/examine(mob/user)
. = ..()
- if(id)
+ if(id && show_id)
. += "Its channel ID is '[id]'."
+ if(can_change_id)
+ . += "Use in hand to change ID."
+
+/obj/item/assembly/control/attack_self(mob/living/user)
+ . = ..()
+ if(!can_change_id)
+ return
+ var/new_id
+ new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
+ if(!isnull(new_id)) //0/"" is considered !, so check null instead of just !.
+ id = new_id
/obj/item/assembly/control/activate()
cooldown = TRUE
@@ -22,7 +43,6 @@
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
-
/obj/item/assembly/control/airlock
name = "airlock controller"
desc = "A small electronic device able to control an airlock remotely."
@@ -123,7 +143,6 @@
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
-
/obj/item/assembly/control/crematorium
name = "crematorium controller"
desc = "An evil-looking remote controller for a crematorium."
@@ -135,3 +154,14 @@
C.cremate(usr)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
+
+/obj/item/assembly/control/electrochromatic
+ name = "electrochromatic window controller"
+ desc = "Toggles linked electrochromatic windows."
+ can_change_id = TRUE
+ /// Stores our status to prevent windows from desyncing.
+ var/on = FALSE
+
+/obj/item/assembly/control/electrochromatic/activate()
+ on = !on
+ do_electrochromatic_toggle(on, id)
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index c47c4a44af..06d73867f8 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -9,7 +9,7 @@
return
-/turf/open/hotspot_expose(exposed_temperature, exposed_volume, soh)
+/turf/open/hotspot_expose(exposed_temperature, exposed_volume, soh = FALSE, holo = FALSE)
var/datum/gas_mixture/air_contents = return_air()
if(!air_contents)
return 0
@@ -35,7 +35,7 @@
if(oxy < 0.5)
return 0
- active_hotspot = new /obj/effect/hotspot(src)
+ active_hotspot = new /obj/effect/hotspot(src, holo)
active_hotspot.temperature = exposed_temperature*50
active_hotspot.volume = exposed_volume*25
@@ -67,8 +67,10 @@
var/bypassing = FALSE
var/visual_update_tick = 0
-/obj/effect/hotspot/Initialize()
+/obj/effect/hotspot/Initialize(mapload, holo = FALSE)
. = ..()
+ if(holo)
+ flags_1 |= HOLOGRAM_1
SSair.hotspots += src
perform_exposure()
setDir(pick(GLOB.cardinals))
@@ -192,7 +194,8 @@
if(bypassing)
icon_state = "3"
- location.burn_tile()
+ if(!(flags_1 & HOLOGRAM_1))
+ location.burn_tile()
//Possible spread due to radiated heat
if(location.air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD)
@@ -200,7 +203,7 @@
for(var/t in location.atmos_adjacent_turfs)
var/turf/open/T = t
if(!T.active_hotspot)
- T.hotspot_expose(radiated_temperature, CELL_VOLUME/4)
+ T.hotspot_expose(radiated_temperature, CELL_VOLUME/4, flags_1 & HOLOGRAM_1)
else
if(volume > CELL_VOLUME*0.4)
@@ -224,7 +227,8 @@
var/turf/open/T = loc
if(istype(T) && T.active_hotspot == src)
T.active_hotspot = null
- DestroyTurf()
+ if(!(flags_1 & HOLOGRAM_1))
+ DestroyTurf()
return ..()
/obj/effect/hotspot/proc/DestroyTurf()
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 864edfdbe6..8f5ab7dd5e 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -64,6 +64,7 @@
nullifyNode(i)
SSair.atmos_machinery -= src
+ SSair.pipenets_needing_rebuilt -= src
dropContents()
if(pipe_vision_img)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 73cb8eeecb..c164dc5ae3 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -116,7 +116,7 @@
if(node2)
node2.atmosinit()
node2.addMember(src)
- build_network()
+ SSair.add_to_rebuild_queue(src)
return TRUE
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index 63a03b1d40..a45728d51f 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -144,7 +144,7 @@
var/datum/pipeline/parent = parents[i]
if(!parent)
stack_trace("Component is missing a pipenet! Rebuilding...")
- build_network()
+ SSair.add_to_rebuild_queue(src)
parent.update = 1
/obj/machinery/atmospherics/components/returnPipenets()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index e013a86fd2..38042fe64d 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -447,6 +447,6 @@
if(node)
node.atmosinit()
node.addMember(src)
- build_network()
+ SSair.add_to_rebuild_queue(src)
#undef CRYOMOBS
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index dbe3c0b90b..dddfdf08c1 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -116,7 +116,7 @@
if(node)
node.atmosinit()
node.addMember(src)
- build_network()
+ SSair.add_to_rebuild_queue(src)
return TRUE
/obj/machinery/atmospherics/components/unary/thermomachine/ui_status(mob/user)
diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
index 33092f5354..bc8fd6777d 100644
--- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm
+++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
@@ -31,7 +31,7 @@
nodes = list()
for(var/obj/machinery/atmospherics/A in needs_nullifying)
A.disconnect(src)
- A.build_network()
+ SSair.add_to_rebuild_queue(A)
/obj/machinery/atmospherics/pipe/layer_manifold/proc/get_all_connected_nodes()
return front_nodes + back_nodes + nodes
diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm
index 1e513b846c..c466a422b2 100644
--- a/code/modules/atmospherics/machinery/pipes/pipes.dm
+++ b/code/modules/atmospherics/machinery/pipes/pipes.dm
@@ -22,7 +22,7 @@
var/obj/machinery/atmospherics/oldN = nodes[i]
..()
if(oldN)
- oldN.build_network()
+ SSair.add_to_rebuild_queue(oldN)
/obj/machinery/atmospherics/pipe/destroy_network()
QDEL_NULL(parent)
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index a41bdee3b6..03463ff0f7 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -159,7 +159,6 @@
/obj/machinery/portable_atmospherics/canister/proto
name = "prototype canister"
-
/obj/machinery/portable_atmospherics/canister/proto/default
name = "prototype canister"
desc = "The best way to fix an atmospheric emergency... or the best way to introduce one."
@@ -172,7 +171,6 @@
can_min_release_pressure = (ONE_ATMOSPHERE / 30)
prototype = TRUE
-
/obj/machinery/portable_atmospherics/canister/proto/default/oxygen
name = "prototype canister"
desc = "A prototype canister for a prototype bike, what could go wrong?"
@@ -181,8 +179,6 @@
filled = 1
release_pressure = ONE_ATMOSPHERE*2
-
-
/obj/machinery/portable_atmospherics/canister/New(loc, datum/gas_mixture/existing_mixture)
..()
if(existing_mixture)
@@ -192,7 +188,7 @@
pump = new(src, FALSE)
pump.on = TRUE
pump.stat = 0
- pump.build_network()
+ SSair.add_to_rebuild_queue(pump)
update_icon()
@@ -208,6 +204,7 @@
air_contents.gases[gas_type] = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
if(starter_temp)
air_contents.temperature = starter_temp
+
/obj/machinery/portable_atmospherics/canister/air/create_gas()
air_contents.gases[/datum/gas/oxygen] = (O2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
air_contents.gases[/datum/gas/nitrogen] = (N2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm
index 18e4da621a..377e9285e3 100644
--- a/code/modules/atmospherics/machinery/portable/pump.dm
+++ b/code/modules/atmospherics/machinery/portable/pump.dm
@@ -20,7 +20,7 @@
pump = new(src, FALSE)
pump.on = TRUE
pump.stat = 0
- pump.build_network()
+ SSair.add_to_rebuild_queue(pump)
/obj/machinery/portable_atmospherics/pump/Destroy()
var/turf/T = get_turf(src)
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index b78f218348..13e223bca3 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -66,12 +66,9 @@
P.info += "Item: [pack.name]
"
P.info += "Contents:
"
P.info += "