diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm
index f6812106ef..39ecc54ec7 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm
@@ -476,7 +476,7 @@
},
/obj/item/storage/bag/plants/portaseeder,
/obj/item/seeds/cotton,
-/obj/item/seeds/cotton,
+/obj/item/seeds/cotton/durathread,
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"bk" = (
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index a4f0e17229..86397c5751 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -23646,7 +23646,10 @@
/area/crew_quarters/bar/atrium)
"aTH" = (
/obj/structure/table/wood,
-/obj/item/reagent_containers/food/drinks/coffee,
+/obj/item/reagent_containers/food/drinks/coffee{
+ pixel_x = -4;
+ pixel_y = 2
+ },
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -60673,10 +60676,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
/obj/machinery/door/firedoor,
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -60691,10 +60690,6 @@
dir = 4
},
/obj/machinery/light,
-/obj/machinery/firealarm{
- dir = 1;
- pixel_y = -26
- },
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
@@ -62744,43 +62739,36 @@
/turf/open/floor/plasteel/dark,
/area/library)
"cct" = (
-/obj/structure/table/wood,
-/obj/item/flashlight/lamp,
-/obj/machinery/computer/security/telescreen/entertainment{
- pixel_x = -32
+/obj/structure/table/wood/fancy,
+/obj/machinery/door/window{
+ name = "Secure Art Exhibition"
},
-/obj/item/radio/intercom{
- name = "Station Intercom";
- pixel_y = 26
- },
-/turf/open/floor/plasteel/dark,
-/area/library)
-"ccu" = (
-/obj/machinery/light/small{
- dir = 1
- },
-/obj/structure/table/wood,
-/obj/item/folder,
-/obj/item/pen,
-/obj/machinery/newscaster{
+/obj/structure/sign/painting/library_secure{
pixel_y = 32
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
+/turf/open/floor/carpet,
+/area/library)
+"ccu" = (
+/obj/structure/table/wood/fancy,
+/obj/structure/window/reinforced{
dir = 4
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
+/obj/structure/window/reinforced,
+/obj/structure/sign/painting/library_secure{
+ pixel_y = 32
},
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/carpet,
/area/library)
"ccv" = (
-/obj/machinery/computer/libraryconsole,
-/obj/structure/table/wood,
-/turf/open/floor/plasteel/dark,
+/obj/structure/extinguisher_cabinet{
+ pixel_y = 32
+ },
+/obj/machinery/camera{
+ c_tag = "Library - Aft";
+ dir = 2;
+ name = "library camera"
+ },
+/turf/open/floor/wood,
/area/library)
"ccw" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
@@ -63922,7 +63910,7 @@
/obj/structure/chair/office/dark{
dir = 8
},
-/obj/effect/landmark/start/librarian,
+/obj/effect/landmark/start/assistant,
/turf/open/floor/plasteel/dark,
/area/library)
"ceg" = (
@@ -63935,71 +63923,21 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 8
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/library)
-"cei" = (
-/obj/structure/chair/comfy/black{
- dir = 8
- },
-/obj/machinery/newscaster{
- pixel_x = 32
- },
-/obj/machinery/camera{
- c_tag = "Library - Fore";
- dir = 8;
- name = "library camera"
- },
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/plasteel/grimy,
/area/library)
"cej" = (
-/obj/machinery/photocopier,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/library)
-"cek" = (
-/obj/structure/chair/office/dark{
- dir = 1
- },
-/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/turf/open/floor/plasteel/dark,
+/obj/effect/landmark/start/librarian,
+/turf/open/floor/plasteel/grimy,
/area/library)
"cel" = (
-/obj/structure/table/wood,
-/obj/item/paper_bin,
-/obj/item/pen,
-/obj/machinery/status_display/evac{
- pixel_x = 32
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
+/obj/structure/chair/sofa/right{
+ icon_state = "sofaend_right";
dir = 8
},
-/turf/open/floor/plasteel/dark,
+/obj/structure/sign/painting/library{
+ pixel_x = 32
+ },
+/turf/open/floor/wood,
/area/library)
"cem" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
@@ -65176,34 +65114,16 @@
},
/turf/open/floor/plasteel/grimy,
/area/library)
-"cfY" = (
-/obj/item/kirbyplants/random,
-/obj/machinery/light/small{
- dir = 4
+"cfZ" = (
+/obj/item/radio/intercom{
+ name = "Station Intercom";
+ pixel_x = -26
+ },
+/obj/structure/sign/painting/library{
+ pixel_y = -32
},
/turf/open/floor/wood,
/area/library)
-"cfZ" = (
-/obj/structure/sign/warning/nosmoking,
-/turf/closed/wall,
-/area/library)
-"cga" = (
-/obj/machinery/door/morgue{
- name = "Private Study"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/library)
"cgb" = (
/obj/structure/sign/plaques/kiddie/library{
pixel_x = -32
@@ -66351,61 +66271,28 @@
/obj/item/kirbyplants/random,
/turf/open/floor/wood,
/area/library)
-"chQ" = (
-/obj/machinery/bookbinder,
-/turf/open/floor/wood,
-/area/library)
-"chR" = (
-/obj/machinery/light{
- dir = 1
- },
-/obj/machinery/newscaster{
- pixel_y = 32
- },
-/obj/structure/bookcase/random,
-/turf/open/floor/wood,
-/area/library)
-"chS" = (
-/obj/structure/chair/comfy/brown,
-/obj/effect/landmark/start/assistant,
-/turf/open/floor/wood,
-/area/library)
-"chT" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/wood,
-/area/library)
-"chU" = (
-/obj/machinery/photocopier,
-/obj/structure/extinguisher_cabinet{
- pixel_y = 32
- },
-/turf/open/floor/wood,
-/area/library)
"chV" = (
-/obj/machinery/light{
- dir = 1
- },
/obj/machinery/newscaster{
- pixel_y = 32
+ pixel_x = -32
},
-/obj/structure/bookcase/manuals/research_and_development,
-/obj/machinery/camera{
- c_tag = "Library";
- name = "library camera"
- },
-/turf/open/floor/wood,
+/turf/open/floor/plasteel/dark,
/area/library)
"chW" = (
-/obj/structure/chair/comfy/brown,
-/obj/item/radio/intercom{
- name = "Station Intercom";
- pixel_y = 26
- },
-/turf/open/floor/wood,
+/obj/machinery/holopad,
+/obj/effect/turf_decal/bot,
+/turf/open/floor/plasteel/grimy,
/area/library)
"chX" = (
-/obj/machinery/vending/coffee,
-/turf/open/floor/wood,
+/obj/structure/table/wood,
+/obj/item/newspaper{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/reagent_containers/food/drinks/coffee{
+ pixel_x = -4;
+ pixel_y = 2
+ },
+/turf/open/floor/plasteel/dark,
/area/library)
"chY" = (
/obj/machinery/door/poddoor/shutters/preopen{
@@ -67294,10 +67181,6 @@
},
/turf/open/floor/plasteel/grimy,
/area/library)
-"cju" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/turf/open/floor/plasteel/grimy,
-/area/library)
"cjv" = (
/obj/machinery/door/airlock/public/glass{
name = "Library Access"
@@ -68920,10 +68803,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/wood,
/area/library)
-"cmv" = (
-/obj/machinery/holopad,
-/turf/open/floor/wood,
-/area/library)
"cmw" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/extinguisher_cabinet{
@@ -69800,7 +69679,7 @@
/turf/open/floor/wood,
/area/library)
"cnP" = (
-/obj/structure/bookcase/manuals/medical,
+/obj/structure/bookcase/random,
/turf/open/floor/wood,
/area/library)
"cnQ" = (
@@ -74568,8 +74447,6 @@
/area/library)
"cwr" = (
/obj/structure/easel,
-/obj/item/canvas/twentythreeXnineteen,
-/obj/item/canvas/twentythreeXtwentythree,
/obj/item/canvas/twentythreeXtwentythree,
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -78500,7 +78377,10 @@
pixel_x = 3;
pixel_y = 3
},
-/obj/item/newspaper,
+/obj/item/newspaper{
+ pixel_x = 3;
+ pixel_y = 3
+ },
/obj/machinery/status_display/evac{
pixel_x = -32
},
@@ -80213,7 +80093,10 @@
pixel_x = 7;
pixel_y = 11
},
-/obj/item/newspaper,
+/obj/item/newspaper{
+ pixel_x = 3;
+ pixel_y = 3
+ },
/obj/item/pen/red,
/turf/open/floor/wood{
icon_state = "wood-broken2"
@@ -110110,7 +109993,10 @@
pixel_x = 3;
pixel_y = 3
},
-/obj/item/newspaper,
+/obj/item/newspaper{
+ pixel_x = 3;
+ pixel_y = 3
+ },
/turf/open/floor/plating,
/area/security/detectives_office/private_investigators_office)
"dFu" = (
@@ -110973,7 +110859,10 @@
/area/crew_quarters/theatre/abandoned)
"dGH" = (
/obj/structure/table/wood,
-/obj/item/newspaper,
+/obj/item/newspaper{
+ pixel_x = 3;
+ pixel_y = 3
+ },
/obj/item/clothing/head/bowler,
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -125489,6 +125378,17 @@
/obj/structure/closet/crate/coffin,
/turf/open/floor/plating,
/area/chapel/office)
+"gjg" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
"gmj" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
@@ -125557,6 +125457,12 @@
},
/turf/open/floor/plasteel/dark,
/area/science/mixing)
+"gOM" = (
+/obj/structure/sign/painting/library{
+ pixel_y = -32
+ },
+/turf/open/floor/wood,
+/area/library)
"gPv" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -125856,6 +125762,12 @@
/obj/item/integrated_circuit_printer,
/turf/open/floor/plasteel/white/side,
/area/science/circuit)
+"jqs" = (
+/obj/structure/sign/painting/library{
+ pixel_y = 32
+ },
+/turf/open/floor/wood,
+/area/library)
"jqM" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/stripes/line{
@@ -125974,6 +125886,17 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/science/mixing)
+"jVB" = (
+/obj/structure/table/wood/fancy,
+/obj/structure/window/reinforced{
+ dir = 8
+ },
+/obj/structure/window/reinforced,
+/obj/structure/sign/painting/library_secure{
+ pixel_y = 32
+ },
+/turf/open/floor/carpet,
+/area/library)
"kam" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/conveyor{
@@ -126386,6 +126309,12 @@
},
/turf/open/floor/plasteel/white,
/area/science/research)
+"mRS" = (
+/obj/machinery/light{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/library)
"mWZ" = (
/obj/machinery/atmospherics/components/binary/pump,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
@@ -126425,6 +126354,17 @@
/obj/machinery/atmospherics/pipe/simple/general/hidden,
/turf/closed/wall/r_wall,
/area/maintenance/disposal/incinerator)
+"oek" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/camera{
+ c_tag = "Library - Aft";
+ dir = 2;
+ name = "library camera"
+ },
+/turf/open/floor/plasteel/grimy,
+/area/library)
"oHk" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -126640,6 +126580,10 @@
},
/turf/open/floor/plating,
/area/science/research/abandoned)
+"pLF" = (
+/obj/machinery/light,
+/turf/open/floor/wood,
+/area/library)
"pQm" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable/white{
@@ -126929,6 +126873,15 @@
"tCh" = (
/turf/closed/wall,
/area/science/misc_lab)
+"tDx" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/turf/open/floor/plasteel/grimy,
+/area/library)
"tMk" = (
/turf/open/floor/plasteel/white/side{
dir = 10
@@ -127085,6 +127038,16 @@
},
/turf/open/floor/plating,
/area/engine/atmos)
+"vLX" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 8
+ },
+/obj/structure/sign/plaques/kiddie/library{
+ pixel_x = 32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/grimy,
+/area/library)
"wei" = (
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plasteel,
@@ -127104,6 +127067,19 @@
/obj/effect/turf_decal/tile/purple,
/turf/open/floor/plasteel/white,
/area/science/misc_lab)
+"wEg" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/firealarm{
+ dir = 1;
+ pixel_y = -26
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
"wFu" = (
/obj/structure/lattice,
/obj/structure/grille,
@@ -127292,6 +127268,13 @@
/obj/structure/fans/tiny/invisible,
/turf/open/space/basic,
/area/space)
+"yin" = (
+/obj/structure/chair/sofa/left{
+ icon_state = "sofaend_left";
+ dir = 8
+ },
+/turf/open/floor/wood,
+/area/library)
"yiv" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/neutral{
@@ -158292,7 +158275,7 @@ ccq
ceg
ccq
chO
-ceg
+vLX
ckQ
cmr
ccq
@@ -158545,11 +158528,11 @@ bUt
bWD
bYM
caH
-ccr
+cwq
ceh
-cfY
-chP
-cjt
+caG
+caG
+oek
ckR
cms
cnO
@@ -158800,12 +158783,12 @@ bDl
bDl
bUu
bWE
-bYO
+gjg
caG
-ccs
-cei
+mRS
+cxV
cfZ
-chQ
+caG
cjt
ckR
cms
@@ -159059,11 +159042,11 @@ bUv
bWC
bYR
caG
+jqs
+cxV
+gOM
caG
-caG
-caG
-chR
-cjt
+tDx
ckR
cmt
cmt
@@ -159316,10 +159299,10 @@ bUq
bWI
bYM
caG
-cct
-cej
+jqs
+cxV
+gOM
caG
-chS
cjt
ckR
cms
@@ -159573,11 +159556,11 @@ bUq
bWD
bYM
caG
-ccu
-cek
-cga
-chT
-cju
+jqs
+cxV
+gOM
+caG
+cjt
ckR
cms
cnQ
@@ -159831,9 +159814,9 @@ bWD
bYM
caG
ccv
-cel
+cxV
+pLF
caG
-chU
cjt
ckR
xuu
@@ -160087,9 +160070,9 @@ bUq
bWD
bYS
caG
-caG
-caG
-caG
+jVB
+cxV
+cmt
chV
cjt
ckT
@@ -160346,7 +160329,7 @@ bYM
caG
cct
cej
-caG
+cxV
chW
cjt
ckR
@@ -160602,12 +160585,12 @@ bWD
bYM
caG
ccu
-cek
-cga
-chT
-cju
+cmt
+cmt
+ccr
+cjt
ckR
-cmv
+cmt
cnU
cpy
cqT
@@ -160856,11 +160839,11 @@ bQu
bQv
bUr
bWD
-bYM
+wEg
caG
-ccv
+chP
cel
-caG
+yin
chX
cjt
ckR
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index 356eefbd35..bfea5f9289 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -7602,10 +7602,10 @@
/turf/open/floor/plating,
/area/security/warden)
"apa" = (
-/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
- dir = 4
- },
/obj/machinery/meter,
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"apb" = (
@@ -38665,11 +38665,20 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bMM" = (
-/obj/machinery/atmospherics/components/unary/thermomachine/heater,
+/obj/structure/rack,
+/obj/item/clothing/suit/hazardvest,
+/obj/item/clothing/suit/hazardvest,
+/obj/item/clothing/suit/hazardvest,
+/obj/item/clothing/suit/hazardvest,
+/obj/item/clothing/gloves/color/black,
+/obj/item/clothing/gloves/color/black,
+/obj/item/clothing/gloves/color/black,
+/obj/item/clothing/mask/gas,
+/obj/item/clothing/mask/gas,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bMN" = (
-/obj/machinery/atmospherics/components/unary/thermomachine/freezer,
+/obj/machinery/atmospherics/components/unary/thermomachine/heater,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bMO" = (
@@ -38739,15 +38748,13 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bMY" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 4
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
+ dir = 1
},
-/turf/closed/wall/r_wall,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bMZ" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 6
- },
+/obj/machinery/atmospherics/components/unary/thermomachine/heater/on,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bNc" = (
@@ -39075,6 +39082,9 @@
/obj/machinery/light{
dir = 8
},
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bNU" = (
@@ -39136,7 +39146,7 @@
/area/engine/atmos)
"bOe" = (
/obj/machinery/meter,
-/obj/machinery/atmospherics/pipe/manifold4w/cyan/visible,
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bOf" = (
@@ -39147,13 +39157,7 @@
/turf/open/floor/plating,
/area/engine/atmos)
"bOg" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 4
- },
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 1;
- name = "Mix to Incinerator"
- },
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bOh" = (
@@ -39460,17 +39464,16 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bOR" = (
-/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
+/obj/machinery/meter,
+/obj/machinery/atmospherics/pipe/manifold/purple/visible{
dir = 1
},
-/obj/machinery/meter,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bOS" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
},
-/obj/structure/tank_dispenser,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bOT" = (
@@ -39483,8 +39486,8 @@
/area/engine/atmos)
"bOU" = (
/obj/machinery/holopad,
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -39571,35 +39574,34 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPe" = (
-/obj/machinery/atmospherics/pipe/manifold/yellow/visible,
+/obj/machinery/atmospherics/pipe/manifold/purple/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPf" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+/obj/machinery/atmospherics/pipe/simple/purple/visible{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPg" = (
-/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/purple/visible{
+ dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/turf/open/floor/plasteel,
/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" = (
/obj/machinery/light{
dir = 4
},
-/obj/machinery/atmospherics/pipe/manifold/yellow/visible,
/obj/effect/turf_decal/tile/green{
dir = 1
},
@@ -39607,6 +39609,9 @@
/obj/effect/turf_decal/tile/green{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/purple/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPj" = (
@@ -40030,8 +40035,8 @@
/obj/machinery/computer/atmos_alert{
dir = 8
},
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
},
/turf/open/floor/plasteel/dark/corner,
/area/engine/atmos)
@@ -40045,7 +40050,11 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/effect/spawner/structure/window,
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/door/poddoor/preopen{
+ id = "atmos";
+ name = "Atmospherics Blast Door"
+ },
/turf/open/floor/plating,
/area/engine/atmos)
"bQo" = (
@@ -40089,7 +40098,7 @@
/turf/open/floor/plasteel,
/area/security/checkpoint/engineering)
"bQr" = (
-/obj/structure/closet/crate,
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bQs" = (
@@ -40113,38 +40122,31 @@
/turf/open/floor/plasteel/dark/corner,
/area/hallway/primary/aft)
"bQu" = (
-/obj/structure/rack,
-/obj/item/clothing/suit/hazardvest,
-/obj/item/clothing/suit/hazardvest,
-/obj/item/clothing/suit/hazardvest,
-/obj/item/clothing/suit/hazardvest,
-/obj/item/clothing/gloves/color/black,
-/obj/item/clothing/gloves/color/black,
-/obj/item/clothing/gloves/color/black,
-/obj/item/clothing/mask/gas,
-/obj/item/clothing/mask/gas,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/closet/crate,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bQv" = (
+/obj/machinery/atmospherics/pipe/simple/purple/visible,
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bQw" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 9
+/obj/machinery/atmospherics/pipe/manifold/green/visible{
+ dir = 1
},
/turf/open/floor/plasteel,
/area/engine/atmos)
"bQx" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/green/visible{
+ dir = 6
},
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 1;
- name = "Mix to Distro"
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 9
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -40161,6 +40163,9 @@
/obj/effect/turf_decal/tile/green{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/green/visible{
+ dir = 10
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bQA" = (
@@ -40436,6 +40441,11 @@
/area/hallway/primary/aft)
"bRr" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/firealarm{
+ dir = 1;
+ pixel_y = -24
+ },
+/obj/structure/tank_dispenser,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRs" = (
@@ -40447,11 +40457,7 @@
/turf/open/floor/plating,
/area/engine/atmos)
"bRt" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/firealarm{
- dir = 1;
- pixel_y = -24
- },
+/obj/structure/reagent_dispensers/fueltank,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRu" = (
@@ -40461,7 +40467,6 @@
/obj/machinery/computer/atmos_alert{
dir = 8
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/dark/corner,
/area/engine/atmos)
"bRv" = (
@@ -40480,8 +40485,10 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRx" = (
-/obj/effect/spawner/structure/window,
-/turf/open/floor/plating,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bRy" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
@@ -40499,8 +40506,9 @@
/obj/structure/cable{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
- dir = 4
+/obj/machinery/atmospherics/components/binary/pump/on{
+ dir = 8;
+ name = "Waste to Filter"
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -40516,26 +40524,26 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRD" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
+ dir = 9
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRE" = (
-/obj/machinery/atmospherics/pipe/manifold/green/visible{
- dir = 1
+/obj/machinery/atmospherics/components/binary/pump{
+ name = "Air to Ports"
},
-/obj/machinery/meter,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRF" = (
-/obj/machinery/atmospherics/pipe/simple/green/visible{
- dir = 4
+/obj/machinery/atmospherics/components/binary/pump{
+ name = "Mix to Ports"
},
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRG" = (
-/obj/machinery/atmospherics/pipe/manifold/green/visible{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/green/visible{
+ dir = 5
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -40552,6 +40560,14 @@
dir = 4;
name = "Unfiltered & Air to Mix"
},
+/obj/machinery/atmospherics/pipe/simple/green/visible,
+/obj/effect/turf_decal/tile/green{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/green,
+/obj/effect/turf_decal/tile/green{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bRL" = (
@@ -40839,11 +40855,7 @@
/area/hallway/primary/aft)
"bSB" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/door/airlock/atmos/glass{
- name = "Atmospherics Monitoring";
- req_access_txt = "24"
- },
-/turf/open/floor/plasteel,
+/turf/closed/wall,
/area/engine/atmos)
"bSC" = (
/obj/machinery/atmospherics/pipe/simple/orange/visible{
@@ -40853,13 +40865,19 @@
/area/engine/atmos)
"bSD" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/closed/wall,
+/obj/machinery/door/airlock/atmos/glass{
+ name = "Atmospherics Monitoring";
+ req_access_txt = "24"
+ },
+/obj/machinery/door/firedoor/heavy,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bSE" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 1;
+ name = "Pure to Mix"
},
-/turf/closed/wall,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bSF" = (
/obj/effect/turf_decal/bot,
@@ -40891,13 +40909,15 @@
/area/engine/atmos)
"bSM" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
+/obj/machinery/atmospherics/pipe/simple/general/visible{
+ dir = 5
+ },
/turf/open/floor/plating,
/area/engine/atmos)
"bSN" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/green/visible{
- dir = 5
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 10
},
/turf/open/floor/plating,
/area/engine/atmos)
@@ -41235,7 +41255,12 @@
/obj/machinery/atmospherics/pipe/simple/orange/visible{
dir = 4
},
-/turf/open/floor/plasteel,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark/corner{
+ dir = 1
+ },
/area/engine/atmos)
"bTM" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
@@ -41248,14 +41273,16 @@
/obj/machinery/atmospherics/pipe/simple/orange/visible{
dir = 4
},
-/obj/effect/spawner/structure/window,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bTO" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 1;
+ name = "External to Waste"
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bTP" = (
@@ -41265,19 +41292,14 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bTQ" = (
-/obj/machinery/atmospherics/components/binary/pump/on{
- dir = 8;
- name = "Waste to Filter"
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 5
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
-/turf/open/floor/plasteel,
+/turf/open/floor/plating,
/area/engine/atmos)
"bTR" = (
-/obj/machinery/atmospherics/components/binary/pump/on{
- dir = 8;
- name = "Filter to Waste"
- },
-/obj/machinery/atmospherics/pipe/simple/cyan/visible,
+/obj/machinery/atmospherics/pipe/manifold/orange/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bTS" = (
@@ -41285,15 +41307,16 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bTU" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 5
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Pure to Ports"
},
/turf/open/floor/plasteel,
/area/engine/atmos)
"bTV" = (
/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
- name = "N2O Outlet Pump"
+ name = "N2O to Pure"
},
/obj/effect/turf_decal/tile/red{
dir = 4
@@ -41639,7 +41662,9 @@
/area/engine/atmos)
"bUL" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/green/visible,
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 4
+ },
/turf/open/floor/plating,
/area/engine/atmos)
"bUM" = (
@@ -41653,9 +41678,7 @@
/area/engine/atmos)
"bUN" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/green/visible{
- dir = 10
- },
+/obj/machinery/atmospherics/pipe/simple/green/visible,
/turf/open/floor/plating,
/area/engine/atmos)
"bUO" = (
@@ -41681,7 +41704,7 @@
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"
},
@@ -41695,6 +41718,9 @@
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/green/visible,
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel/white/corner,
/area/engine/atmos)
"bUU" = (
@@ -42023,10 +42049,10 @@
/turf/closed/wall/r_wall,
/area/engine/atmos)
"bVP" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
- dir = 6
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "External to Pumps"
},
-/obj/effect/spawner/structure/window,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bVQ" = (
@@ -42122,6 +42148,12 @@
/obj/machinery/atmospherics/components/trinary/filter/atmos/n2o{
dir = 1
},
+/obj/effect/turf_decal/tile/red{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
/turf/open/floor/plasteel/white/corner,
/area/engine/atmos)
"bWd" = (
@@ -42402,7 +42434,12 @@
dir = 4;
pixel_x = -22
},
-/turf/open/floor/plasteel,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark/corner{
+ dir = 1
+ },
/area/engine/atmos)
"bWO" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
@@ -42411,8 +42448,10 @@
/turf/closed/wall/r_wall,
/area/engine/atmos)
"bWP" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
-/turf/closed/wall,
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bWQ" = (
/turf/closed/wall/r_wall,
@@ -42436,7 +42475,7 @@
/obj/structure/cable{
icon_state = "1-4"
},
-/turf/open/floor/plating,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bWU" = (
/obj/machinery/light{
@@ -42774,7 +42813,12 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
dir = 9
},
-/turf/closed/wall,
+/obj/machinery/door/poddoor/preopen{
+ id = "atmos";
+ name = "Atmospherics Blast Door"
+ },
+/obj/effect/turf_decal/delivery,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bXM" = (
/obj/machinery/door/poddoor/preopen{
@@ -42853,7 +42897,10 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bXU" = (
-/obj/structure/reagent_dispensers/fueltank,
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Ports to External"
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bXV" = (
@@ -42863,12 +42910,19 @@
},
/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
- name = "Plasma Outlet Pump"
+ name = "Plasma to Pure"
},
+/obj/machinery/atmospherics/pipe/simple/green/visible,
/obj/effect/turf_decal/stripes/line{
dir = 5
},
-/obj/machinery/atmospherics/pipe/simple/green/visible,
+/obj/effect/turf_decal/tile/purple{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/purple,
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bXW" = (
@@ -43172,17 +43226,8 @@
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"bYJ" = (
-/obj/effect/turf_decal/tile/yellow{
- dir = 4
- },
-/obj/machinery/door/airlock/atmos{
- name = "Atmospherics";
- req_access_txt = "24"
- },
-/obj/machinery/door/firedoor/heavy,
-/turf/open/floor/plasteel/dark/corner{
- dir = 1
- },
+/obj/machinery/atmospherics/pipe/manifold4w/general/visible,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bYK" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
@@ -43215,11 +43260,8 @@
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"bYN" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
- dir = 4
- },
-/turf/open/floor/plating,
+/obj/machinery/atmospherics/pipe/manifold4w/yellow/visible,
+/turf/open/floor/plasteel,
/area/engine/atmos)
"bYO" = (
/obj/structure/disposalpipe/segment{
@@ -43235,10 +43277,14 @@
/obj/machinery/computer/atmos_control/tank/toxin_tank{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/green/visible,
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/green/visible,
+/obj/effect/turf_decal/tile/purple,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bYU" = (
@@ -43539,16 +43585,32 @@
/area/engine/atmos)
"bZH" = (
/obj/machinery/portable_atmospherics/canister,
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bZI" = (
-/obj/machinery/portable_atmospherics/scrubber,
+/obj/machinery/space_heater,
+/obj/effect/turf_decal/stripes/line{
+ dir = 9
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bZK" = (
/obj/machinery/atmospherics/components/trinary/filter/atmos/plasma{
dir = 1
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/purple,
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bZL" = (
@@ -43933,13 +43995,18 @@
/turf/closed/wall/r_wall,
/area/security/checkpoint/engineering)
"caE" = (
-/obj/structure/reagent_dispensers/watertank/high,
+/obj/machinery/atmospherics/pipe/manifold/general/visible{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"caF" = (
/obj/machinery/atmospherics/pipe/simple/green/visible{
dir = 6
},
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 9
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"caG" = (
@@ -43953,12 +44020,10 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"caH" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 5
- },
/obj/effect/decal/cleanable/oil{
icon_state = "floor6"
},
+/obj/machinery/atmospherics/pipe/manifold/yellow/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"caI" = (
@@ -44366,14 +44431,17 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cbA" = (
-/obj/machinery/portable_atmospherics/pump,
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 4;
+ name = "Ports to Incinerator"
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"cbB" = (
/obj/machinery/atmospherics/pipe/simple/green/visible,
/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
- name = "Air Outlet Pump"
+ name = "Air to Pure"
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -44407,7 +44475,7 @@
"cbG" = (
/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
- name = "CO2 Outlet Pump"
+ name = "CO2 to Pure"
},
/obj/effect/turf_decal/tile/yellow{
dir = 1
@@ -44783,7 +44851,10 @@
/turf/closed/wall/r_wall,
/area/engine/engineering)
"ccy" = (
-/obj/machinery/space_heater,
+/obj/machinery/atmospherics/pipe/simple/yellow/visible,
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"ccz" = (
@@ -45132,15 +45203,24 @@
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/engine/atmos)
"cdB" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 9
+/obj/machinery/atmospherics/pipe/simple/cyan/visible,
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/dark/visible{
+ dir = 4
},
-/turf/open/floor/plasteel,
+/turf/open/floor/plating,
/area/engine/atmos)
"cdC" = (
/obj/machinery/atmospherics/components/trinary/filter/atmos/co2{
dir = 1
},
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/yellow,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"cdD" = (
@@ -45735,7 +45815,10 @@
/turf/open/floor/plasteel,
/area/engine/break_room)
"cfi" = (
-/obj/machinery/portable_atmospherics/scrubber/huge,
+/obj/effect/turf_decal/stripes/line{
+ dir = 10
+ },
+/obj/structure/reagent_dispensers/watertank/high,
/turf/open/floor/plasteel,
/area/engine/atmos)
"cfj" = (
@@ -46428,6 +46511,13 @@
/obj/machinery/atmospherics/components/trinary/filter/atmos/o2{
dir = 4
},
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"chb" = (
@@ -46470,8 +46560,11 @@
/turf/open/floor/plasteel/cafeteria,
/area/engine/atmos)
"che" = (
-/obj/machinery/door/airlock/atmos{
- name = "Atmospherics";
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
+/obj/machinery/door/airlock/external{
+ name = "Atmospherics External Airlock";
req_access_txt = "24"
},
/turf/open/floor/plating,
@@ -46942,8 +47035,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" = (
@@ -52243,7 +52336,9 @@
/area/science/mixing)
"cBF" = (
/obj/effect/landmark/event_spawn,
-/obj/machinery/atmospherics/pipe/manifold4w/scrubbers/visible,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"cBH" = (
@@ -52432,10 +52527,10 @@
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
"cCE" = (
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/general/visible{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"cCF" = (
@@ -52528,10 +52623,7 @@
/turf/open/floor/wood,
/area/crew_quarters/theatre)
"cGG" = (
-/obj/effect/spawner/structure/window,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 10
- },
+/obj/machinery/atmospherics/pipe/simple/general/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"cHf" = (
@@ -53723,6 +53815,13 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
+"dkV" = (
+/obj/machinery/space_heater,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"dly" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -53985,12 +54084,8 @@
},
/area/crew_quarters/fitness/pool)
"ecE" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 4
- },
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 1;
- name = "Mix to Waste"
+/obj/machinery/atmospherics/pipe/simple/general/visible{
+ dir = 5
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -54751,6 +54846,11 @@
/obj/effect/landmark/event_spawn,
/turf/open/floor/plasteel,
/area/science/circuit)
+"fKv" = (
+/obj/machinery/portable_atmospherics/scrubber/huge,
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"fMp" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/dark,
@@ -54932,13 +55032,9 @@
/turf/open/floor/carpet,
/area/crew_quarters/cryopod)
"gfJ" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+/obj/machinery/atmospherics/pipe/simple/general/visible{
dir = 4
},
-/obj/machinery/door/airlock/atmos{
- name = "Atmospherics";
- req_access_txt = "24"
- },
/turf/open/floor/plasteel,
/area/engine/atmos)
"ghD" = (
@@ -54975,11 +55071,12 @@
dir = 4
},
/obj/structure/closet/secure_closet/atmospherics,
-/obj/item/cartridge/atmos,
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark/corner{
dir = 1
},
-/turf/open/floor/plasteel,
/area/engine/atmos)
"gnf" = (
/obj/structure/disposalpipe/segment{
@@ -55478,6 +55575,13 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"hOd" = (
+/obj/machinery/portable_atmospherics/scrubber,
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"hOv" = (
/obj/structure/table/wood/fancy,
/obj/item/reagent_containers/food/snacks/burger/plain,
@@ -55891,9 +55995,17 @@
/turf/open/floor/plasteel,
/area/engine/engineering)
"iYC" = (
-/obj/effect/spawner/structure/window,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plasteel,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/machinery/door/firedoor/heavy,
+/obj/machinery/door/airlock/atmos{
+ name = "Atmospherics";
+ req_access_txt = "24"
+ },
+/turf/open/floor/plasteel/dark/corner{
+ dir = 1
+ },
/area/engine/atmos)
"iYE" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
@@ -56426,6 +56538,13 @@
},
/turf/open/floor/plating,
/area/maintenance/fore/secondary)
+"khU" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 4;
+ name = "N2 to Pure"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"khV" = (
/obj/machinery/vending/cola/red,
/obj/structure/sign/poster/contraband/robust_softdrinks{
@@ -57729,6 +57848,13 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
+"nNP" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 4;
+ name = "O2 to Pure"
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"nQi" = (
/obj/machinery/recharge_station,
/turf/open/floor/plating,
@@ -58344,6 +58470,13 @@
},
/turf/open/floor/wood,
/area/crew_quarters/bar)
+"plL" = (
+/obj/machinery/portable_atmospherics/pump,
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"plS" = (
/obj/machinery/door/window/brigdoor/security/cell{
id = "Cell 1";
@@ -58918,11 +59051,12 @@
dir = 4
},
/obj/structure/closet/secure_closet/atmospherics,
-/obj/item/cartridge/atmos,
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark/corner{
dir = 1
},
-/turf/open/floor/plasteel,
/area/engine/atmos)
"rcD" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
@@ -59114,6 +59248,13 @@
},
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
+"rto" = (
+/obj/machinery/portable_atmospherics/scrubber,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"rtC" = (
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/plating,
@@ -59432,6 +59573,12 @@
/obj/effect/spawner/lootdrop/maintenance,
/turf/open/floor/plating,
/area/maintenance/fore)
+"siv" = (
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 9
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"slk" = (
/obj/machinery/door/airlock/maintenance{
req_access_txt = "12"
@@ -61316,6 +61463,11 @@
},
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
+"wcr" = (
+/obj/machinery/portable_atmospherics/pump,
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"wcB" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 10
@@ -61469,7 +61621,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)
"wAh" = (
@@ -61917,6 +62069,12 @@
/obj/item/radio/headset/headset_cargo,
/turf/open/floor/plasteel,
/area/quartermaster/storage)
+"xBF" = (
+/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/engine/atmos)
"xDM" = (
/obj/machinery/camera{
c_tag = "Locker Room South";
@@ -92203,7 +92361,7 @@ bUF
bVN
bWN
bXM
-bYJ
+bLK
bRi
bZy
cbu
@@ -92453,14 +92611,14 @@ alk
bNQ
bOV
bQk
-bRt
+bVQ
bSD
bTM
bUH
bVQ
bVZ
bXM
-bLK
+iYC
cew
bTh
cdt
@@ -92709,13 +92867,13 @@ bLL
bOd
bNQ
bOU
-bTO
-bRr
-bSE
+bQj
+bOd
+bMK
bTN
-gfJ
-bVP
-bWP
+bTP
+bRy
+cfN
bXL
bLK
bRj
@@ -92968,8 +93126,8 @@ bNS
bOX
bQm
bRv
-cGG
-glY
+bRs
+rca
bTP
bVX
bWQ
@@ -93225,7 +93383,7 @@ bNR
bOW
bQl
bRu
-iYC
+bRs
rca
bUI
bVR
@@ -93481,7 +93639,7 @@ bMK
bMK
bOY
bQn
-bRx
+bRs
bMK
bUP
bUJ
@@ -93736,7 +93894,7 @@ bKz
bLK
bQr
bNT
-bOV
+bQu
bQo
bRw
bSF
@@ -94249,7 +94407,7 @@ bJv
bKB
bLK
bMM
-bNV
+bOd
bOQ
bQj
bRy
@@ -94518,12 +94676,12 @@ bVV
bVV
bWT
bZG
-caE
-cbA
-ccy
-bZH
-bZI
-bQu
+bOd
+bOd
+bOd
+bOd
+bOd
+bOd
bOd
cgW
cit
@@ -94766,19 +94924,19 @@ bMO
bIF
bOZ
bQp
-bRA
-bTP
-bOd
+bRx
+bTO
+bTR
bOd
bOd
bOd
bOd
bXS
bOd
-bXU
-cbA
-ccy
-bZH
+bOd
+bOd
+bOd
+bOd
bZI
cfi
bOd
@@ -95022,10 +95180,10 @@ bLK
bMR
bIH
bJF
-bRy
-bTQ
-ecE
-bOd
+bRt
+bRA
+bTP
+bVP
bOd
bOd
bOd
@@ -95036,8 +95194,8 @@ bOd
bOd
bOd
bOd
-bOd
-bOd
+dkV
+fKv
cfQ
cgY
ciu
@@ -95279,11 +95437,11 @@ bLK
bMQ
bNY
bPa
-bYN
+bMQ
bRC
bSK
-bOd
-bOd
+bWP
+bZH
bOd
bOd
bOd
@@ -95293,8 +95451,8 @@ bOd
bOd
bOd
bOd
-bOd
-bOd
+rto
+wcr
apa
cgX
apF
@@ -95539,8 +95697,8 @@ bPd
cBF
bRD
bSK
-bOd
-bOd
+bWP
+bZH
bOd
bOd
bOd
@@ -95550,9 +95708,9 @@ bOd
bOd
cBJ
bOd
-bOd
-bOd
-bOd
+hOd
+plL
+bTP
cha
civ
axs
@@ -95794,10 +95952,10 @@ bMS
cfQ
bPc
bQs
-bTR
+cez
bSJ
-bOd
-bOd
+bWP
+bZH
bOd
bOd
bOd
@@ -95807,9 +95965,9 @@ bOd
bOd
bOd
bOd
-bOd
-bOd
-bOd
+cfQ
+cez
+siv
cgZ
bSK
crk
@@ -96053,9 +96211,7 @@ bOR
bQv
bRF
bSM
-bTS
-bOd
-bOd
+bXU
bOd
bOd
bOd
@@ -96066,6 +96222,8 @@ bOd
bOd
bOd
bOd
+bTP
+cfQ
cbD
chb
wzX
@@ -96307,15 +96465,13 @@ bLK
bMU
bOc
bPe
-bTP
+bMY
bRE
bUL
-cfT
-bOd
-bOd
-bOd
-bOd
-bOd
+bYJ
+caE
+cGG
+ecE
bOd
bOd
bOd
@@ -96323,6 +96479,8 @@ bOd
bOd
bOd
bOd
+khU
+nNP
cfP
ccz
bSJ
@@ -96562,12 +96720,15 @@ bvd
bKH
bLK
bMX
-bTP
+bMY
bPg
bQx
-bRF
-bSM
+bSE
+bTQ
bTU
+cbA
+bOd
+gfJ
bOd
bOd
bOd
@@ -96575,10 +96736,7 @@ bOd
bOd
bOd
bOd
-bOd
-bOd
-bMZ
-bTS
+xBF
caH
cbE
chd
@@ -96824,8 +96982,8 @@ bPf
bQw
bRG
bSN
-bPg
-bTS
+bYN
+ccy
bTS
cCE
bWa
@@ -96834,7 +96992,7 @@ bTS
bTS
bYL
bTS
-cdB
+bTS
caF
cbB
cfT
@@ -97332,14 +97490,14 @@ bvj
bvd
bKH
bLK
-bMY
+bLK
bOf
bPh
bQy
bRI
ceA
bPh
-bQy
+cdB
bRI
cCF
bPh
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 07fba56f90..9f7e39af54 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -3807,7 +3807,8 @@
movement_type = 1;
name = "Sergeant Araneus";
real_name = "Sergeant Araneus";
- response_help = "pets";
+ response_help_continuous = "pets";
+ response_help_simple = "pet";
turns_per_move = 10
},
/turf/open/floor/carpet,
diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm
index 737028385a..35d7152eeb 100644
--- a/_maps/map_files/Mining/Lavaland.dmm
+++ b/_maps/map_files/Mining/Lavaland.dmm
@@ -2367,9 +2367,7 @@
/obj/item/seeds/cotton{
yield = 5
},
-/obj/item/seeds/cotton{
- yield = 5
- },
+/obj/item/seeds/cotton/durathread,
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"Vj" = (
diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 0b46f21a97..e8e75c132a 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -83,10 +83,3 @@
#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you
-
-///Max length of a keypress command before it's considered to be a forged packet/bogus command
-#define MAX_KEYPRESS_COMMANDLENGTH 16
-///Max amount of keypress messages per second over two seconds before client is autokicked
-#define MAX_KEYPRESS_AUTOKICK 100
-///Length of max held keys
-#define MAX_HELD_KEYS 15
diff --git a/code/__DEFINES/admin/keybindings.dm b/code/__DEFINES/admin/keybindings.dm
new file mode 100644
index 0000000000..3efc26c7d5
--- /dev/null
+++ b/code/__DEFINES/admin/keybindings.dm
@@ -0,0 +1,18 @@
+// Defines for managed input/keybinding system.
+/// Max length of a keypress command before it's considered to be a forged packet/bogus command
+#define MAX_KEYPRESS_COMMANDLENGTH 16
+/// Maximum keys that can be bound to one button
+#define MAX_COMMANDS_PER_KEY 5
+/// Maximum keys per keybind
+#define MAX_KEYS_PER_KEYBIND 3
+/// Max amount of keypress messages per second over two seconds before client is autokicked
+#define MAX_KEYPRESS_AUTOKICK 100
+/// Max keys that can be held down at once by a client
+#define MAX_HELD_KEYS 15
+
+/// Macroset name of hotkeys/keybind only/modern mode
+#define SKIN_MACROSET_HOTKEYS "hotkeys"
+/// Macroset name of classic hotkey mode
+#define SKIN_MACROSET_CLASSIC_HOTKEYS "oldhotkeys"
+/// Macroset name of classic input mode
+#define SKIN_MACROSET_CLASSIC_INPUT "oldinput"
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index eb71b8b5bb..bcb29d72a5 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -149,7 +149,7 @@
// /mob signals
#define COMSIG_MOB_CLICKED_SHIFT_ON "mob_shift_click_on" //from base of /atom/ShiftClick(): (atom/A), for return values, see COMSIG_CLICK_SHIFT
-#define COMSIG_MOB_VISIBLE_ATOMS "mob_visible_atoms" //from base of mob/visible_atoms(): (list/visible_atoms)
+#define COMSIG_MOB_FOV_VIEW "mob_visible_atoms" //from base of mob/fov_view(): (list/visible_atoms)
#define COMSIG_MOB_EXAMINATE "mob_examinate" //from base of /mob/verb/examinate(): (atom/A), for return values, see COMSIG_CLICK_SHIFT
#define COMPONENT_EXAMINATE_BLIND 3 //outputs the "something is there but you can't see it" message.
#define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed)
@@ -185,7 +185,7 @@
#define SPEECH_LANGUAGE 5
// #define SPEECH_IGNORE_SPAM 6
// #define SPEECH_FORCED 7
-#define COMSIG_MOB_IS_VIEWER "mob_is_viewer" //from base of /get_actual_viewers(): (atom/center, depth, viewers_list)
+#define COMSIG_MOB_FOV_VIEWER "mob_is_viewer" //from base of /fov_viewers(): (atom/center, depth, viewers_list)
#define COMSIG_MOB_GET_VISIBLE_MESSAGE "mob_get_visible_message" //from base of atom/visible_message(): (atom/A, msg, range, ignored_mobs)
#define COMPONENT_NO_VISIBLE_MESSAGE 1 //exactly what's said on the tin.
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
@@ -326,6 +326,9 @@
#define COMSIG_SPECIES_GAIN "species_gain" //from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
#define COMSIG_SPECIES_LOSS "species_loss" //from datum/species/on_species_loss(): (datum/species/lost_species)
+// /datum/mutation signals
+#define COMSIG_HUMAN_MUTATION_LOSS "human_mutation_loss" //from datum/mutation/human/on_losing(): (datum/mutation/human/lost_mutation)
+
/*******Component Specific Signals*******/
//Janitor
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index 9d34bc14d2..9facaf5d70 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -20,27 +20,41 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define DF_ISPROCESSING (1<<2)
//FLAGS BITMASK
-
-#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
-#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this.
-#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.)
-#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff
-#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay
-#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving
-#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows
+///This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
+#define HEAR_1 (1<<3)
+///Projectiels will check ricochet on things impacted that have this.
+#define CHECK_RICOCHET_1 (1<<4)
+///Conducts electricity (metal etc.).
+#define CONDUCT_1 (1<<5)
+///For machines and structures that should not break into parts, eg, holodeck stuff.
+#define NODECONSTRUCT_1 (1<<7)
+///Atom queued to SSoverlay.
+#define OVERLAY_QUEUED_1 (1<<8)
+///Item has priority to check when entering or leaving.
+#define ON_BORDER_1 (1<<9)
+///Prevent clicking things below it on the same turf eg. doors/ fulltile windows.
+#define PREVENT_CLICK_UNDER_1 (1<<11)
#define HOLOGRAM_1 (1<<12)
-#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
-#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object
-#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff.
-#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) /// should not get harmed if this gets caught by an explosion?
-#define BLOCK_FACE_ATOM_1 (1<<17) /// Early returns mob.face_atom()
+///Prevents mobs from getting chainshocked by teslas and the supermatter.
+#define SHOCKED_1 (1<<13)
+///Whether /atom/Initialize() has already run for the object.
+#define INITIALIZED_1 (1<<14)
+///was this spawned by an admin? used for stat tracking stuff.
+#define ADMIN_SPAWNED_1 (1<<15)
+/// should not get harmed if this gets caught by an explosion?
+#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16)
+/// Early returns mob.face_atom()
+#define BLOCK_FACE_ATOM_1 (1<<17)
//turf-only flags
#define NOJAUNT_1 (1<<0)
#define UNUSED_RESERVATION_TURF_1 (1<<1)
-#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas.
-#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf
-#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf
+///If a turf can be made dirty at roundstart. This is also used in areas.
+#define CAN_BE_DIRTY_1 (1<<2)
+///Blocks lava rivers being generated on the turf.
+#define NO_LAVA_GEN_1 (1<<6)
+///Blocks ruins spawning on the turf.
+#define NO_RUINS_1 (1<<10)
/*
These defines are used specifically with the atom/pass_flags bitmask
@@ -76,14 +90,15 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define GOLIATH_WEAKNESS (1<<9) //CIT CHANGE
//tesla_zap
-#define TESLA_MACHINE_EXPLOSIVE (1<<0)
-#define TESLA_ALLOW_DUPLICATES (1<<1)
-#define TESLA_OBJ_DAMAGE (1<<2)
-#define TESLA_MOB_DAMAGE (1<<3)
-#define TESLA_MOB_STUN (1<<4)
+#define ZAP_MACHINE_EXPLOSIVE (1<<0)
+#define ZAP_ALLOW_DUPLICATES (1<<1)
+#define ZAP_OBJ_DAMAGE (1<<2)
+#define ZAP_MOB_DAMAGE (1<<3)
+#define ZAP_MOB_STUN (1<<4)
-#define TESLA_DEFAULT_FLAGS ALL
-#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN
+#define ZAP_DEFAULT_FLAGS ALL
+#define ZAP_FUSION_FLAGS ZAP_OBJ_DAMAGE | ZAP_MOB_DAMAGE | ZAP_MOB_STUN
+#define ZAP_SUPERMATTER_FLAGS NONE
//EMP protection
#define EMP_PROTECT_SELF (1<<0)
diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm
index 16d763606b..5acda2274c 100644
--- a/code/__DEFINES/footsteps.dm
+++ b/code/__DEFINES/footsteps.dm
@@ -24,6 +24,15 @@
#define FOOTPRINT_SNAKE "snake"
#define FOOTPRINT_DRAG "drag"
+//footstep mob defines
+#define FOOTSTEP_MOB_CLAW 1
+#define FOOTSTEP_MOB_BAREFOOT 2
+#define FOOTSTEP_MOB_HEAVY 3
+#define FOOTSTEP_MOB_SHOE 4
+#define FOOTSTEP_MOB_HUMAN 5 //Warning: Only works on /mob/living/carbon/human
+#define FOOTSTEP_MOB_SLIME 6
+#define FOOTSTEP_MOB_CRAWL 7
+
/*
id = list(
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 122ba67402..28ec3383ae 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -148,50 +148,6 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isclown(A) (istype(A, /mob/living/simple_animal/hostile/retaliate/clown))
-GLOBAL_LIST_INIT(shoefootmob, typecacheof(list(
- /mob/living/carbon/human/,
- /mob/living/simple_animal/cow,
- /mob/living/simple_animal/hostile/cat_butcherer,
- /mob/living/simple_animal/hostile/faithless,
- /mob/living/simple_animal/hostile/nanotrasen,
- /mob/living/simple_animal/hostile/pirate,
- /mob/living/simple_animal/hostile/russian,
- /mob/living/simple_animal/hostile/syndicate,
- /mob/living/simple_animal/hostile/wizard,
- /mob/living/simple_animal/hostile/zombie,
- /mob/living/simple_animal/hostile/retaliate/clown,
- /mob/living/simple_animal/hostile/retaliate/spaceman,
- /mob/living/simple_animal/hostile/retaliate/nanotrasenpeace,
- /mob/living/simple_animal/hostile/retaliate/goat,
- /mob/living/carbon/true_devil,
- )))
-
-GLOBAL_LIST_INIT(clawfootmob, typecacheof(list(
- /mob/living/carbon/alien/humanoid,
- /mob/living/simple_animal/hostile/alien,
- /mob/living/simple_animal/pet/cat,
- /mob/living/simple_animal/pet/dog,
- /mob/living/simple_animal/pet/fox,
- /mob/living/simple_animal/chicken,
- /mob/living/simple_animal/hostile/bear,
- /mob/living/simple_animal/hostile/jungle/mega_arachnid,
- /mob/living/simple_animal/hostile/asteroid/ice_whelp,
- /mob/living/simple_animal/hostile/asteroid/wolf,
- /mob/living/simple_animal/hostile/asteroid/polarbear
- )))
-
-GLOBAL_LIST_INIT(barefootmob, typecacheof(list(
- /mob/living/carbon/monkey,
- /mob/living/simple_animal/pet/penguin,
- /mob/living/simple_animal/hostile/gorilla,
- /mob/living/simple_animal/hostile/jungle/mook
- )))
-
-GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
- /mob/living/simple_animal/hostile/megafauna,
- /mob/living/simple_animal/hostile/jungle/leaper
- )))
-
//Misc mobs
#define isobserver(A) (istype(A, /mob/dead/observer))
diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm
index 210e5a4a35..6f33bb1a0e 100644
--- a/code/__DEFINES/layers_planes.dm
+++ b/code/__DEFINES/layers_planes.dm
@@ -42,6 +42,7 @@
#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
#define BLACKNESS_PLANE_RENDER_TARGET "BLACKNESS_PLANE"
+///Layers most often used by atoms of plane lower than GAME_PLANE
#define SPACE_LAYER 1.8
//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define
#define MID_TURF_LAYER 2.02
@@ -61,11 +62,12 @@
#define GAS_PIPE_VISIBLE_LAYER 2.47
#define GAS_FILTER_LAYER 2.48
#define GAS_PUMP_LAYER 2.49
+
#define LOW_OBJ_LAYER 2.5
#define LOW_SIGIL_LAYER 2.52
#define SIGIL_LAYER 2.54
#define HIGH_SIGIL_LAYER 2.56
-
+///Layers most often used by atoms of plane equal or higher than GAME_PLANE
#define BELOW_OPEN_DOOR_LAYER 2.6
#define BLASTDOOR_LAYER 2.65
#define OPEN_DOOR_LAYER 2.7
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 0122cc68d8..c7e1d7b672 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -463,7 +463,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define PDAIMG(what) {""}
//Filters
-#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"color"="#04080FAA")
+#define AMBIENT_OCCLUSION(_size, _color) list("type"="drop_shadow","x"=0,"y"=-2,"size"=_size,"color"=_color)
#define EYE_BLUR(size) list("type"="blur", "size"=size)
#define GRAVITY_MOTION_BLUR list("type"="motion_blur","x"=0,"y"=0)
diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm
index affa23d30a..09cea91540 100644
--- a/code/__DEFINES/robots.dm
+++ b/code/__DEFINES/robots.dm
@@ -51,6 +51,19 @@
#define ASSEMBLY_FOURTH_STEP 3
#define ASSEMBLY_FIFTH_STEP 4
+//Bot Upgrade defines
+#define UPGRADE_CLEANER_ADVANCED_MOP (1<<0)
+#define UPGRADE_CLEANER_BROOM (1<<1)
+
+#define UPGRADE_MEDICAL_HYPOSPRAY (1<<0)
+#define UPGRADE_MEDICAL_CHEM_BOARD (1<<1)
+#define UPGRADE_MEDICAL_CRYO_BOARD (1<<2)
+#define UPGRADE_MEDICAL_CHEM_MASTER (1<<3)
+#define UPGRADE_MEDICAL_SLEEP_BOARD (1<<4)
+#define UPGRADE_MEDICAL_PIERERCING (1<<5)
+
+#define UPGRADE_FLOOR_ARTBOX (1<<0)
+#define UPGRADE_FLOOR_SYNDIBOX (1<<1)
//Checks to determine borg availability depending on the server's config. These are defines in the interest of reducing copypasta
#define BORG_SEC_AVAILABLE (!CONFIG_GET(flag/disable_secborg) && GLOB.security_level >= CONFIG_GET(number/minimum_secborg_alert))
diff --git a/code/__DEFINES/rust_g.config.dm b/code/__DEFINES/rust_g.config.dm
deleted file mode 100644
index 68a1b42fb1..0000000000
--- a/code/__DEFINES/rust_g.config.dm
+++ /dev/null
@@ -1 +0,0 @@
-#define RUSTG_OVERRIDE_BUILTINS
\ No newline at end of file
diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm
index ccd5b92c79..aeacdb7c51 100644
--- a/code/__DEFINES/rust_g.dm
+++ b/code/__DEFINES/rust_g.dm
@@ -1,10 +1,27 @@
// rust_g.dm - DM API for rust_g extension library
#define RUST_G "rust_g"
+#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
+#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
+#define RUSTG_JOB_ERROR "JOB PANICKED"
+
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
+#define rustg_dmi_create_png(fname,width,height,data) call(RUST_G, "dmi_create_png")(fname,width,height,data)
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
-#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text)
+#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
+
+// RUST-G defines & procs for HTTP component
+#define RUSTG_HTTP_METHOD_GET "get"
+#define RUSTG_HTTP_METHOD_POST "post"
+#define RUSTG_HTTP_METHOD_PUT "put"
+#define RUSTG_HTTP_METHOD_DELETE "delete"
+#define RUSTG_HTTP_METHOD_PATCH "patch"
+#define RUSTG_HTTP_METHOD_HEAD "head"
+
+#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
+#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
+#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm
index 9127b4e3dd..659c0fe11b 100644
--- a/code/__DEFINES/skills/defines.dm
+++ b/code/__DEFINES/skills/defines.dm
@@ -27,25 +27,27 @@
#define DEF_SKILL_GAIN 1
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
-#define SKILL_AFFINITY_MOOD_BONUS 1.25
+//An extra point for each few seconds of delay when using a tool. Before the multiplier.
+#define SKILL_GAIN_DELAY_DIVISOR 3 SECONDS
-///Items skill_flags and other defines
-#define SKILL_USE_TOOL (1<<0)
-#define SKILL_TRAINING_TOOL (1<<1)
-#define SKILL_ATTACK_MOB (1<<2)
-#define SKILL_TRAIN_ATTACK_MOB (1<<3)
-#define SKILL_ATTACK_OBJ (1<<4)
-#define SKILL_TRAIN_ATTACK_OBJ (1<<5)
-#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage.
-#define SKILL_THROW_STAM_COST (1<<7)
-#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on.
-#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood.
-#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood.
+///Items skill_traits and other defines
+#define SKILL_USE_TOOL "use_tool"
+#define SKILL_TRAINING_TOOL "training_tool"
+#define SKILL_ATTACK_MOB "attack_mob"
+#define SKILL_TRAIN_ATTACK_MOB "train_attack_mob"
+#define SKILL_ATTACK_OBJ "attack_obj"
+#define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj"
+#define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage.
+#define SKILL_THROW_STAM_COST "throw_stam_cost"
+#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on.
+#define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity.
+#define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage?
-///competency_threshold index defines
-#define THRESHOLD_COMPETENT 1
-#define THRESHOLD_EXPERT 2
-#define THRESHOLD_MASTER 3
+///competency_threshold defines
+#define THRESHOLD_UNTRAINED "untrained"
+#define THRESHOLD_COMPETENT "competent"
+#define THRESHOLD_EXPERT "expert"
+#define THRESHOLD_MASTER "master"
/// Level/Experience skills defines.
#define STD_XP_LVL_UP 100
@@ -88,11 +90,14 @@
#define MODIFIER_SKILL_BODYBOUND (1<<6)
///Adds the difference of the current value and the value stored at the time the modifier was added to the result.
#define MODIFIER_SKILL_ORIGIN_DIFF (1<<7)
+///Will this skill use competency thresholds instead of preset values
+#define MODIFIER_USE_THRESHOLDS (1<<8)
#define MODIFIER_TARGET_VALUE "value"
#define MODIFIER_TARGET_LEVEL "level"
#define MODIFIER_TARGET_AFFINITY "affinity"
///Ascending priority defines.
+#define MODIFIER_SKILL_PRIORITY_LOW 100
#define MODIFIER_SKILL_PRIORITY_DEF 50
-#define MODIFIER_SKILL_PRIORITY_MAX 100 //max priority, meant for job/antag modifiers so they don't null out any debuff
+#define MODIFIER_SKILL_PRIORITY_MAX 1 //max priority, meant for job/antag modifiers so they don't null out other (de)buffs
\ No newline at end of file
diff --git a/code/__DEFINES/tgs.config.dm b/code/__DEFINES/tgs.config.dm
index 9f4f63a1fc..a2fcc7855a 100644
--- a/code/__DEFINES/tgs.config.dm
+++ b/code/__DEFINES/tgs.config.dm
@@ -4,8 +4,9 @@
#define TGS_READ_GLOBAL(Name) GLOB.##Name
#define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
#define TGS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]")
-#define TGS_INFO_LOG(message) log_world("TGS: Info: [##message]")
-#define TGS_ERROR_LOG(message) log_world("TGS: Error: [##message]")
+#define TGS_INFO_LOG(message) log_world("TGS Info: [##message]")
+#define TGS_WARNING_LOG(message) log_world("TGS Warn: [##message]")
+#define TGS_ERROR_LOG(message) log_world("TGS Error: [##message]")
#define TGS_NOTIFY_ADMINS(event) message_admins(##event)
#define TGS_CLIENT_COUNT GLOB.clients.len
#define TGS_PROTECT_DATUM(Path) GENERAL_PROTECT_DATUM(##Path)
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index dcccfc9295..e164a4ec96 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,5 +1,7 @@
//tgstation-server DMAPI
+#define TGS_DMAPI_VERSION "5.1.1"
+
//All functions and datums outside this document are subject to change with any version and should not be relied on
//CONFIGURATION
@@ -17,7 +19,6 @@
//Required interfaces (fill in with your codebase equivalent):
//create a global variable named `Name` and set it to `Value`
-//These globals must not be modifiable from anywhere outside of the server tools
#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value)
//Read the value in the global variable `Name`
@@ -26,10 +27,10 @@
//Set the value in the global variable `Name` to `Value`
#define TGS_WRITE_GLOBAL(Name, Value)
-//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game priveledge escalation
+//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game use of DD -> TGS capabilities
#define TGS_PROTECT_DATUM(Path)
-//display an announcement `message` from the server to all players
+//Display an announcement `message` from the server to all players
#define TGS_WORLD_ANNOUNCE(message)
//Notify current in-game administrators of a string `event`
@@ -38,6 +39,9 @@
//Write an info `message` to a server log
#define TGS_INFO_LOG(message)
+//Write an warning `message` to a server log
+#define TGS_WARNING_LOG(message)
+
//Write an error `message` to a server log
#define TGS_ERROR_LOG(message)
@@ -48,10 +52,12 @@
//EVENT CODES
-#define TGS_EVENT_PORT_SWAP -2 //before a port change is about to happen, extra parameter is new port
-#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //before a reboot mode change, extras parameters are the current and new reboot mode enums
+#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //Before a reboot mode change, extras parameters are the current and new reboot mode enums
+#define TGS_EVENT_PORT_SWAP -2 //Before a port change is about to happen, extra parameters is new port
+#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra parameter is the new name
+#define TGS_EVENT_WATCHDOG_REATTACH -4 //After the watchdog reattaches to DD, extra parameter is the new /datum/tgs_version of the server
-//See the descriptions for these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
+//See the descriptions for the parameters of these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
#define TGS_EVENT_REPO_RESET_ORIGIN 0
#define TGS_EVENT_REPO_CHECKOUT 1
#define TGS_EVENT_REPO_FETCH 2
@@ -63,9 +69,12 @@
#define TGS_EVENT_COMPILE_START 8
#define TGS_EVENT_COMPILE_CANCELLED 9
#define TGS_EVENT_COMPILE_FAILURE 10
-#define TGS_EVENT_COMPILE_COMPLETE 11
+#define TGS_EVENT_COMPILE_COMPLETE 11 // Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the TGS_EVENT_DEPLOYMENT_COMPLETE instead
#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
#define TGS_EVENT_REPO_MERGE_CONFLICT 13
+#define TGS_EVENT_DEPLOYMENT_COMPLETE 14
+#define TGS_EVENT_WATCHDOG_SHUTDOWN 15
+#define TGS_EVENT_WATCHDOG_DETACH 16
//OTHER ENUMS
@@ -80,6 +89,7 @@
//REQUIRED HOOKS
//Call this somewhere in /world/New() that is always run
+//IMPORTANT: This function may sleep!
//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels
//minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated
/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
@@ -109,12 +119,12 @@
//represents a version of tgstation-server
/datum/tgs_version
- var/suite //The suite version, can be >=3
+ var/suite //The suite/major version, can be >=3
//this group of variables can be null to represent a wild card
- var/major //The major version
var/minor //The minor version
var/patch //The patch version
+ var/deprecated_patch //The legacy version
var/raw_parameter //The unparsed parameter
var/deprefixed_parameter //The version only bit of raw_parameter
@@ -123,6 +133,10 @@
/datum/tgs_version/proc/Wildcard()
return
+//if the tgs_version equals some other_version
+/datum/tgs_version/proc/Equals(datum/tgs_version/other_version)
+ return
+
//represents a merge of a GitHub pull request
/datum/tgs_revision_information/test_merge
var/number //pull request number
@@ -179,14 +193,45 @@
return
//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
-//No function below this succeeds if it returns FALSE
+//No function below this succeeds if it returns FALSE or if TgsNew() has yet to be called
/world/proc/TgsAvailable()
return
+//Forces a hard reboot of BYOND by ending the process
+//unlike del(world) clients will try to reconnect
+//If the service has not requested a shutdown, the next server will take over
+/world/proc/TgsEndProcess()
+ return
+
+//Send a message to non-admin connected chats
+//message: The message to send
+//admin_only: If TRUE, message will instead be sent to only admin connected chats
+/world/proc/TgsTargetedChatBroadcast(message, admin_only)
+ return
+
+//Send a private message to a specific user
+//message: The message to send
+//user: The /datum/tgs_chat_user to send to
+/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
+ return
+
+//The following functions will sleep if a call to TgsNew() is sleeping
+
+//Sends a message to connected game chats
+//message: The message to send
+//channels: optional channels to limit the broadcast to
+/world/proc/TgsChatBroadcast(message, list/channels)
+ return
+
//Gets the current /datum/tgs_version of the server tools running the server
/world/proc/TgsVersion()
return
+//Gets the current /datum/tgs_version of the DMAPI being used
+/world/proc/TgsApiVersion()
+ return
+
+//Gets the name of the TGS instance running the game
/world/proc/TgsInstanceName()
return
@@ -202,34 +247,10 @@
/world/proc/TgsTestMerges()
return
-//Forces a hard reboot of BYOND by ending the process
-//unlike del(world) clients will try to reconnect
-//If the service has not requested a shutdown, the next server will take over
-/world/proc/TgsEndProcess()
- return
-
//Gets a list of connected tgs_chat_channel
/world/proc/TgsChatChannelInfo()
return
-//Sends a message to connected game chats
-//message: The message to send
-//channels: optional channels to limit the broadcast to
-/world/proc/TgsChatBroadcast(message, list/channels)
- return
-
-//Send a message to non-admin connected chats
-//message: The message to send
-//admin_only: If TRUE, message will instead be sent to only admin connected chats
-/world/proc/TgsTargetedChatBroadcast(message, admin_only)
- return
-
-//Send a private message to a specific user
-//message: The message to send
-//user: The /datum/tgs_chat_user to send to
-/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
- return
-
/*
The MIT License
@@ -255,4 +276,4 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
\ No newline at end of file
+*/
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 91a4a6f2c3..a63a59c75f 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -88,6 +88,7 @@
#define TRAIT_SLEEPIMMUNE "sleep_immunity"
#define TRAIT_PUSHIMMUNE "push_immunity"
#define TRAIT_SHOCKIMMUNE "shock_immunity"
+#define TRAIT_TESLA_SHOCKIMMUNE "tesla_shock_immunity"
#define TRAIT_STABLEHEART "stable_heart"
#define TRAIT_STABLELIVER "stable_liver"
#define TRAIT_RESISTHEAT "resist_heat"
diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm
index a364e0b93c..889e1bb1c0 100644
--- a/code/__DEFINES/vv.dm
+++ b/code/__DEFINES/vv.dm
@@ -122,3 +122,6 @@
// misc
#define VV_HK_SPACEVINE_PURGE "spacevine_purge"
+
+// paintings
+#define VV_HK_REMOVE_PAINTING "remove_painting"
diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm
index 86e8d1bc2b..5e57dd5328 100644
--- a/code/__HELPERS/_cit_helpers.dm
+++ b/code/__HELPERS/_cit_helpers.dm
@@ -1,9 +1,6 @@
//THIS FILE CONTAINS CONSTANTS, PROCS, AND OTHER THINGS//
/////////////////////////////////////////////////////////
-/mob/proc/setClickCooldown(var/timeout)
- next_move = max(world.time + timeout, next_move)
-
/proc/get_matrix_largest()
var/matrix/mtrx=new()
return mtrx.Scale(2)
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index e7b8560569..ba29205452 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -671,3 +671,13 @@
for(var/key in input)
ret += key
return ret
+
+/proc/is_type_in_ref_list(path, list/L)
+ if(!ispath(path))//not a path
+ return
+ for(var/i in L)
+ var/datum/D = i
+ if(!istype(D))//not an usable reference
+ continue
+ if(istype(D, path))
+ return TRUE
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 8ef924eea4..5e0ac99bae 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -4,7 +4,9 @@
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
-#define WRITE_LOG(log, text) rustg_log_write(log, text)
+//This is an external call, "true" and "false" are how rust parses out booleans
+#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
+#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
//print a warning message to world.log
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].")
@@ -152,6 +154,9 @@
/proc/log_subsystem(subsystem, text)
WRITE_LOG(GLOB.subsystem_log, "[subsystem]: [text]")
+/proc/log_click(object, location, control, params, client/C, event = "clicked")
+ WRITE_LOG(GLOB.click_log, "CLICK: [C.ckey] - [event] : [object] | [location] | [control] | [params]")
+
/* Log to both DD and the logfile. */
/proc/log_world(text)
#ifdef USE_CUSTOM_ERROR_HANDLER
@@ -181,7 +186,7 @@
/proc/start_log(log)
WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------")
-/* ui logging */
+/* ui logging */
/proc/log_tgui(text)
WRITE_LOG(GLOB.tgui_log, text)
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 6c0ffa5caa..75ac6a8b26 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -250,13 +250,13 @@
processing += A.contents
//viewers() but with a signal, for blacklisting.
-/proc/get_actual_viewers(depth = world.view, atom/center)
+/proc/fov_viewers(depth = world.view, atom/center)
if(!center)
return
. = viewers(depth, center)
for(var/k in .)
var/mob/M = k
- SEND_SIGNAL(M, COMSIG_MOB_IS_VIEWER, center, depth, .)
+ SEND_SIGNAL(M, COMSIG_MOB_FOV_VIEWER, center, depth, .)
/proc/get_mobs_in_radio_ranges(list/obj/item/radio/radios)
. = list()
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index bcfaa1bed2..0b5c60a95a 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -75,6 +75,8 @@
var/datum/emote/E = new path()
E.emote_list[E.key] = E
+ init_keybindings()
+
//Uplink Items
for(var/path in subtypesof(/datum/uplink_item))
var/datum/uplink_item/I = path
diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm
index dadd4322fb..cbe1817233 100644
--- a/code/__HELPERS/sanitize_values.dm
+++ b/code/__HELPERS/sanitize_values.dm
@@ -18,6 +18,12 @@
return text
return default
+/proc/sanitize_islist(value, default)
+ if(islist(value) && length(value))
+ return value
+ if(default)
+ return default
+
/proc/sanitize_inlist(value, list/List, default)
if(value in List)
return value
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 09047d32bf..2c8497d5ed 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -629,3 +629,45 @@
return null
r += ascii2text(c)
return r
+
+/proc/slot_to_string(slot)
+ switch(slot)
+ if(SLOT_BACK)
+ return "Backpack"
+ if(SLOT_WEAR_MASK)
+ return "Mask"
+ if(SLOT_HANDS)
+ return "Hands"
+ if(SLOT_BELT)
+ return "Belt"
+ if(SLOT_EARS)
+ return "Ears"
+ if(SLOT_GLASSES)
+ return "Glasses"
+ if(SLOT_GLOVES)
+ return "Gloves"
+ if(SLOT_NECK)
+ return "Neck"
+ if(SLOT_HEAD)
+ return "Head"
+ if(SLOT_SHOES)
+ return "Shoes"
+ if(SLOT_WEAR_SUIT)
+ return "Suit"
+ if(SLOT_W_UNIFORM)
+ return "Uniform"
+ if(SLOT_IN_BACKPACK)
+ return "In backpack"
+
+/proc/tg_ui_icon_to_cit_ui(ui_style)
+ switch(ui_style)
+ if('icons/mob/screen_plasmafire.dmi')
+ return 'modular_citadel/icons/ui/screen_plasmafire.dmi'
+ if('icons/mob/screen_slimecore.dmi')
+ return 'modular_citadel/icons/ui/screen_slimecore.dmi'
+ if('icons/mob/screen_operative.dmi')
+ return 'modular_citadel/icons/ui/screen_operative.dmi'
+ if('icons/mob/screen_clockwork.dmi')
+ return 'modular_citadel/icons/ui/screen_clockwork.dmi'
+ else
+ return 'modular_citadel/icons/ui/screen_midnight.dmi'
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 06dd746250..d6195b1dc6 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1600,8 +1600,13 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//empty string - use TgsTargetBroadcast with admin_only = FALSE
//other string - use TgsChatBroadcast with the tag that matches config_setting, only works with TGS4, if using TGS3 the above method is used
/proc/send2chat(message, config_setting)
- if(config_setting == null || !world.TgsAvailable())
+ if(config_setting == null)
return
+
+ UNTIL(GLOB.tgs_initialized)
+ if(!world.TgsAvailable())
+ return
+
var/datum/tgs_version/version = world.TgsVersion()
if(config_setting == "" || version.suite == 3)
world.TgsTargetedChatBroadcast(message, FALSE)
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 52eff15492..1aab96f85e 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -132,9 +132,11 @@ GLOBAL_LIST_INIT(bitfields, list(
"NO_RUINS_1" = NO_RUINS_1,
"PREVENT_CLICK_UNDER_1" = PREVENT_CLICK_UNDER_1,
"HOLOGRAM_1" = HOLOGRAM_1,
- "TESLA_IGNORE_1" = TESLA_IGNORE_1,
+ "SHOCKED_1" = SHOCKED_1,
"INITIALIZED_1" = INITIALIZED_1,
"ADMIN_SPAWNED_1" = ADMIN_SPAWNED_1,
+ "BLOCK_FACE_ATOM_1" = BLOCK_FACE_ATOM_1,
+ "PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1
),
"clothing_flags" = list(
"LAVAPROTECT" = LAVAPROTECT,
@@ -148,12 +150,12 @@ GLOBAL_LIST_INIT(bitfields, list(
"IGNORE_HAT_TOSS" = IGNORE_HAT_TOSS,
"SCAN_REAGENTS" = SCAN_REAGENTS
),
- "tesla_flags" = list(
- "TESLA_MOB_DAMAGE" = TESLA_MOB_DAMAGE,
- "TESLA_OBJ_DAMAGE" = TESLA_OBJ_DAMAGE,
- "TESLA_MOB_STUN" = TESLA_MOB_STUN,
- "TESLA_ALLOW_DUPLICATES" = TESLA_ALLOW_DUPLICATES,
- "TESLA_MACHINE_EXPLOSIVE" = TESLA_MACHINE_EXPLOSIVE,
+ "zap_flags" = list(
+ "ZAP_MOB_DAMAGE" = ZAP_MOB_DAMAGE,
+ "ZAP_OBJ_DAMAGE" = ZAP_OBJ_DAMAGE,
+ "ZAP_MOB_STUN" = ZAP_MOB_STUN,
+ "ZAP_ALLOW_DUPLICATES" = ZAP_ALLOW_DUPLICATES,
+ "ZAP_MACHINE_EXPLOSIVE" = ZAP_MACHINE_EXPLOSIVE,
),
"smooth" = list(
"SMOOTH_TRUE" = SMOOTH_TRUE,
diff --git a/code/_globalvars/lists/client.dm b/code/_globalvars/lists/client.dm
new file mode 100644
index 0000000000..5181d870c4
--- /dev/null
+++ b/code/_globalvars/lists/client.dm
@@ -0,0 +1,21 @@
+GLOBAL_LIST_EMPTY(classic_keybinding_list_by_key)
+GLOBAL_LIST_EMPTY(hotkey_keybinding_list_by_key)
+GLOBAL_LIST_EMPTY(keybindings_by_name)
+
+// This is a mapping from JS keys to Byond - ref: https://keycode.info/
+GLOBAL_LIST_INIT(_kbMap, list(
+ "UP" = "North",
+ "RIGHT" = "East",
+ "DOWN" = "South",
+ "LEFT" = "West",
+ "INSERT" = "Insert",
+ "HOME" = "Northwest",
+ "PAGEUP" = "Northeast",
+ "DEL" = "Delete",
+ "END" = "Southwest",
+ "PAGEDOWN" = "Southeast",
+ "SPACEBAR" = "Space",
+ "ALT" = "Alt",
+ "SHIFT" = "Shift",
+ "CONTROL" = "Ctrl"
+ ))
diff --git a/code/_globalvars/lists/keybindings.dm b/code/_globalvars/lists/keybindings.dm
new file mode 100644
index 0000000000..7e5b016a95
--- /dev/null
+++ b/code/_globalvars/lists/keybindings.dm
@@ -0,0 +1,31 @@
+/// Creates and sorts all the keybinding datums
+/proc/init_keybindings()
+ for(var/KB in subtypesof(/datum/keybinding))
+ var/datum/keybinding/keybinding = KB
+ if(!initial(keybinding.hotkey_keys))
+ continue
+ add_keybinding(new keybinding)
+ // init_emote_keybinds() - Disabled - I don't particularly want this.
+
+/// Adds an instanced keybinding to the global tracker
+/proc/add_keybinding(datum/keybinding/instance)
+ GLOB.keybindings_by_name[instance.name] = instance
+
+ // Classic
+ if(LAZYLEN(instance.classic_keys))
+ for(var/bound_key in instance.classic_keys)
+ LAZYADD(GLOB.classic_keybinding_list_by_key[bound_key], list(instance.name))
+
+ // Hotkey
+ if(LAZYLEN(instance.hotkey_keys))
+ for(var/bound_key in instance.hotkey_keys)
+ LAZYADD(GLOB.hotkey_keybinding_list_by_key[bound_key], list(instance.name))
+
+/proc/init_emote_keybinds()
+ for(var/i in subtypesof(/datum/emote))
+ var/datum/emote/faketype = i
+ if(!initial(faketype.key))
+ continue
+ var/datum/keybinding/emote/emote_kb = new
+ emote_kb.link_to_emote(faketype)
+ add_keybinding(emote_kb)
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index ba75fbfc9c..65fd772dfe 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -36,6 +36,8 @@ GLOBAL_VAR(reagent_log)
GLOBAL_PROTECT(reagent_log)
GLOBAL_VAR(world_crafting_log)
GLOBAL_PROTECT(world_crafting_log)
+GLOBAL_VAR(click_log)
+GLOBAL_PROTECT(click_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm
index dd8b9f0d94..1b100bebaf 100644
--- a/code/_globalvars/traits.dm
+++ b/code/_globalvars/traits.dm
@@ -29,6 +29,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE,
"TRAIT_PUSHIMMUNE" = TRAIT_PUSHIMMUNE,
"TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE,
+ "TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE,
"TRAIT_STABLEHEART" = TRAIT_STABLEHEART,
"TRAIT_STABLELIVER" = TRAIT_STABLELIVER,
"TRAIT_RESISTHEAT" = TRAIT_RESISTHEAT,
diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm
index d7557b00d3..7a8b0a1121 100644
--- a/code/_onclick/hud/plane_master.dm
+++ b/code/_onclick/hud/plane_master.dm
@@ -57,7 +57,7 @@
/obj/screen/plane_master/wall/backdrop(mob/mymob)
if(mymob?.client?.prefs.ambientocclusion)
- add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION)
+ add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(4, "#04080FAA"))
else
remove_filter("ambient_occlusion")
@@ -70,6 +70,12 @@
. = ..()
add_filter("vision_cone", 100, list(type="alpha", render_source=FIELD_OF_VISION_RENDER_TARGET, flags=MASK_INVERSE))
+/obj/screen/plane_master/above_wall/backdrop(mob/mymob)
+ if(mymob?.client?.prefs.ambientocclusion)
+ add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(3, "#04080F64"))
+ else
+ remove_filter("ambient_occlusion")
+
///Contains most things in the game world
/obj/screen/plane_master/game_world
name = "game world plane master"
@@ -83,7 +89,7 @@
/obj/screen/plane_master/game_world/backdrop(mob/mymob)
if(mymob?.client?.prefs.ambientocclusion)
- add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION)
+ add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(4, "#04080FAA"))
else
remove_filter("ambient_occlusion")
diff --git a/code/_onclick/hud/screen_objects/storage.dm b/code/_onclick/hud/screen_objects/storage.dm
index d7d711917d..7e8bfe12ab 100644
--- a/code/_onclick/hud/screen_objects/storage.dm
+++ b/code/_onclick/hud/screen_objects/storage.dm
@@ -65,6 +65,7 @@
return ..()
/obj/screen/storage/volumetric_box/Destroy()
+ makeItemInactive()
our_item = null
return ..()
@@ -87,10 +88,14 @@
makeItemInactive()
/obj/screen/storage/volumetric_box/proc/makeItemInactive()
+ if(!our_item)
+ return
our_item.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
our_item.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
/obj/screen/storage/volumetric_box/proc/makeItemActive()
+ if(!our_item)
+ return
our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others!
our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 9e120db102..3ad0219391 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -112,13 +112,13 @@
/obj/attacked_by(obj/item/I, mob/living/user)
var/totitemdamage = I.force
- var/bad_flag = NONE
+ var/bad_trait
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
totitemdamage *= 0.5
- bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
+ bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(I.used_skills && user.mind)
if(totitemdamage)
- totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag)
+ totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
for(var/skill in I.used_skills)
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
continue
@@ -154,16 +154,16 @@
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
. = I.force
- var/bad_flag = NONE
+ var/bad_trait
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
. *= 0.5
- bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
+ bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
. *= 0.5
if(!user.mind || !I.used_skills)
return
if(.)
- . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag)
+ . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait)
for(var/skill in I.used_skills)
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
continue
@@ -207,16 +207,16 @@
return 1
/// How much stamina this takes to swing this is not for realism purposes hecc off.
-/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = SKILL_STAMINA_COST)
+/obj/item/proc/getweight(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST)
. = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier
if(!user)
return
- var/bad_flag = NONE
+ var/bad_trait
if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
. *= STAM_COST_NO_COMBAT_MULT
- bad_flag |= SKILL_COMBAT_MODE
+ bad_trait = SKILL_COMBAT_MODE
if(used_skills && user.mind)
- . = user.mind.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE)
+ . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE)
/// How long this staggers for. 0 and negatives supported.
/obj/item/proc/melee_stagger_duration(force_override)
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index f8a66fce09..79b110a78a 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -508,6 +508,10 @@
//Allows players to set a hexadecimal color of their choice as skin tone, on top of the standard ones.
/datum/config_entry/flag/allow_custom_skintones
+///Initial loadout points
+/datum/config_entry/number/initial_gear_points
+ config_entry_value = 10
+
/**
* Enables the FoV component, which hides objects and mobs behind the parent from their sight, unless they turn around, duh.
* Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best.
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index 166f930e33..8a1c08bc35 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -451,3 +451,18 @@ SUBSYSTEM_DEF(garbage)
#endif
#endif
+
+#ifdef TESTING
+/proc/writeDatumCount()
+ var/list/datums = list()
+ for(var/datum/D in world)
+ datums[D.type] += 1
+ for(var/datum/D)
+ datums[D.type] += 1
+ datums = sortTim(datums, /proc/cmp_numeric_dsc, associative = TRUE)
+ if(fexists("data/DATUMCOUNT.txt"))
+ fdel("data/DATUMCOUNT.txt")
+ var/outfile = file("data/DATUMCOUNT.txt")
+ for(var/path in datums)
+ outfile << "[datums[path]]\t\t\t\t\t[path]"
+#endif
diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm
index 1f8a03b3e7..7c51ba4506 100644
--- a/code/controllers/subsystem/input.dm
+++ b/code/controllers/subsystem/input.dm
@@ -6,13 +6,20 @@ SUBSYSTEM_DEF(input)
priority = FIRE_PRIORITY_INPUT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
- var/list/macro_sets
- var/list/movement_keys
+ /// Classic mode input focused macro set. Manually set because we can't define ANY or ANY+UP for classic.
+ var/static/list/macroset_classic_input
+ /// Classic mode map focused macro set. Manually set because it needs to be clientside and go to macroset_classic_input.
+ var/static/list/macroset_classic_hotkey
+ /// New hotkey mode macro set. All input goes into map, game keeps incessently setting your focus to map, we can use ANY all we want here; we don't care about the input bar, the user has to force the input bar every time they want to type.
+ var/static/list/macroset_hotkey
+
+ /// Macro set for hotkeys
+ var/list/hotkey_mode_macros
+ /// Macro set for classic.
+ var/list/input_mode_macros
/datum/controller/subsystem/input/Initialize()
- setup_default_macro_sets()
-
- setup_default_movement_keys()
+ setup_macrosets()
initialized = TRUE
@@ -20,94 +27,69 @@ SUBSYSTEM_DEF(input)
return ..()
-// This is for when macro sets are eventualy datumized
-/datum/controller/subsystem/input/proc/setup_default_macro_sets()
- var/list/static/default_macro_sets
-
- if(default_macro_sets)
- macro_sets = default_macro_sets
- return
-
- default_macro_sets = list(
- "default" = list(
- "Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
- "O" = "ooc",
- "Ctrl+O" = "looc",
- "T" = "say",
- "Ctrl+T" = "say_indicator",
- "Y" = "whisper",
- "M" = "me",
- "Ctrl+M" = "me_indicator",
- "5" = "subtle",
- "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
- "Any" = "\"KeyDown \[\[*\]\]\"",
- "Any+UP" = "\"KeyUp \[\[*\]\]\"",
- ),
- "old_default" = list(
- "Tab" = "\".winset \\\"mainwindow.macro=old_hotkeys map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"",
- "Ctrl+T" = "say",
- "Ctrl+O" = "ooc",
- ),
- "old_hotkeys" = list(
- "Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
- "O" = "ooc",
- "L" = "looc",
- "T" = "say",
- "Ctrl+T" = "say_indicator",
- "M" = "me",
- "Ctrl+M" = "me_indicator",
- "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
- "Any" = "\"KeyDown \[\[*\]\]\"",
- "Any+UP" = "\"KeyUp \[\[*\]\]\"",
- ),
- )
-
- // Because i'm lazy and don't want to type all these out twice
- var/list/old_default = default_macro_sets["old_default"]
-
- var/list/static/oldmode_keys = list(
+/// Sets up the key list for classic mode for when badmins screw up vv's.
+/datum/controller/subsystem/input/proc/setup_macrosets()
+ // First, let's do the snowflake keyset!
+ macroset_classic_input = list()
+ var/list/classic_mode_keys = list(
"North", "East", "South", "West",
"Northeast", "Southeast", "Northwest", "Southwest",
- "Insert", "Delete", "Ctrl", "Alt",
+ "Insert", "Delete", "Ctrl", "Alt", "Shift",
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
)
+ for(var/key in classic_mode_keys)
+ macroset_classic_input[key] = "\"KeyDown [key]\""
+ macroset_classic_input["[key]+UP"] = "\"KeyUp [key]\""
+ // LET'S PLAY THE BIND EVERY KEY GAME!
+ // oh except for Backspace and Enter; if you want to use those you shouldn't have used oldmode!
+ var/list/classic_ctrl_override_keys = list(
+ "\[", "\]", "\\\\", ";", "'", ",", ".", "/", "-", "=", "`"
+ )
+ // i'm lazy let's play the list iteration game of numbers
+ for(var/i in 0 to 9)
+ classic_ctrl_override_keys += "[i]"
+ // let's play the ascii game of A to Z (UPPERCASE)
+ for(var/i in 65 to 90)
+ classic_ctrl_override_keys += ascii2text(i)
+ // let's play the game of clientside bind overrides!
+ classic_ctrl_override_keys -= list("T", "O", "M", "L")
+ macroset_classic_input["Ctrl+T"] = "say"
+ macroset_classic_input["Ctrl+O"] = "ooc"
+ macroset_classic_input["Ctrl+L"] = "looc"
+ // let's play the list iteration game x2
+ for(var/key in classic_ctrl_override_keys)
+ // make sure to double double quote to ensure things are treated as a key combo instead of addition/semicolon logic.
+ macroset_classic_input["\"Ctrl+[key]\""] = "\"KeyDown [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\""
+ macroset_classic_input["\"Ctrl+[key]+UP\""] = "\"KeyUp [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\""
+ // Misc
+ macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\""
+ macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\""
- for(var/i in 1 to oldmode_keys.len)
- var/key = oldmode_keys[i]
- old_default[key] = "\"KeyDown [key]\""
- old_default["[key]+UP"] = "\"KeyUp [key]\""
+ // FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET.
+ macroset_classic_hotkey = list(
+ "Any" = "\"KeyDown \[\[*\]\]\"",
+ "Any+UP" = "\"KeyUp \[\[*\]\]\"",
+ "Tab" = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT] input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
+ "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
+ "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
+ "O" = "ooc",
+ "T" = "say",
+ "L" = "looc",
+ "M" = "me"
+ )
- var/list/static/oldmode_ctrl_override_keys = list(
- "W" = "W", "A" = "A", "S" = "S", "D" = "D", // movement
- "1" = "1", "2" = "2", "3" = "3", "4" = "4", // intent
- "B" = "B", // resist
- "E" = "E", // quick equip
- "F" = "F", // intent left
- "G" = "G", // intent right
- "H" = "H", // stop pulling
- "Q" = "Q", // drop
- "R" = "R", // throw
- "X" = "X", // switch hands
- "Y" = "Y", // activate item
- "Z" = "Z", // activate item
- )
-
- for(var/i in 1 to oldmode_ctrl_override_keys.len)
- var/key = oldmode_ctrl_override_keys[i]
- var/override = oldmode_ctrl_override_keys[key]
- old_default["Ctrl+[key]"] = "\"KeyDown [override]\""
- old_default["Ctrl+[key]+UP"] = "\"KeyUp [override]\""
-
- macro_sets = default_macro_sets
-
-// For initially setting up or resetting to default the movement keys
-/datum/controller/subsystem/input/proc/setup_default_movement_keys()
- var/static/list/default_movement_keys = list(
- "W" = NORTH, "A" = WEST, "S" = SOUTH, "D" = EAST, // WASD
- "North" = NORTH, "West" = WEST, "South" = SOUTH, "East" = EAST, // Arrow keys & Numpad
- )
-
- movement_keys = default_movement_keys.Copy()
+ // And finally, the modern set.
+ macroset_hotkey = list(
+ "Any" = "\"KeyDown \[\[*\]\]\"",
+ "Any+UP" = "\"KeyUp \[\[*\]\]\"",
+ "Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
+ "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
+ "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
+ "O" = "ooc",
+ "T" = "say",
+ "L" = "looc",
+ "M" = "me"
+ )
// Badmins just wanna have fun ♪
/datum/controller/subsystem/input/proc/refresh_client_macro_sets()
@@ -115,9 +97,10 @@ SUBSYSTEM_DEF(input)
for(var/i in 1 to clients.len)
var/client/user = clients[i]
user.set_macros()
+ user.update_movement_keys()
/datum/controller/subsystem/input/fire()
var/list/clients = GLOB.clients // Let's sing the list cache song
- for(var/i in 1 to length(clients))
+ for(var/i in 1 to clients.len)
var/client/C = clients[i]
C.keyLoop()
diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm
index 0a60c6e5d3..cd577e4ac6 100644
--- a/code/controllers/subsystem/persistence.dm
+++ b/code/controllers/subsystem/persistence.dm
@@ -24,6 +24,8 @@ SUBSYSTEM_DEF(persistence)
var/list/saved_votes = list()
var/list/obj/structure/sign/picture_frame/photo_frames
var/list/obj/item/storage/photo_album/photo_albums
+ var/list/obj/structure/sign/painting/painting_frames = list()
+ var/list/paintings = list()
/datum/controller/subsystem/persistence/Initialize()
LoadSatchels()
@@ -265,6 +267,7 @@ SUBSYSTEM_DEF(persistence)
CollectAntagReputation()
SaveRandomizedRecipes()
SavePanicBunker()
+ SavePaintings()
/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
var/bunker_path = file("data/bunker_passthrough.json")
@@ -528,3 +531,19 @@ SUBSYSTEM_DEF(persistence)
file_data["data"] = saved_votes[ckey]
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/persistence/proc/LoadPaintings()
+ var/json_file = file("data/paintings.json")
+ if(fexists(json_file))
+ paintings = json_decode(file2text(json_file))
+
+ for(var/obj/structure/sign/painting/P in painting_frames)
+ P.load_persistent()
+
+/datum/controller/subsystem/persistence/proc/SavePaintings()
+ for(var/obj/structure/sign/painting/P in painting_frames)
+ P.save_persistent()
+
+ var/json_file = file("data/paintings.json")
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(paintings))
diff --git a/code/datums/actions/ninja.dm b/code/datums/actions/ninja.dm
index b655078349..c0314b9c48 100644
--- a/code/datums/actions/ninja.dm
+++ b/code/datums/actions/ninja.dm
@@ -8,11 +8,11 @@
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjaboost
- check_flags = NONE
name = "Adrenaline Boost"
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
button_icon_state = "repulse"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ required_mobility_flags = NONE
/datum/action/item_action/ninjapulse
name = "EM Burst (25E)"
diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm
index 7ff25eb12f..279118d877 100644
--- a/code/datums/brain_damage/phobia.dm
+++ b/code/datums/brain_damage/phobia.dm
@@ -44,7 +44,7 @@
return
if(world.time > next_check && world.time > next_scare)
next_check = world.time + 50
- var/list/seen_atoms = owner.visible_atoms(7)
+ var/list/seen_atoms = owner.fov_view(7)
if(LAZYLEN(trigger_objs))
for(var/obj/O in seen_atoms)
diff --git a/code/datums/components/art.dm b/code/datums/components/art.dm
new file mode 100644
index 0000000000..f6d3cb6c61
--- /dev/null
+++ b/code/datums/components/art.dm
@@ -0,0 +1,56 @@
+
+#define BAD_ART 12.5
+#define GOOD_ART 25
+#define GREAT_ART 50
+
+/datum/component/art
+ var/impressiveness = 0
+
+/datum/component/art/Initialize(impress)
+ impressiveness = impress
+ if(isobj(parent))
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_obj_examine)
+ else
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_other_examine)
+ if(isstructure(parent))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
+ if(isitem(parent))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/apply_moodlet)
+
+/datum/component/art/proc/apply_moodlet(mob/M, impress)
+ M.visible_message("[M] stops and looks intently at [parent].", \
+ "You stop to take in [parent].")
+ switch(impress)
+ if (0 to BAD_ART)
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
+ if (BAD_ART to GOOD_ART)
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok)
+ if (GOOD_ART to GREAT_ART)
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood)
+ if(GREAT_ART to INFINITY)
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
+
+
+/datum/component/art/proc/on_other_examine(datum/source, mob/M)
+ apply_moodlet(M, impressiveness)
+
+/datum/component/art/proc/on_obj_examine(datum/source, mob/M)
+ var/obj/O = parent
+ apply_moodlet(M, impressiveness *(O.obj_integrity/O.max_integrity))
+
+/datum/component/art/proc/on_attack_hand(datum/source, mob/M)
+ to_chat(M, "You start examining [parent]...")
+ if(!do_after(M, 20, target = parent))
+ return
+ on_obj_examine(source, M)
+
+/datum/component/art/rev
+
+/datum/component/art/rev/apply_moodlet(mob/M, impress)
+ M.visible_message("[M] stops to inspect [parent].", \
+ "You take in [parent], inspecting the fine craftsmanship of the proletariat.")
+
+ if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev))
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
+ else
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
diff --git a/code/datums/components/crafting/glassware/glassware.dm b/code/datums/components/crafting/glassware/glassware.dm
index 2b57837c5d..6e1a3d47a0 100644
--- a/code/datums/components/crafting/glassware/glassware.dm
+++ b/code/datums/components/crafting/glassware/glassware.dm
@@ -74,7 +74,7 @@
//////////////////////Lens//////////////////////////
//Six Steps //
-//Sells for 1800 cr, takes 15 glass shets //
+//Sells for 1600 cr, takes 15 glass shets //
//Usefull for selling and later crafting //
////////////////////////////////////////////////////
@@ -146,14 +146,14 @@
/obj/item/glasswork/glass_base/glass_lens_part5
name = "Unpolished glass lens"
- desc = "A small unpolished glass lens. Could be polished with some silk."
+ desc = "A small unpolished glass lens. Could be polished with some cloth."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "glass_optics"
next_step = /obj/item/glasswork/glass_base/glass_lens_part6
/obj/item/glasswork/glass_base/glass_lens_part5/attackby(obj/item/I, mob/user, params)
..()
- if(istype(I, /obj/item/stack/sheet/silk))
+ if(istype(I, /obj/item/stack/sheet/cloth))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
@@ -324,7 +324,7 @@
//////////////////////Tea Plates////////////////////
//Three Steps //
-//Sells for 1200 cr, takes 5 glass shets //
+//Sells for 1000 cr, takes 5 glass shets //
//Usefull for selling and chemical things //
////////////////////////////////////////////////////
@@ -370,20 +370,20 @@
/obj/item/glasswork/glass_base/tea_plate3
name = "Disk of glass"
- desc = "A disk of glass that can be cant be used for much. Needs to be polished with some silk."
+ desc = "A disk of glass that can be cant be used for much. Needs to be polished with some cloth."
icon_state = "glass_base_half"
next_step = /obj/item/tea_plate
/obj/item/glasswork/glass_base/tea_plate3/attackby(obj/item/I, mob/user, params)
..()
- if(istype(I, /obj/item/stack/sheet/silk))
+ if(istype(I, /obj/item/stack/sheet/cloth))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
//////////////////////Tea Cup///////////////////////
//Four Steps //
-//Sells for 1800 cr, takes 6 glass shets //
+//Sells for 1600 cr, takes 6 glass shets //
//Usefull for selling and chemical things //
////////////////////////////////////////////////////
@@ -429,13 +429,13 @@
/obj/item/glasswork/glass_base/tea_cup3
name = "Disk of glass"
- desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some silk."
+ desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some cloth."
icon_state = "glass_base_half"
next_step = /obj/item/glasswork/glass_base/tea_cup4
/obj/item/glasswork/glass_base/cup3/attackby(obj/item/I, mob/user, params)
..()
- if(istype(I, /obj/item/stack/sheet/silk))
+ if(istype(I, /obj/item/stack/sheet/cloth))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
diff --git a/code/datums/components/crafting/guncrafting.dm b/code/datums/components/crafting/guncrafting.dm
index 89868c2332..e06583ab61 100644
--- a/code/datums/components/crafting/guncrafting.dm
+++ b/code/datums/components/crafting/guncrafting.dm
@@ -1,21 +1,20 @@
//Gun crafting parts til they can be moved elsewhere
// PARTS //
+/obj/item/weaponcrafting
+ icon = 'icons/obj/improvised.dmi'
/obj/item/weaponcrafting/receiver
name = "modular receiver"
desc = "A prototype modular receiver and trigger assembly for a firearm."
- icon = 'icons/obj/improvised.dmi'
icon_state = "receiver"
/obj/item/weaponcrafting/stock
name = "rifle stock"
desc = "A classic rifle stock that doubles as a grip, roughly carved out of wood."
- icon = 'icons/obj/improvised.dmi'
icon_state = "riflestock"
-/obj/item/weaponcrafting/silkstring
- name = "silkstring"
- desc = "A long piece of silk with some resemblance to cable coil."
- icon = 'icons/obj/improvised.dmi'
- icon_state = "silkstring"
+/obj/item/weaponcrafting/durathread_string
+ name = "durathread string"
+ desc = "A long piece of durathread with some resemblance to cable coil."
+ icon_state = "durastring"
diff --git a/code/datums/components/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm
index 02dd3f2c05..7a7379c834 100644
--- a/code/datums/components/crafting/recipes/recipes_clothing.dm
+++ b/code/datums/components/crafting/recipes/recipes_clothing.dm
@@ -39,14 +39,14 @@
time = 10
reqs = list(/obj/item/paper = 20)
category = CAT_CLOTHING
-
+
/datum/crafting_recipe/armwraps
name = "Armwraps"
result = /obj/item/clothing/gloves/fingerless/pugilist
time = 60
tools = list(TOOL_WIRECUTTER)
reqs = list(/obj/item/stack/sheet/cloth = 4,
- /obj/item/stack/sheet/silk = 2,
+ /obj/item/stack/sheet/durathread = 2,
/obj/item/stack/sheet/leather = 2)
category = CAT_CLOTHING
diff --git a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm
index 318587f5cb..206895178a 100644
--- a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm
+++ b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm
@@ -192,7 +192,7 @@
result = /obj/item/gun/ballistic/bow/pipe
reqs = list(/obj/item/pipe = 5,
/obj/item/stack/sheet/plastic = 15,
- /obj/item/weaponcrafting/silkstring = 5)
+ /obj/item/weaponcrafting/durathread_string = 5)
time = 450
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
@@ -281,7 +281,7 @@
result = /obj/item/ammo_casing/caseless/arrow/wood
time = 30
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
- /obj/item/stack/sheet/silk = 1,
+ /obj/item/stack/sheet/durathread = 1,
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
category = CAT_WEAPONRY
subcategory = CAT_AMMO
diff --git a/code/datums/components/field_of_vision.dm b/code/datums/components/field_of_vision.dm
index b819604168..5fb7b2596c 100644
--- a/code/datums/components/field_of_vision.dm
+++ b/code/datums/components/field_of_vision.dm
@@ -86,10 +86,10 @@
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_mob_logout)
RegisterSignal(M, COMSIG_MOB_GET_VISIBLE_MESSAGE, .proc/on_visible_message)
RegisterSignal(M, COMSIG_MOB_EXAMINATE, .proc/on_examinate)
- RegisterSignal(M, COMSIG_MOB_VISIBLE_ATOMS, .proc/on_visible_atoms)
+ RegisterSignal(M, COMSIG_MOB_FOV_VIEW, .proc/on_fov_view)
RegisterSignal(M, COMSIG_MOB_CLIENT_CHANGE_VIEW, .proc/on_change_view)
RegisterSignal(M, COMSIG_MOB_RESET_PERSPECTIVE, .proc/on_reset_perspective)
- RegisterSignal(M, COMSIG_MOB_IS_VIEWER, .proc/is_viewer)
+ RegisterSignal(M, COMSIG_MOB_FOV_VIEWER, .proc/is_viewer)
/datum/component/field_of_vision/UnregisterFromParent()
. = ..()
@@ -109,8 +109,8 @@
UNREGISTER_NESTED_LOCS(nested_locs, COMSIG_MOVABLE_MOVED, 1)
UnregisterSignal(M, list(COMSIG_MOB_CLIENT_LOGIN, COMSIG_MOB_CLIENT_LOGOUT,
COMSIG_MOB_GET_VISIBLE_MESSAGE, COMSIG_MOB_EXAMINATE,
- COMSIG_MOB_VISIBLE_ATOMS, COMSIG_MOB_RESET_PERSPECTIVE,
- COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_IS_VIEWER))
+ COMSIG_MOB_FOV_VIEW, COMSIG_MOB_RESET_PERSPECTIVE,
+ COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_FOV_VIEWER))
/**
* Generates the holder and images (if not generated yet) and adds them to client.images.
@@ -296,7 +296,7 @@
if(fov.alpha)
FOV_ANGLE_CHECK(source, target, return, return COMPONENT_NO_VISIBLE_MESSAGE)
-/datum/component/field_of_vision/proc/on_visible_atoms(mob/source, list/atoms)
+/datum/component/field_of_vision/proc/on_fov_view(mob/source, list/atoms)
if(!fov.alpha)
return
for(var/k in atoms)
diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm
index fbf559fe35..f767c607a5 100644
--- a/code/datums/components/footstep.dm
+++ b/code/datums/components/footstep.dm
@@ -1,26 +1,52 @@
+///Footstep component. Plays footsteps at parents location when it is appropriate.
/datum/component/footstep
+ ///How many steps the parent has taken since the last time a footstep was played
var/steps = 0
+ ///volume determines the extra volume of the footstep. This is multiplied by the base volume, should there be one.
var/volume
+ ///e_range stands for extra range - aka how far the sound can be heard. This is added to the base value and ignored if there isn't a base value.
var/e_range
+ ///footstep_type is a define which determines what kind of sounds should get chosen.
+ var/footstep_type
+ ///This can be a list OR a soundfile OR null. Determines whatever sound gets played.
+ var/footstep_sounds
-/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
+/datum/component/footstep/Initialize(footstep_type_ = FOOTSTEP_MOB_BAREFOOT, volume_ = 0.5, e_range_ = -1)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
volume = volume_
e_range = e_range_
- RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
+ footstep_type = footstep_type_
+ switch(footstep_type)
+ if(FOOTSTEP_MOB_HUMAN)
+ if(!ishuman(parent))
+ return COMPONENT_INCOMPATIBLE
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_humanstep)
+ return
+ if(FOOTSTEP_MOB_CLAW)
+ footstep_sounds = GLOB.clawfootstep
+ if(FOOTSTEP_MOB_BAREFOOT)
+ footstep_sounds = GLOB.barefootstep
+ if(FOOTSTEP_MOB_HEAVY)
+ footstep_sounds = GLOB.heavyfootstep
+ if(FOOTSTEP_MOB_SHOE)
+ footstep_sounds = GLOB.footstep
+ if(FOOTSTEP_MOB_SLIME)
+ footstep_sounds = 'sound/effects/footstep/slime1.ogg'
+ if(FOOTSTEP_MOB_CRAWL)
+ footstep_sounds = 'sound/effects/footstep/crawl1.ogg'
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_simplestep) //Note that this doesn't get called for humans.
-/datum/component/footstep/proc/play_footstep()
+///Prepares a footstep. Determines if it should get played. Returns the turf it should get played on. Note that it is always a /turf/open
+/datum/component/footstep/proc/prepare_step()
var/turf/open/T = get_turf(parent)
if(!istype(T))
return
var/mob/living/LM = parent
- var/v = volume
- var/e = e_range
if(!T.footstep || LM.buckled || !CHECK_MOBILITY(LM, MOBILITY_STAND) || LM.buckled || LM.throwing || (LM.movement_type & (VENTCRAWLING | FLYING)))
if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
- playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
+ playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume)
return
if(HAS_TRAIT(LM, TRAIT_SILENT_STEP))
@@ -30,79 +56,83 @@
var/mob/living/carbon/C = LM
if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
return
- if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
- v /= 2
- e -= 5
+ if(C.m_intent == MOVE_INTENT_WALK)
+ return
steps++
- if(steps >= 3)
+ if(steps >= 6)
steps = 0
- else
+ if(steps % 2)
return
- if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around
+ if(steps != 0 && !LM.has_gravity(T)) // don't need to step as often when you hop around
return
+ return T
- //begin playsound shenanigans//
-
- //for barefooted non-clawed mobs like monkeys
- if(isbarefoot(LM))
- playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
- GLOB.barefootstep[T.barefootstep][2] * v,
- TRUE,
- GLOB.barefootstep[T.barefootstep][3] + e)
+/datum/component/footstep/proc/play_simplestep()
+ var/turf/open/T = prepare_step()
+ if(!T)
return
-
- //for xenomorphs, dogs, and other clawed mobs
- if(isclawfoot(LM))
- if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
- v /= 3
- e -= 5
-
- playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
- GLOB.clawfootstep[T.clawfootstep][2] * v,
- TRUE,
- GLOB.clawfootstep[T.clawfootstep][3] + e)
+ if(isfile(footstep_sounds) || istext(footstep_sounds))
+ playsound(T, footstep_sounds, volume)
return
-
- //for megafauna and other large and imtimidating mobs such as the bloodminer
- if(isheavyfoot(LM))
- playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
- GLOB.heavyfootstep[T.heavyfootstep][2] * v,
- TRUE,
- GLOB.heavyfootstep[T.heavyfootstep][3] + e)
+ var/turf_footstep
+ switch(footstep_type)
+ if(FOOTSTEP_MOB_CLAW)
+ turf_footstep = T.clawfootstep
+ if(FOOTSTEP_MOB_BAREFOOT)
+ turf_footstep = T.barefootstep
+ if(FOOTSTEP_MOB_HEAVY)
+ turf_footstep = T.heavyfootstep
+ if(FOOTSTEP_MOB_SHOE)
+ turf_footstep = T.footstep
+ if(!turf_footstep)
return
+ playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range)
- //for slimes
- if(isslime(LM))
- playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
+/datum/component/footstep/proc/play_humanstep()
+ var/turf/open/T = prepare_step()
+ if(!T)
return
-
- //for (simple) humanoid mobs (clowns, russians, pirates, etc.)
- if(isshoefoot(LM))
- if(!ishuman(LM))
- playsound(T, pick(GLOB.footstep[T.footstep][1]),
- GLOB.footstep[T.footstep][2] * v,
- TRUE,
- GLOB.footstep[T.footstep][3] + e)
- return
- if(ishuman(LM)) //for proper humans, they're special
- var/mob/living/carbon/human/H = LM
- var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
-
- if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
- playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
+ var/mob/living/carbon/human/H = parent
+ var/list/L = GLOB.barefootstep
+ var/turf_footstep = T.barefootstep
+ var/special = FALSE
+ if(H.physiology.footstep_type)
+ switch(H.physiology.footstep_type)
+ if(FOOTSTEP_MOB_CLAW)
+ turf_footstep = T.clawfootstep
+ L = GLOB.clawfootstep
+ if(FOOTSTEP_MOB_BAREFOOT)
+ turf_footstep = T.barefootstep
+ L = GLOB.barefootstep
+ if(FOOTSTEP_MOB_HEAVY)
+ turf_footstep = T.heavyfootstep
+ L = GLOB.heavyfootstep
+ if(FOOTSTEP_MOB_SHOE)
+ turf_footstep = T.footstep
+ L = GLOB.footstep
+ if(FOOTSTEP_MOB_SLIME)
+ playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume)
return
+ if(FOOTSTEP_MOB_CRAWL)
+ playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume)
+ return
+ special = TRUE
+ else
+ var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
+ if(feetCover) //are we wearing shoes
+ playsound(T, pick(GLOB.footstep[T.footstep][1]),
+ GLOB.footstep[T.footstep][2] * volume,
+ TRUE,
+ GLOB.footstep[T.footstep][3] + e_range)
+ return
- if(feetCover) //are we wearing shoes
- playsound(T, pick(GLOB.footstep[T.footstep][1]),
- GLOB.footstep[T.footstep][2] * v,
- TRUE,
- GLOB.footstep[T.footstep][3] + e)
-
- if(!feetCover) //are we NOT wearing shoes
- playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
- GLOB.barefootstep[T.barefootstep][2] * v,
- TRUE,
- GLOB.barefootstep[T.barefootstep][3] + e)
\ No newline at end of file
+ if(!special && H.dna.species.special_step_sounds)
+ playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE)
+ else
+ playsound(T, pick(L[turf_footstep][1]),
+ L[turf_footstep][2] * volume,
+ TRUE,
+ L[turf_footstep][3] + e_range)
diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm
index 2f411ff37f..5860bd029b 100644
--- a/code/datums/components/material_container.dm
+++ b/code/datums/components/material_container.dm
@@ -73,7 +73,7 @@
if(!material_amount)
to_chat(user, "[I] does not contain sufficient materials to be accepted by [parent].")
return
- if(!has_space(material_amount))
+ if((!precise_insertion || !GLOB.typecache_stack[I]) && !has_space(material_amount))
to_chat(user, "[parent] has not enough space. Please remove materials from [parent] in order to insert more.")
return
user_insert(I, user)
diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm
index 6a32a46aef..f5da669c3a 100644
--- a/code/datums/components/rotation.dm
+++ b/code/datums/components/rotation.dm
@@ -23,18 +23,12 @@
if(can_user_rotate)
src.can_user_rotate = can_user_rotate
- else
- src.can_user_rotate = CALLBACK(src,.proc/default_can_user_rotate)
if(can_be_rotated)
src.can_be_rotated = can_be_rotated
- else
- src.can_be_rotated = CALLBACK(src,.proc/default_can_be_rotated)
if(after_rotation)
src.after_rotation = after_rotation
- else
- src.after_rotation = CALLBACK(src,.proc/default_after_rotation)
//Try Clockwise,counter,flip in order
if(src.rotation_flags & ROTATION_FLIP)
@@ -103,14 +97,34 @@
examine_list += "Alt-click to rotate it clockwise."
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
- if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation))
- return
+ if(can_be_rotated)
+ if(!can_be_rotated.Invoke(user, default_rotation_direction))
+ return
+ else
+ if(!default_can_be_rotated(user, default_rotation_direction))
+ return
+ if(can_user_rotate)
+ if(!can_user_rotate.Invoke(user, default_rotation_direction))
+ return
+ else
+ if(!default_can_user_rotate(user, default_rotation_direction))
+ return
BaseRot(user, rotation)
return TRUE
/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user)
- if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction))
- return
+ if(can_be_rotated)
+ if(!can_be_rotated.Invoke(user, default_rotation_direction))
+ return
+ else
+ if(!default_can_be_rotated(user, default_rotation_direction))
+ return
+ if(can_user_rotate)
+ if(!can_user_rotate.Invoke(user, default_rotation_direction))
+ return
+ else
+ if(!default_can_user_rotate(user, default_rotation_direction))
+ return
if(istype(I,/obj/item/wrench))
BaseRot(user,default_rotation_direction)
return COMPONENT_NO_AFTERATTACK
@@ -126,7 +140,10 @@
if(ROTATION_FLIP)
rot_degree = 180
AM.setDir(turn(AM.dir,rot_degree))
- after_rotation.Invoke(user,rotation_type)
+ if(after_rotation)
+ after_rotation.Invoke(user, rotation_type)
+ else
+ default_after_rotation(user, rotation_type)
/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type)
if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY))
diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm
index e044a59668..55c3e1d083 100644
--- a/code/datums/components/storage/concrete/_concrete.dm
+++ b/code/datums/components/storage/concrete/_concrete.dm
@@ -136,9 +136,7 @@
var/mob/M = parent.loc
I.dropped(M)
if(new_location)
- //Reset the items values
- _removal_reset(AM)
- AM.forceMove(new_location)
+ AM.forceMove(new_location) // exited comsig will handle removal reset.
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index 68ba0e4272..f93d40bb04 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -351,7 +351,6 @@
return master._removal_reset(thing)
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
- _removal_reset(thing)
if(LAZYACCESS(ui_item_blocks, thing))
var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing]
for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion.
@@ -359,6 +358,7 @@
M.client?.screen -= C.on_screen_objects()
ui_item_blocks -= thing
qdel(C)
+ _removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK!
refresh_mob_views()
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
@@ -572,7 +572,7 @@
if(rustle_sound)
playsound(parent, "rustle", 50, 1, -5)
to_chat(user, "You put [I] [insert_preposition]to [parent].")
- for(var/mob/viewing in get_actual_viewers(world.view, user)-M)
+ for(var/mob/viewing in fov_viewers(world.view, user)-M)
if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
viewing.show_message("[M] puts [I] [insert_preposition]to [parent].", MSG_VISUAL)
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm
index a7a61802d3..216d82b4c8 100644
--- a/code/datums/diseases/_MobProcs.dm
+++ b/code/datums/diseases/_MobProcs.dm
@@ -145,4 +145,10 @@
return !is_mouth_covered()
/mob/living/carbon/CanSpreadAirborneDisease()
- return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25)))
\ No newline at end of file
+ return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25)))
+
+/mob/living/proc/set_shocked()
+ flags_1 |= SHOCKED_1
+
+/mob/living/proc/reset_shocked()
+ flags_1 &= ~ SHOCKED_1
\ No newline at end of file
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 26786da776..747db3d6ce 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -47,8 +47,8 @@
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.dna.skin_tone_override = skin_tone_override
- destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
+ destination.set_species(species.type, icon_update=0)
destination.dna.real_name = real_name
destination.dna.nameless = nameless
destination.dna.custom_species = custom_species
@@ -246,6 +246,17 @@
construct_block(GLOB.mam_body_markings_list.Find(features["mam_body_markings"]), GLOB.mam_body_markings_list.len)
if(DNA_TAUR_BLOCK)
construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len)
+ if(species.mutant_bodyparts["taur"] && ishuman(holder))
+ var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
+ switch(T?.taur_mode)
+ if(STYLE_HOOF_TAURIC)
+ H.physiology.footstep_type = FOOTSTEP_MOB_SHOE
+ if(STYLE_PAW_TAURIC)
+ H.physiology.footstep_type = FOOTSTEP_MOB_CLAW
+ if(STYLE_SNEK_TAURIC)
+ H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL
+ else
+ H.physiology.footstep_type = null
//Please use add_mutation or activate_mutation instead
/datum/dna/proc/force_give(datum/mutation/human/HM)
diff --git a/code/datums/elements/dwarfism.dm b/code/datums/elements/dwarfism.dm
new file mode 100644
index 0000000000..fefbe4fbe7
--- /dev/null
+++ b/code/datums/elements/dwarfism.dm
@@ -0,0 +1,42 @@
+#define SHORT 4/5
+#define TALL 5/4
+
+///Very similar to squish, but for dwarves and shorties
+/datum/element/dwarfism
+ element_flags = ELEMENT_DETACH|ELEMENT_BESPOKE
+ id_arg_index = 2
+ var/comsig
+ var/list/attached_targets = list()
+
+/datum/element/dwarfism/Attach(datum/target, comsig, comsig_target)
+ . = ..()
+ if(!isliving(target))
+ return ELEMENT_INCOMPATIBLE
+
+ src.comsig = comsig
+
+ var/mob/living/L = target
+ if(L.lying != 0)
+ L.transform = L.transform.Scale(SHORT, 1)
+ else
+ L.transform = L.transform.Scale(1, SHORT)
+ attached_targets[target] = comsig_target
+ RegisterSignal(target, comsig, .proc/check_loss) //Second arg of the signal will be checked against the comsig_target.
+
+/datum/element/dwarfism/proc/check_loss(mob/living/L, comsig_target)
+ if(attached_targets[L] == comsig_target)
+ Detach(L)
+
+/datum/element/dwarfism/Detach(mob/living/L)
+ . = ..()
+ if(QDELETED(L))
+ return
+ if(L.lying != 0)
+ L.transform = L.transform.Scale(TALL, 1)
+ else
+ L.transform = L.transform.Scale(1, TALL)
+ UnregisterSignal(L, comsig)
+ attached_targets -= L
+
+#undef SHORT
+#undef TALL
diff --git a/code/datums/elements/wuv.dm b/code/datums/elements/wuv.dm
index fffb90c681..6476a204cf 100644
--- a/code/datums/elements/wuv.dm
+++ b/code/datums/elements/wuv.dm
@@ -41,7 +41,7 @@
return
//we want to delay the effect to be displayed after the mob is petted, not before.
switch(user.a_intent)
- if(INTENT_HARM, INTENT_DISARM)
+ if(INTENT_HARM)
addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1)
if(INTENT_HELP)
addtimer(CALLBACK(src, .proc/pet_the_dog, source, user), 1)
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 0b0fed407c..91b8e32566 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -5,16 +5,18 @@
var/list/testmerge = list()
/datum/getrev/New()
+ commit = rustg_git_revparse("HEAD")
+ if(commit)
+ date = rustg_git_commit_date(commit)
+ originmastercommit = rustg_git_revparse("origin/master")
+
+/datum/getrev/proc/load_tgs_info()
testmerge = world.TgsTestMerges()
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
- else
- commit = rustg_git_revparse("HEAD")
- if(commit)
- date = rustg_git_commit_date(commit)
- originmastercommit = rustg_git_revparse("origin/master")
+ date = rustg_git_commit_date(commit)
// goes to DD log and config_error.txt
log_world(get_log_message())
@@ -77,7 +79,9 @@
msg += "No commit information"
if(world.TgsAvailable())
var/datum/tgs_version/version = world.TgsVersion()
- msg += "Server tools version: [version.raw_parameter]"
+ msg += "TGS version: [version.raw_parameter]"
+ var/datum/tgs_version/api_version = world.TgsApiVersion()
+ msg += "DMAPI version: [api_version.raw_parameter]"
// Game mode odds
msg += "
Current Informational Settings:"
@@ -121,4 +125,4 @@
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
msg += "[ctag] [percentage]%"
- to_chat(src, msg.Join("
"))
\ No newline at end of file
+ to_chat(src, msg.Join("
"))
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index 1464927c3a..c56425b074 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -248,7 +248,7 @@
description = "Something I recently ate was horrifyingly disgusting.\n"
mood_change = -5
timeout = 5 MINUTES
-
+
/datum/mood_event/nanite_sadness
description = "+++++++HAPPINESS SUPPRESSION+++++++\n"
mood_change = -7
@@ -256,3 +256,7 @@
/datum/mood_event/nanite_sadness/add_effects(message)
description = "+++++++[message]+++++++\n"
+/datum/mood_event/artbad
+ description = "I've produced better art than that from my ass.\n"
+ mood_change = -2
+ timeout = 1200
diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm
index 1e9a53cf57..95177f6869 100644
--- a/code/datums/mood_events/generic_positive_events.dm
+++ b/code/datums/mood_events/generic_positive_events.dm
@@ -182,3 +182,17 @@
description = "What a peculiar emblem. It makes me feel hopeful for my future.\n"
mood_change = 5
+/datum/mood_event/artok
+ description = "It's nice to see people are making art around here.\n"
+ mood_change = 2
+ timeout = 2 MINUTES
+
+/datum/mood_event/artgood
+ description = "What a thought-provoking piece of art. I'll remember that for a while.\n"
+ mood_change = 3
+ timeout = 3 MINUTES
+
+/datum/mood_event/artgreat
+ description = "That work of art was so great it made me believe in the goodness of humanity. Says a lot in a place like this.\n"
+ mood_change = 4
+ timeout = 4 MINUTES
diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm
index 9edaa7605c..db739c5100 100644
--- a/code/datums/mutations/_mutations.dm
+++ b/code/datums/mutations/_mutations.dm
@@ -116,7 +116,8 @@
owner.apply_overlay(layer_used)
if(power)
owner.RemoveSpell(power)
- qdel(src)
+ qdel(power)
+ SEND_SIGNAL(owner, COMSIG_HUMAN_MUTATION_LOSS, src)
return 0
return 1
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index 9f8c74e2db..866ea85dbf 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -82,7 +82,7 @@
if(..())
return
ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
- owner.transform = owner.transform.Scale(1, 0.8)
+ owner.AddElement(/datum/element/dwarfism, COMSIG_HUMAN_MUTATION_LOSS, src)
passtable_on(owner, GENETIC_MUTATION)
owner.visible_message("[owner] suddenly shrinks!", "Everything around you seems to grow..")
@@ -90,7 +90,6 @@
if(..())
return
REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
- owner.transform = owner.transform.Scale(1, 1.25)
passtable_off(owner, GENETIC_MUTATION)
owner.visible_message("[owner] suddenly grows!", "Everything around you seems to shrink..")
diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm
index 41ef52e317..571a8274d8 100644
--- a/code/datums/skills/_skill.dm
+++ b/code/datums/skills/_skill.dm
@@ -20,18 +20,20 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/desc
/// Color of the name as shown in the html readout
var/name_color = "#F0F0F0" // White on dark surface.
- /// Our progression type
+ /// Our progression type. These are mostly used to skip typechecks overhead, don't go around messing with these.
var/progression_type
/// Abstract type
var/abstract_type = /datum/skill
/// List of max levels. Only used in level skills, but present here for helper macros.
var/max_levels = INFINITY
- /// skill threshold used in generic skill competency calculations.
- var/list/competency_thresholds = list(0, 0, 0)
- /// Multiplier of the difference of the holder skill value and the selected threshold.
- var/list/competency_mults = list(0, 0, 0)
- /// In which way this skil can affect or be affected through actions and skill modifiers.
- var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD
+ /// skill threshold used in generic skill competency operations.
+ var/list/competency_thresholds
+ /// Base multiplier used in skill competency operations.
+ var/base_multiplier = 1
+ /// Value added to the base multiplier depending on overall competency compared to maximum value/level.
+ var/competency_multiplier = 1
+ /// A list of ways this skill can affect or be affected through actions and skill modifiers.
+ var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
/**
* Ensures what someone's setting as a value for this skill is valid.
@@ -66,8 +68,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/binary
abstract_type = /datum/skill/binary
progression_type = SKILL_PROGRESSION_BINARY
- competency_thresholds = list(FALSE, TRUE, TRUE)
- competency_mults = list(0.5, 0.5, 0.5)
+ competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
/datum/skill/binary/sanitize_value(new_value)
return new_value? TRUE : FALSE
@@ -78,6 +79,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/numerical
abstract_type = /datum/skill/numerical
progression_type = SKILL_PROGRESSION_NUMERICAL
+ competency_thresholds = list(THRESHOLD_COMPETENT = 25, THRESHOLD_EXPERT = 50, THRESHOLD_MASTER = 75)
/// Max value of this skill
var/max_value = 100
/// Min value of this skill
@@ -180,8 +182,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/level/job
abstract_type = /datum/skill/level/job
levels = list("Basic", "Trained", "Experienced", "Master")
- competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
- competency_mults = list(0.15, 0.1, 0.1)
+ competency_thresholds = list(THRESHOLD_COMPETENT = JOB_SKILL_TRAINED, THRESHOLD_EXPERT = JOB_SKILL_EXPERT, THRESHOLD_MASTER = JOB_SKILL_MASTER)
associative = TRUE
//quite the reference, no?
@@ -195,7 +196,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
"Proficient", "Talented", "Adept", "Expert",
"Professional", "Accomplished", "Great", "Master",
"High Master", "Grand Master", "Legendary")
- competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER)
- competency_mults = list(0.15, 0.1, 0.08)
+ competency_thresholds = list(THRESHOLD_COMPETENT = DORF_SKILL_COMPETENT, THRESHOLD_EXPERT = DORF_SKILL_EXPERT, THRESHOLD_MASTER = DORF_SKILL_MASTER)
associative = TRUE
unskilled_tier = "Dabbling"
diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm
index 500b49a1ff..071db3306a 100644
--- a/code/datums/skills/_skill_holder.dm
+++ b/code/datums/skills/_skill_holder.dm
@@ -122,16 +122,22 @@
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/mind/proc/action_skill_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
- var/mod
var/datum/skill/S = GLOB.skill_datums[skill]
if(!S)
- return
+ return value
+ var/mod = S.base_multiplier
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
- mod = get_skill_level(S.type)
+ var/datum/skill/level/L = S
+ var/skill_lvl = get_skill_level(L.type)
+ mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[threshold]-skill_lvl, 0))*L.competency_multiplier
+ if(SKILL_PROGRESSION_NUMERICAL)
+ var/datum/skill/numerical/N = S
+ var/skill_val = get_skill_value(N.type)
+ mod += skill_val/(N.max_value+max(N.competency_thresholds[threshold]-skill_val, 0))*N.competency_multiplier
else
- mod = get_skill_value(S.type)
- mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
+ var/comp_threshold = S.competency_thresholds[threshold]
+ mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
. = modifier_is_multiplier ? value*mod : value/mod
/**
@@ -139,29 +145,42 @@
* Args:
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
* * value : the value to modify, may be a delay, damage, probability.
- * * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
+ * * traits : the required traits each skill (either in I.used_skills or the skill datum skill_traits) must have to influence
* * the value.
- * * bad_flags : the opposite of the above, skills that must not be present to impact the value.
+ * * bad_traits : the opposite of the above.
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
-/datum/mind/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
+/datum/mind/proc/item_action_skills_mod(obj/item/I, value, traits, bad_traits, modifier_is_multiplier = TRUE)
. = value
var/sum = 0
var/divisor = 0
+ var/one_trait = istext(traits)
+ var/one_bad_trait = istext(bad_traits)
for(var/k in I.used_skills)
var/datum/skill/S = GLOB.skill_datums[k]
if(!S)
continue
- var/our_flags = (I.used_skills[k]|S.skill_flags)
- if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
+ var/our_traits = S.skill_traits
+ our_traits |= I.used_skills[k]
+ if(traits && !(one_trait ? (traits in our_traits) : length(our_traits & traits)))
continue
- var/mod
+ if(bad_traits && (one_bad_trait ? (bad_traits in our_traits) : length(our_traits & bad_traits)))
+ continue
+ var/mod = S.base_multiplier
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
- mod = get_skill_level(S.type)
+ var/datum/skill/level/L = S
+ var/skill_lvl = get_skill_level(L.type)
+ mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[I.skill_difficulty]-skill_lvl, 0))*L.competency_multiplier
+ if(SKILL_PROGRESSION_NUMERICAL)
+ var/datum/skill/numerical/N = S
+ var/skill_val = get_skill_value(N.type)
+ mod += skill_val/(N.max_value+max(N.competency_thresholds[I.skill_difficulty]-skill_val, 0))*N.competency_multiplier
else
- mod = get_skill_value(S.type)
- sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
+ var/comp_threshold = S.competency_thresholds[I.skill_difficulty]
+ mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
+ sum += mod
+ divisor++
if(divisor)
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
diff --git a/code/datums/skills/_skill_modifier.dm b/code/datums/skills/_skill_modifier.dm
index b0115194a7..a28cf3aebd 100644
--- a/code/datums/skills/_skill_modifier.dm
+++ b/code/datums/skills/_skill_modifier.dm
@@ -9,11 +9,13 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
/datum/skill_modifier
/// flags for this skill modifier.
var/modifier_flags = NONE
- /// target skills, can be a specific skill typepath or a set of skill flags.
- var/target_skills = NONE
+ /// target skills, can be a specific skill typepath or a list of skill traits.
+ var/target_skills = /datum/skill
+ /// the GLOB.potential_skills_per_mod key generated on runtime. You shouldn't be var-editing it.
+ var/target_skills_key
/// The identifier key this skill modifier is associated with.
var/identifier
- /// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags flags.
+ /// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags.
var/affinity_mod = 1
/// skill value modifier, see above.
var/value_mod = 1
@@ -38,21 +40,25 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
CRASH("Skill modifier identifier \"[identifier]\" already taken.")
GLOB.skill_modifiers[identifier] = src
if(ispath(target_skills))
+ target_skills_key = target_skills
var/list/mod_L = GLOB.potential_mods_per_skill[target_skills]
if(!mod_L)
mod_L = GLOB.potential_mods_per_skill[target_skills] = list()
else
BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE)
mod_L[identifier] = src
- GLOB.potential_skills_per_mod["[target_skills]"] = list(target_skills)
- else //Should be a bitfield.
- var/list/L = GLOB.potential_skills_per_mod["[target_skills]"]
+ GLOB.potential_skills_per_mod[target_skills_key] = list(target_skills)
+ else //Should be a list.
+ var/list/T = target_skills
+ T = sortTim(target_skills, /proc/cmp_text_asc) //Sort the list contents alphabetically.
+ target_skills_key = T.Join("-")
+ var/list/L = GLOB.potential_skills_per_mod[target_skills_key]
if(!L)
L = list()
for(var/path in GLOB.skill_datums)
- if(GLOB.skill_datums[path].skill_flags & target_skills)
+ if(GLOB.skill_datums[path].skill_traits & target_skills)
L += path
- GLOB.potential_skills_per_mod["[target_skills]"] = L
+ GLOB.potential_skills_per_mod[target_skills_key] = L
for(var/path in L)
var/list/mod_L = GLOB.potential_mods_per_skill[path]
if(!mod_L)
@@ -62,7 +68,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
mod_L[identifier] = src
/datum/skill_modifier/Destroy()
- for(var/path in GLOB.potential_skills_per_mod["[target_skills]"])
+ for(var/path in GLOB.potential_skills_per_mod[target_skills_key])
var/mod_L = GLOB.potential_mods_per_skill[path]
mod_L -= identifier
if(!length(mod_L))
@@ -96,7 +102,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
LAZYINITLIST(skill_holder.skill_affinity_mods)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
LAZYINITLIST(skill_holder.skill_level_mods)
- for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
+ for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
if(M.modifier_flags & MODIFIER_SKILL_VALUE)
ADD_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values, get_skill_value(path, FALSE))
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY)
@@ -127,7 +133,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(!skill_holder.skill_value_mods && !skill_holder.skill_affinity_mods && !skill_holder.skill_level_mods)
return
- for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
+ for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
if(M.modifier_flags & MODIFIER_SKILL_VALUE && skill_holder.skill_value_mods)
REMOVE_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values)
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY && skill_holder.skill_affinity_mods)
@@ -155,6 +161,18 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(MODIFIER_TARGET_AFFINITY)
mod = affinity_mod
+ if(modifier_flags & MODIFIER_USE_THRESHOLDS && istext(mod))
+ var/datum/skill/S = GLOB.skill_datums[skillpath]
+ if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
+ var/datum/skill/level/L = S
+ switch(L.level_up_method)
+ if(STANDARD_LEVEL_UP)
+ mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
+ if(DWARFY_LEVEL_UP)
+ mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
+ else
+ mod = S.competency_thresholds[mod]
+
var/diff = 0
if(modifier_flags & (MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_HANDICAP))
if(modifier_flags & MODIFIER_SKILL_VIRTUE)
diff --git a/code/datums/skills/engineering.dm b/code/datums/skills/engineering.dm
index 59c9436e46..db7b33450c 100644
--- a/code/datums/skills/engineering.dm
+++ b/code/datums/skills/engineering.dm
@@ -2,5 +2,4 @@
name = "Wiring"
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
name_color = COLOR_PALE_ORANGE
- competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
- skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL
+ skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
diff --git a/code/datums/skills/medical.dm b/code/datums/skills/medical.dm
index aaae1236a6..404c141157 100644
--- a/code/datums/skills/medical.dm
+++ b/code/datums/skills/medical.dm
@@ -2,4 +2,4 @@
name = "Surgery"
desc = "How proficient you are at doing surgery."
name_color = COLOR_PALE_BLUE_GRAY
- competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100.
+ competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
diff --git a/code/datums/skills/modifiers/mood.dm b/code/datums/skills/modifiers/mood.dm
index 2ab74bdbbb..30f24afcc4 100644
--- a/code/datums/skills/modifiers/mood.dm
+++ b/code/datums/skills/modifiers/mood.dm
@@ -1,8 +1,8 @@
/datum/skill_modifier/bad_mood
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
- target_skills = SKILL_USE_MOOD
+ target_skills = list(SKILL_SANITY)
/datum/skill_modifier/great_mood
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
- target_skills = SKILL_TRAIN_MOOD
+ target_skills = list(SKILL_SANITY)
affinity_mod = 1.2
diff --git a/code/datums/skills/modifiers/organs.dm b/code/datums/skills/modifiers/organs.dm
new file mode 100644
index 0000000000..13ebaf0658
--- /dev/null
+++ b/code/datums/skills/modifiers/organs.dm
@@ -0,0 +1,13 @@
+/datum/skill_modifier/brain_damage
+ target_skills = list(SKILL_INTELLIGENCE)
+ modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
+ value_mod = 0.85
+ level_mod = 0.85
+ affinity_mod = 0.85
+
+/datum/skill_modifier/heavy_brain_damage
+ target_skills = list(SKILL_INTELLIGENCE)
+ modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
+ priority = MODIFIER_SKILL_PRIORITY_LOW
+ value_mod = THRESHOLD_COMPETENT
+ level_mod = THRESHOLD_COMPETENT
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index ce6e2782e4..130988867d 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -120,11 +120,13 @@
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
. = ..()
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
+ ADD_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize")
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
/datum/status_effect/mesmerize/on_remove()
. = ..()
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
+ REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize")
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
diff --git a/code/datums/tgs_event_handler.dm b/code/datums/tgs_event_handler.dm
new file mode 100644
index 0000000000..a3324121bf
--- /dev/null
+++ b/code/datums/tgs_event_handler.dm
@@ -0,0 +1,20 @@
+/datum/tgs_event_handler/impl/HandleEvent(event_code, ...)
+ switch(event_code)
+ if(TGS_EVENT_REBOOT_MODE_CHANGE)
+ var/list/reboot_mode_lookup = list ("[TGS_REBOOT_MODE_NORMAL]" = "be normal", "[TGS_REBOOT_MODE_SHUTDOWN]" = "shutdown the server", "[TGS_REBOOT_MODE_RESTART]" = "hard restart the server")
+ var old_reboot_mode = args[2]
+ var new_reboot_mode = args[3]
+ message_admins("TGS: Reboot will no longer [reboot_mode_lookup["[old_reboot_mode]"]], it will instead [reboot_mode_lookup["[new_reboot_mode]"]]")
+ if(TGS_EVENT_PORT_SWAP)
+ message_admins("TGS: Changing port from [world.port] to [args[2]]")
+ if(TGS_EVENT_INSTANCE_RENAMED)
+ message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]")
+ if(TGS_EVENT_COMPILE_START)
+ message_admins("TGS: Deployment started, new game version incoming...")
+ if(TGS_EVENT_COMPILE_CANCELLED)
+ message_admins("TGS: Deployment cancelled!")
+ if(TGS_EVENT_COMPILE_FAILURE)
+ message_admins("TGS: Deployment failed!")
+ if(TGS_EVENT_DEPLOYMENT_COMPLETE)
+ message_admins("TGS: Deployment complete!")
+ to_chat(world, "Server updated, changes will be applied on the next round...")
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index a63f63f4a4..1ff27bafa9 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -581,6 +581,14 @@
SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode)
return FALSE
+/**
+ * Respond to a electric bolt action on our item
+ *
+ * Default behaviour is to return, we define here to allow for cleaner code later on
+ */
+/atom/proc/zap_act(power, zap_flags, shocked_targets)
+ return
+
/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user)
if(GetComponent(/datum/component/storage))
return component_storage_contents_dump_act(src_object, user)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 206864d44c..9736f473e8 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -37,6 +37,8 @@
var/throwforce = 0
var/datum/component/orbiter/orbiting
var/can_be_z_moved = TRUE
+ ///If we were without gravity and another animation happened, the bouncing will stop, and we need to restart it in next life().
+ var/floating_need_update = FALSE
var/zfalling = FALSE
@@ -492,15 +494,16 @@
/atom/movable/proc/float(on)
if(throwing)
return
- if(on && !(movement_type & FLOATING))
+ if(on && (!(movement_type & FLOATING) || floating_need_update))
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
sleep(10)
animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
- setMovetype(movement_type | FLOATING)
- else if (!on && (movement_type & FLOATING))
+ if(!(movement_type & FLOATING))
+ setMovetype(movement_type | FLOATING)
+ else if (!on && movement_type & FLOATING)
animate(src, pixel_y = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING)
-
+ floating_need_update = FALSE
/* Language procs
* Unless you are doing something very specific, these are the ones you want to use.
diff --git a/code/game/gamemodes/gangs/dominator.dm b/code/game/gamemodes/gangs/dominator.dm
index dca50be5b9..af75315ded 100644
--- a/code/game/gamemodes/gangs/dominator.dm
+++ b/code/game/gamemodes/gangs/dominator.dm
@@ -48,9 +48,6 @@
/obj/machinery/dominator/hulk_damage()
return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED
-/obj/machinery/dominator/tesla_act()
- qdel(src)
-
/obj/machinery/dominator/update_icon()
cut_overlays()
if(stat & BROKEN)
diff --git a/code/game/gamemodes/gangs/gang_decals.dm b/code/game/gamemodes/gangs/gang_decals.dm
index 7aaed769d9..a37b4cb63b 100644
--- a/code/game/gamemodes/gangs/gang_decals.dm
+++ b/code/game/gamemodes/gangs/gang_decals.dm
@@ -10,7 +10,7 @@
/obj/effect/decal/cleanable/crayon/gang
icon = 'icons/effects/crayondecal.dmi'
layer = ABOVE_NORMAL_TURF_LAYER //Harder to hide
- plane = GAME_PLANE
+ plane = ABOVE_WALL_PLANE
do_icon_rotate = FALSE //These are designed to always face south, so no rotation please.
var/datum/team/gang/gang
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 470c26ed0f..e2f26d6617 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -522,11 +522,11 @@ Class Procs:
/obj/machinery/proc/can_be_overridden()
. = 1
-/obj/machinery/tesla_act(power, tesla_flags, shocked_objects)
- ..()
- if(prob(85) && (tesla_flags & TESLA_MACHINE_EXPLOSIVE))
+/obj/machinery/zap_act(power, zap_flags, shocked_objects)
+ . = ..()
+ if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE))
explosion(src, 1, 2, 4, flame_range = 2, adminlog = FALSE, smoke = FALSE)
- if(tesla_flags & TESLA_OBJ_DAMAGE)
+ else if(zap_flags & ZAP_OBJ_DAMAGE)
take_damage(power/2000, BURN, "energy")
if(prob(40))
emp_act(EMP_LIGHT)
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 5bfef9f925..7b92fb58d8 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -290,8 +290,6 @@
operating = TRUE
do_animate("closing")
layer = closingLayer
- if(!safe)
- crush()
sleep(5)
density = TRUE
sleep(5)
@@ -303,6 +301,8 @@
update_freelook_sight()
if(safe)
CheckForMobs()
+ else
+ crush()
return 1
/obj/machinery/door/proc/CheckForMobs()
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 3a79ff3c82..621e486e90 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
desc = "It's a floor-mounted device for projecting holographic images."
icon_state = "holopad0"
layer = LOW_OBJ_LAYER
- plane = FLOOR_PLANE
+ plane = ABOVE_WALL_PLANE
flags_1 = HEAR_1
use_power = IDLE_POWER_USE
idle_power_usage = 5
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index f9f4eb3e80..1730569e10 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -115,8 +115,8 @@
return PROCESS_KILL
/obj/machinery/space_heater/RefreshParts()
- var/laser = 0
- var/cap = 0
+ var/laser = 2
+ var/cap = 1
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
laser += M.rating
for(var/obj/item/stock_parts/capacitor/M in component_parts)
@@ -166,6 +166,11 @@
else
return ..()
+/obj/machinery/space_heater/wrench_act(mob/living/user, obj/item/I)
+ ..()
+ default_unfasten_wrench(user, I, 5)
+ return TRUE
+
/obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm
index f618888d98..dcd86c9f24 100644
--- a/code/game/machinery/wishgranter.dm
+++ b/code/game/machinery/wishgranter.dm
@@ -11,9 +11,6 @@
var/insisting = 0
/obj/machinery/wish_granter/attack_hand(mob/living/carbon/user)
- . = ..()
- if(.)
- return
if(charges <= 0)
to_chat(user, "The Wish Granter lies silent.")
return
@@ -22,22 +19,116 @@
to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.")
return
- else if(is_special_character(user))
- to_chat(user, "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away.")
-
else if (!insisting)
to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?")
insisting++
else
- to_chat(user, "You speak. [pick("I want the station to disappear","Humanity is corrupt, mankind must be destroyed","I want to be rich", "I want to rule the world","I want immortality.")]. The Wish Granter answers.")
- to_chat(user, "Your head pounds for a moment, before your vision clears. You are the avatar of the Wish Granter, and your power is LIMITLESS! And it's all yours. You need to make sure no one can take it from you. No one can know, first.")
+ if(is_special_character(user))
+ to_chat(user, "You speak. [pick("I want power","Humanity is corrupt, mankind must be destroyed", "I want to rule the world","I want immortality")]. The Wish Granter answers.")
+ to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!")
+ user.dna.add_mutation(HULK)
+ user.dna.add_mutation(XRAY)
+ user.dna.add_mutation(SPACEMUT)
+ user.dna.add_mutation(TK)
+ user.next_move_modifier *= 0.5 //half the delay between attacks!
+ to_chat(user, "Things around you feel slower!")
+ charges--
+ insisting = FALSE
+ to_chat(user, "You have a very great feeling about this!")
+ else
+ to_chat(user, "The Wish Granter awaits your wish.")
+ var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","The Station To Disappear","To Kill","Nothing")
+ switch(wish)
+ if("Power") //Gives infinite power in exchange for infinite power going off in your face!
+ if(charges <= 0)
+ return
+ to_chat(user, "Your wish is granted, but at a terrible cost...")
+ to_chat(user, "The Wish Granter punishes you for your selfishness, warping itself into a delaminating supermatter shard!")
+ var/obj/item/stock_parts/cell/infinite/powah = new /obj/item/stock_parts/cell/infinite(get_turf(user))
+ if(user.put_in_hands(powah))
+ to_chat(user, "[powah] materializes into your hands!")
+ else
+ to_chat(user, "[powah] materializes onto the floor.")
+ var/obj/machinery/power/supermatter_crystal/powerwish = new /obj/machinery/power/supermatter_crystal(loc)
+ powerwish.damage = 700 //right at the emergency threshold
+ powerwish.produces_gas = FALSE
+ charges--
+ insisting = FALSE
+ if(!charges)
+ qdel(src)
+ if("Wealth") //Gives 1 million space bucks in exchange for being turned into gold!
+ if(charges <= 0)
+ return
+ to_chat(user, "Your wish is granted, but at a cost...")
+ to_chat(user, "The Wish Granter punishes you for your selfishness, warping your body to match the greed in your heart.")
+ new /obj/structure/closet/crate/trashcart/moneywish(loc)
+ new /obj/structure/closet/crate/trashcart/moneywish(loc)
+ user.set_species(/datum/species/golem/gold)
+ charges--
+ insisting = FALSE
+ if(!charges)
+ qdel(src)
+ if("The Station To Disappear") //teleports you to the station and makes you blind, making the station disappear for you!
+ if(charges <= 0)
+ return
+ to_chat(user, "Your wish is 'granted', but at a terrible cost...")
+ to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your eyes to match the darkness in your heart.")
+ user.dna.add_mutation(BLINDMUT)
+ var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES)
+ if(eyes)
+ eyes.applyOrganDamage(eyes.maxHealth)
+ var/list/destinations = list()
+ for(var/obj/item/beacon/B in GLOB.teleportbeacons)
+ var/turf/T = get_turf(B)
+ if(is_station_level(T.z))
+ destinations += B
+ var/chosen_beacon = pick(destinations)
+ var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon))
+ try_move_adjacent(J)
+ playsound(src,'sound/effects/sparks4.ogg',50,1)
+ charges--
+ insisting = FALSE
+ if(!charges)
+ qdel(src)
+ if("To Kill") //Makes you kill things in exchange for rewards!
+ if(charges <= 0)
+ return
+ to_chat(user, "Your wish is granted, but at a terrible cost...")
+ to_chat(user, "The Wish Granter punishes you for your wickedness, warping itself into a dastardly creature for you to kill! ...but it almost seems to reward you for this.")
+ var/obj/item/melee/transforming/energy/sword/cx/killreward = new /obj/item/melee/transforming/energy/sword/cx(get_turf(user))
+ if(user.put_in_hands(killreward))
+ to_chat(user, "[killreward] materializes into your hands!")
+ else
+ to_chat(user, "[killreward] materializes onto the floor.")
+ user.next_move_modifier *= 0.8 //20% less delay between attacks!
+ to_chat(user, "Things around you feel slightly slower!")
+ var/mob/living/simple_animal/hostile/venus_human_trap/killwish = new /mob/living/simple_animal/hostile/venus_human_trap(loc)
+ killwish.maxHealth = 1500
+ killwish.health = killwish.maxHealth
+ killwish.vine_grab_distance = 6
+ killwish.melee_damage_upper = 30
+ killwish.loot = list(/obj/item/dualsaber/hypereutactic)
+ charges--
+ insisting = FALSE
+ if(!charges)
+ qdel(src)
+ if("Nothing") //Makes the wish granter disappear
+ if(charges <= 0)
+ return
+ to_chat(user, "The Wish Granter vanishes from sight!")
+ to_chat(user, "You feel as if you just narrowly avoided a terrible fate...")
+ charges--
+ insisting = FALSE
+ qdel(src)
- charges--
- insisting = 0
+//ITEMS THAT IT USES
- user.mind.add_antag_datum(/datum/antagonist/wishgranter)
+/obj/structure/closet/crate/trashcart/moneywish
+ desc = "A heavy, metal trashcart with wheels. Filled with cash."
+ name = "loaded trash cart"
- to_chat(user, "You have a very bad feeling about this.")
-
- return
+/obj/structure/closet/crate/trashcart/moneywish/PopulateContents() //25*20*1000=500,000
+ for(var/i in 1 to 25)
+ var/obj/item/stack/spacecash/c1000/lodsamoney = new /obj/item/stack/spacecash/c1000(src)
+ lodsamoney.amount = lodsamoney.max_amount
diff --git a/code/game/mecha/combat/neovgre.dm b/code/game/mecha/combat/neovgre.dm
index c678912a21..fdcc4df151 100644
--- a/code/game/mecha/combat/neovgre.dm
+++ b/code/game/mecha/combat/neovgre.dm
@@ -62,18 +62,21 @@
/obj/mecha/combat/neovgre/process()
..()
- if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hople to stop the superweapon
+ if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hope to stop the superweapon
cell.charge = INFINITY
max_integrity = INFINITY
obj_integrity = max_integrity
CHECK_TICK //Just to be on the safe side lag wise
- else if(cell.charge < cell.maxcharge)
- for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
- var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
- if (get_clockwork_power() <= delta)
- cell.charge += delta
- adjust_clockwork_power(-delta)
- CHECK_TICK
+ else
+ if(cell.charge < cell.maxcharge)
+ for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
+ var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
+ if (get_clockwork_power() >= delta)
+ cell.charge += delta
+ adjust_clockwork_power(-delta)
+ if(obj_integrity < max_integrity && istype(loc, /turf/open/floor/clockwork))
+ obj_integrity += min(max_integrity - obj_integrity, max_integrity / 200)
+ CHECK_TICK
/obj/mecha/combat/neovgre/Initialize()
.=..()
@@ -90,7 +93,7 @@
energy_drain = 30
name = "Aribter Laser Cannon"
desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere"
- fire_sound = "sound/weapons/neovgre_laser.ogg"
+ fire_sound = 'sound/weapons/neovgre_laser.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M)
if(istype(M))
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index 53768fe9a9..1fe7f74dec 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -77,7 +77,7 @@
/obj/mecha/attack_animal(mob/living/simple_animal/user)
mecha_log_message("Attack by simple animal. Attacker - [user].", color="red")
if(!user.melee_damage_upper && !user.obj_damage)
- user.emote("custom", message = "[user.friendly] [src].")
+ user.emote("custom", message = "[user.friendly_verb_continuous] [src].")
return 0
else
var/play_soundeffect = 1
diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm
index 955b9935dd..8cfdad0432 100644
--- a/code/game/objects/effects/decals/crayon.dm
+++ b/code/game/objects/effects/decals/crayon.dm
@@ -3,7 +3,7 @@
desc = "Graffiti. Damn kids."
icon = 'icons/effects/crayondecal.dmi'
icon_state = "rune1"
- plane = GAME_PLANE //makes the graffiti visible over a wall.
+ plane = ABOVE_WALL_PLANE //makes the graffiti visible over a wall.
gender = NEUTER
mergeable_decal = FALSE
var/do_icon_rotate = TRUE
diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm
index 3e7706282a..5dbd18aa0c 100644
--- a/code/game/objects/effects/decals/decal.dm
+++ b/code/game/objects/effects/decals/decal.dm
@@ -35,6 +35,7 @@
icon = 'icons/turf/decals.dmi'
icon_state = "warningline"
layer = TURF_DECAL_LAYER
+ plane = ABOVE_WALL_PLANE
/obj/effect/turf_decal/Initialize()
..()
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 992e9c84a7..6910bb1db0 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -469,6 +469,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
/obj/effect/landmark/stationroom
var/list/templates = list()
layer = BULLET_HOLE_LAYER
+ plane = ABOVE_WALL_PLANE
/obj/effect/landmark/stationroom/New()
..()
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index a8422dedc0..2a4b6d7df5 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -135,7 +135,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
///Skills vars
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
var/list/datum/skill/used_skills
- var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general.
+ var/skill_difficulty = THRESHOLD_UNTRAINED //how difficult it's to use this item in general.
var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item.
/obj/item/Initialize()
@@ -805,7 +805,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay)
if(user.mind && used_skills)
- delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE)
+ delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, null, FALSE)
// Create a callback with checks that would be called every tick by do_after.
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks)
@@ -831,11 +831,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay >= MIN_TOOL_SOUND_DELAY)
play_tool_sound(target, volume)
+
if(user.mind && used_skills && skill_gain_mult)
+ var/gain = skill_gain + delay/SKILL_GAIN_DELAY_DIVISOR
for(var/skill in used_skills)
- if(!(used_skills[skill] & SKILL_TRAINING_TOOL))
+ if(!(SKILL_TRAINING_TOOL in used_skills[skill]))
continue
- user.mind.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
+ user.mind.auto_gain_experience(skill, gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
return TRUE
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index 0676c439f0..cb44b82ad2 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -143,7 +143,7 @@ RLD
//if user can't be seen from A (only checks surroundings' opaqueness) and can't see A.
//jarring, but it should stop people from targetting atoms they can't see...
//excluding darkness, to allow RLD to be used to light pitch black dark areas.
- if(!((user in view(view_range, A)) || (user in get_actual_viewers(view_range, A))))
+ if(!((user in view(view_range, A)) || (user in fov_viewers(view_range, A))))
to_chat(user, "You focus, pointing \the [src] at whatever outside your field of vision in that direction... to no avail.")
return FALSE
return TRUE
diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm
index 1f6dff490d..3640db2d8a 100644
--- a/code/game/objects/items/apc_frame.dm
+++ b/code/game/objects/items/apc_frame.dm
@@ -58,18 +58,22 @@
/obj/item/wallframe/proc/after_attach(var/obj/O)
transfer_fingerprints_to(O)
-/obj/item/wallframe/attackby(obj/item/W, mob/user, params)
- ..()
- if(istype(W, /obj/item/screwdriver))
- // For camera-building borgs
- var/turf/T = get_step(get_turf(user), user.dir)
- if(iswallturf(T))
- T.attackby(src, user, params)
+/obj/item/wallframe/screwdriver_act(mob/user, obj/item/I)
+ . = ..()
+ if(.)
+ return
+ // For camera-building borgs
+ var/turf/T = get_step(get_turf(user), user.dir)
+ if(iswallturf(T))
+ T.attackby(src, user)
+/obj/item/wallframe/wrench_act(mob/user, obj/item/I)
+ if(!custom_materials)
+ return
var/metal_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT)
var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT)
- if(istype(W, /obj/item/wrench) && (metal_amt || glass_amt))
+ if(metal_amt || glass_amt)
to_chat(user, "You dismantle [src].")
if(metal_amt)
new /obj/item/stack/sheet/metal(get_turf(src), metal_amt)
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index f60edf2917..a4ed8dedd1 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -91,6 +91,11 @@
refill()
+/obj/item/toy/crayon/examine(mob/user)
+ . = ..()
+ if(can_change_colour)
+ . += "Ctrl-click [src] while it's on your person to quickly recolour it."
+
/obj/item/toy/crayon/proc/refill()
if(charges == -1)
charges_left = 100
@@ -160,6 +165,12 @@
update_icon()
return TRUE
+/obj/item/toy/crayon/CtrlClick(mob/user)
+ if(can_change_colour && !isturf(loc) && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ select_colour(user)
+ else
+ return ..()
+
/obj/item/toy/crayon/proc/staticDrawables()
. = list()
@@ -237,14 +248,7 @@
else
paint_mode = PAINT_NORMAL
if("select_colour")
- if(can_change_colour)
- var/chosen_colour = input(usr,"","Choose Color",paint_color) as color|null
-
- if (!isnull(chosen_colour))
- paint_color = chosen_colour
- . = TRUE
- else
- . = FALSE
+ . = can_change_colour && select_colour(usr)
if("enter_text")
var/txt = stripped_input(usr,"Choose what to write.",
"Scribbles",default = text_buffer)
@@ -254,6 +258,13 @@
drawtype = "a"
update_icon()
+/obj/item/toy/crayon/proc/select_colour(mob/user)
+ var/chosen_colour = input(user, "", "Choose Color", paint_color) as color|null
+ if (!isnull(chosen_colour) && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ paint_color = chosen_colour
+ return TRUE
+ return FALSE
+
/obj/item/toy/crayon/proc/crayon_text_strip(text)
var/static/regex/crayon_r = new /regex(@"[^\w!?,.=%#&+\/\-]")
return replacetext(lowertext(text), crayon_r, "")
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index 92c2d40c98..b683ea9934 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -433,7 +433,7 @@
H.visible_message("The defibrillator safely discharges the excessive charge into the floor!")
return
var/mob/living/M = H.pulledby
- if(M.electrocute_act(30, src))
+ if(M.electrocute_act(30, H))
M.visible_message("[M] is electrocuted by [M.p_their()] contact with [H]!")
M.emote("scream")
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index 1d2a2c9ad1..c931d92379 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -135,7 +135,7 @@
outmsg = "You miss the lens of [C] with [src]!"
//catpeople
- var/list/viewers = get_actual_viewers(1,targloc)
+ var/list/viewers = fov_viewers(1,targloc)
for(var/mob/living/carbon/human/H in viewers)
if(!iscatperson(H) || H.incapacitated() || H.eye_blind )
continue
diff --git a/code/game/objects/items/implants/implantpad.dm b/code/game/objects/items/implants/implantpad.dm
index f0fc76a2e2..4766e534c9 100644
--- a/code/game/objects/items/implants/implantpad.dm
+++ b/code/game/objects/items/implants/implantpad.dm
@@ -66,7 +66,7 @@
if(ismob(loc))
attack_self(loc)
else
- for(var/mob/M in get_actual_viewers(1, src))
+ for(var/mob/M in fov_viewers(1, src))
if(M.client)
attack_self(M)
add_fingerprint(usr)
diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm
index fc7b196bd2..1459afeb2d 100644
--- a/code/game/objects/items/shields.dm
+++ b/code/game/objects/items/shields.dm
@@ -197,10 +197,10 @@
if(obj_integrity >= max_integrity)
to_chat(user, "[src] is already in perfect condition.")
else
- var/obj/item/stack/sheet/mineral/titanium/T = W
- T.use(1)
+ var/obj/item/stack/S = W
+ S.use(1)
obj_integrity = max_integrity
- to_chat(user, "You repair [src] with [T].")
+ to_chat(user, "You repair [src] with [S].")
else
return ..()
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index f19dbb2a6b..aebc5121cd 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -5,7 +5,6 @@
* Wood
* Bamboo
* Cloth
- * Silk
* Durathread
* Cardboard
* Runed Metal (cult)
@@ -268,6 +267,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\
null, \
new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\
+ new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\
new/datum/stack_recipe("mortar", /obj/item/reagent_containers/glass/mortar, 3), \
new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 10),\
))
@@ -388,6 +388,9 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
null, \
new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/sunglasses/blindfold, 2), \
null, \
+ new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteenXnineteen, 3), \
+ new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythreeXnineteen, 4), \
+ new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythreeXtwentythree, 5), \
))
/obj/item/stack/sheet/cloth
@@ -401,7 +404,6 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
throwforce = 0
pull_effort = 90
is_fabric = TRUE
- loom_result = /obj/item/stack/sheet/silk
merge_type = /obj/item/stack/sheet/cloth
/obj/item/stack/sheet/cloth/get_main_recipes()
@@ -414,30 +416,6 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
/obj/item/stack/sheet/cloth/thirty
amount = 30
-/*
- * Silk
- */
-
- GLOBAL_LIST_INIT(silk_recipes, list ( \
- new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 4, time = 40), \
- new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 2, time = 40), \
- null, \
- new/datum/stack_recipe("silk string", /obj/item/weaponcrafting/silkstring, 1, time = 40), \
- ))
-
-/obj/item/stack/sheet/silk
- name = "silk"
- desc = "A long, soft material. Made out of refined cotton, instead of relying on the habits of spiders or silkworms."
- singular_name = "silk sheet"
- icon_state = "sheet-silk"
- item_state = "sheet-cloth"
- novariants = TRUE
- merge_type = /obj/item/stack/sheet/silk
-
-/obj/item/stack/sheet/silk/get_main_recipes()
- . = ..()
- . += GLOB.silk_recipes
-
/*
* Durathread
*/
@@ -446,6 +424,7 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \
new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 40), \
new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 40), \
new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \
+ new/datum/stack_recipe("durathread string", /obj/item/weaponcrafting/durathread_string, 1, time = 40) \
))
/obj/item/stack/sheet/durathread
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 52802fa3df..5b7eb65d9b 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -61,7 +61,7 @@
switch(contents.len)
if(0)
icon_state = "[initial(icon_state)]"
- if(0 to 11)
+ if(1 to 11)
icon_state = "[initial(icon_state)]1"
if(11 to 20)
icon_state = "[initial(icon_state)]2"
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 57e9ea9aaa..de5f332f43 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -210,6 +210,7 @@
power = 8
force = 10
precision = 1
+ total_mass = 0.2
cooling_power = 5
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT // don't put in storage
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index d3272616b3..881e4d5f1a 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -104,7 +104,7 @@
if (ismob(src.loc))
attack_self(src.loc)
else
- for(var/mob/M in get_actual_viewers(1, src))
+ for(var/mob/M in fov_viewers(1, src))
if (M.client)
src.attack_self(M)
return
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index fc5680e524..dc39f7f89d 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -478,6 +478,20 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throw_range = 2
attack_verb = list("busted")
+/obj/item/statuebust/attack_self(mob/living/user)
+ add_fingerprint(user)
+ user.examinate(src)
+
+/obj/item/statuebust/examine(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ if (!isliving(user))
+ return
+ user.visible_message("[user] stops to admire [src].", \
+ "You take in [src], admiring its fine craftsmanship.")
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood)
+
/obj/item/tailclub
name = "tail club"
desc = "For the beating to death of lizards with their own tails."
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 8dac972d04..e64b7d8f8d 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -112,7 +112,7 @@
/obj/attack_animal(mob/living/simple_animal/M)
if(!M.melee_damage_upper && !M.obj_damage)
- M.emote("custom", message = "[M.friendly] [src].")
+ M.emote("custom", message = "[M.friendly_verb_continuous] [src].")
return 0
else
var/play_soundeffect = 1
@@ -232,15 +232,16 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
cut_overlay(GLOB.fire_overlay, TRUE)
SSfire_burning.processing -= src
-/obj/proc/tesla_act(power, tesla_flags, shocked_targets)
+/obj/zap_act(power, zap_flags, shocked_targets)
+ if(QDELETED(src))
+ return 0
obj_flags |= BEING_SHOCKED
- var/power_bounced = power / 2
- tesla_zap(src, 3, power_bounced, tesla_flags, shocked_targets)
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
+ return power / 2
//The surgeon general warns that being buckled to certain objects receiving powerful shocks is greatly hazardous to your health
-//Only tesla coils and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later.
-/obj/proc/tesla_buckle_check(var/strength)
+//Only tesla coils, vehicles, and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later.
+/obj/proc/zap_buckle_check(var/strength)
if(has_buckled_mobs())
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 6916e7c24a..0b2fe5ac2a 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -123,7 +123,7 @@
/obj/proc/updateUsrDialog()
if((obj_flags & IN_USE) && !(obj_flags & USES_TGUI))
var/is_in_use = FALSE
- var/list/nearby = get_actual_viewers(1, src)
+ var/list/nearby = fov_viewers(1, src)
for(var/mob/M in nearby)
if ((M.client && M.machine == src))
is_in_use = TRUE
@@ -152,7 +152,7 @@
if(obj_flags & IN_USE)
var/is_in_use = FALSE
if(update_viewers)
- for(var/mob/M in get_actual_viewers(1, src))
+ for(var/mob/M in fov_viewers(1, src))
if ((M.client && M.machine == src))
is_in_use = TRUE
src.interact(M)
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 405e697d3b..98f772a116 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -35,101 +35,368 @@
else
painting = null
-
-//////////////
-// CANVASES //
-//////////////
-
-#define AMT_OF_CANVASES 4 //Keep this up to date or shit will break.
-
-//To safe memory on making /icons we cache the blanks..
-GLOBAL_LIST_INIT(globalBlankCanvases, new(AMT_OF_CANVASES))
-
/obj/item/canvas
name = "canvas"
desc = "Draw out your soul on this canvas!"
icon = 'icons/obj/artstuff.dmi'
icon_state = "11x11"
resistance_flags = FLAMMABLE
- var/whichGlobalBackup = 1 //List index
+ var/width = 11
+ var/height = 11
+ var/list/grid
+ var/canvas_color = "#ffffff" //empty canvas color
+ var/ui_x = 400
+ var/ui_y = 400
+ var/used = FALSE
+ var/painting_name //Painting name, this is set after framing.
+ var/finalized = FALSE //Blocks edits
+ var/author_ckey
+ var/icon_generated = FALSE
+ var/icon/generated_icon
-/obj/item/canvas/nineteenXnineteen
- icon_state = "19x19"
- whichGlobalBackup = 2
+ // Painting overlay offset when framed
+ var/framed_offset_x = 11
+ var/framed_offset_y = 10
-/obj/item/canvas/twentythreeXnineteen
- icon_state = "23x19"
- whichGlobalBackup = 3
+ pixel_x = 10
+ pixel_y = 9
-/obj/item/canvas/twentythreeXtwentythree
- icon_state = "23x23"
- whichGlobalBackup = 4
-
-//HEY YOU
-//ARE YOU READING THE CODE FOR CANVASES?
-//ARE YOU AWARE THEY CRASH HALF THE SERVER WHEN SOMEONE DRAWS ON THEM...
-//...AND NOBODY CAN FIGURE OUT WHY?
-//THEN GO ON BRAVE TRAVELER
-//TRY TO FIX THEM AND REMOVE THIS CODE
/obj/item/canvas/Initialize()
- ..()
- return INITIALIZE_HINT_QDEL //Delete on creation
+ . = ..()
+ reset_grid()
-//Find the right size blank canvas
-/obj/item/canvas/proc/getGlobalBackup()
- . = null
- if(GLOB.globalBlankCanvases[whichGlobalBackup])
- . = GLOB.globalBlankCanvases[whichGlobalBackup]
- else
- var/icon/I = icon(initial(icon),initial(icon_state))
- GLOB.globalBlankCanvases[whichGlobalBackup] = I
- . = I
+/obj/item/canvas/proc/reset_grid()
+ grid = new/list(width,height)
+ for(var/x in 1 to width)
+ for(var/y in 1 to height)
+ grid[x][y] = canvas_color
+/obj/item/canvas/attack_self(mob/user)
+ . = ..()
+ ui_interact(user)
+/obj/item/canvas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
-//One pixel increments
-/obj/item/canvas/attackby(obj/item/I, mob/user, params)
- //Click info
- var/list/click_params = params2list(params)
- var/pixX = text2num(click_params["icon-x"])
- var/pixY = text2num(click_params["icon-y"])
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "canvas", name, ui_x, ui_y, master_ui, state)
+ ui.set_autoupdate(FALSE)
+ ui.open()
- //Should always be true, otherwise you didn't click the object, but let's check because SS13~
- if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
- return
-
- //Cleaning one pixel with a soap or rag
- if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag))
- //Pixel info created only when needed
- var/icon/masterpiece = icon(icon,icon_state)
- var/thePix = masterpiece.GetPixel(pixX,pixY)
- var/icon/Ico = getGlobalBackup()
- if(!Ico)
- qdel(masterpiece)
- return
-
- var/theOriginalPix = Ico.GetPixel(pixX,pixY)
- if(thePix != theOriginalPix) //colour changed
- DrawPixelOn(theOriginalPix,pixX,pixY)
- qdel(masterpiece)
-
- //Drawing one pixel with a crayon
- else if(istype(I, /obj/item/toy/crayon))
- var/obj/item/toy/crayon/C = I
- DrawPixelOn(C.paint_color, pixX, pixY)
+/obj/item/canvas/attackby(obj/item/I, mob/living/user, params)
+ if(user.a_intent == INTENT_HELP)
+ ui_interact(user)
else
return ..()
+/obj/item/canvas/ui_data(mob/user)
+ . = ..()
+ .["grid"] = grid
+ .["name"] = painting_name
+ .["finalized"] = finalized
-//Clean the whole canvas
-/obj/item/canvas/attack_self(mob/user)
- if(!user)
+/obj/item/canvas/examine(mob/user)
+ . = ..()
+ ui_interact(user)
+
+/obj/item/canvas/ui_act(action, params)
+ . = ..()
+ if(. || finalized)
return
- var/icon/blank = getGlobalBackup()
- if(blank)
- //it's basically a giant etch-a-sketch
- icon = blank
- user.visible_message("[user] cleans the canvas.","You clean the canvas.")
+ var/mob/user = usr
+ switch(action)
+ if("paint")
+ var/obj/item/I = user.get_active_held_item()
+ var/color = get_paint_tool_color(I)
+ if(!color)
+ return FALSE
+ var/x = text2num(params["x"])
+ var/y = text2num(params["y"])
+ grid[x][y] = color
+ used = TRUE
+ update_icon()
+ . = TRUE
+ if("finalize")
+ . = TRUE
+ if(!finalized)
+ finalize(user)
+
+/obj/item/canvas/proc/finalize(mob/user)
+ finalized = TRUE
+ author_ckey = user.ckey
+ generate_proper_overlay()
+ try_rename(user)
+
+/obj/item/canvas/update_overlays()
+ . = ..()
+ if(!icon_generated)
+ if(used)
+ var/mutable_appearance/detail = mutable_appearance(icon,"[icon_state]wip")
+ detail.pixel_x = 1
+ detail.pixel_y = 1
+ . += detail
+ else
+ var/mutable_appearance/detail = mutable_appearance(generated_icon)
+ detail.pixel_x = 1
+ detail.pixel_y = 1
+ . += detail
+
+/obj/item/canvas/proc/generate_proper_overlay()
+ if(icon_generated)
+ return
+ var/png_filename = "data/paintings/temp_painting.png"
+ var/result = rustg_dmi_create_png(png_filename,"[width]","[height]",get_data_string())
+ if(result)
+ CRASH("Error generating painting png : [result]")
+ generated_icon = new(png_filename)
+ icon_generated = TRUE
+ update_icon()
+
+/obj/item/canvas/proc/get_data_string()
+ var/list/data = list()
+ for(var/y in 1 to height)
+ for(var/x in 1 to width)
+ data += grid[x][y]
+ return data.Join("")
+
+//Todo make this element ?
+/obj/item/canvas/proc/get_paint_tool_color(obj/item/I)
+ if(!I)
+ return
+ if(istype(I, /obj/item/toy/crayon))
+ var/obj/item/toy/crayon/C = I
+ return C.paint_color
+ else if(istype(I, /obj/item/pen))
+ var/obj/item/pen/P = I
+ switch(P.colour)
+ if("black")
+ return "#000000"
+ if("blue")
+ return "#0000ff"
+ if("red")
+ return "#ff0000"
+ return P.colour
+ else if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag))
+ return canvas_color
+
+/obj/item/canvas/proc/try_rename(mob/user)
+ var/new_name = stripped_input(user,"What do you want to name the painting?")
+ if(!painting_name && new_name && user.canUseTopic(src,BE_CLOSE))
+ painting_name = new_name
+ SStgui.update_uis(src)
+
+/obj/item/canvas/nineteenXnineteen
+ icon_state = "19x19"
+ width = 19
+ height = 19
+ ui_x = 600
+ ui_y = 600
+ pixel_x = 6
+ pixel_y = 9
+ framed_offset_x = 8
+ framed_offset_y = 9
+
+/obj/item/canvas/twentythreeXnineteen
+ icon_state = "23x19"
+ width = 23
+ height = 19
+ ui_x = 800
+ ui_y = 600
+ pixel_x = 4
+ pixel_y = 10
+ framed_offset_x = 6
+ framed_offset_y = 8
+
+/obj/item/canvas/twentythreeXtwentythree
+ icon_state = "23x23"
+ width = 23
+ height = 23
+ ui_x = 800
+ ui_y = 800
+ pixel_x = 5
+ pixel_y = 9
+ framed_offset_x = 5
+ framed_offset_y = 6
+
+/obj/item/wallframe/painting
+ name = "painting frame"
+ desc = "The perfect showcase for your favorite deathtrap memories."
+ icon = 'icons/obj/decals.dmi'
+ custom_materials = null
+ flags_1 = 0
+ icon_state = "frame-empty"
+ result_path = /obj/structure/sign/painting
+
+/obj/structure/sign/painting
+ name = "Painting"
+ desc = "Art or \"Art\"? You decide."
+ icon = 'icons/obj/decals.dmi'
+ icon_state = "frame-empty"
+ buildable_sign = FALSE
+ var/obj/item/canvas/C
+ var/persistence_id
+
+/obj/structure/sign/painting/Initialize(mapload, dir, building)
+ . = ..()
+ SSpersistence.painting_frames += src
+ AddComponent(/datum/component/art, 20)
+ if(dir)
+ setDir(dir)
+ if(building)
+ pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
+ pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
+
+/obj/structure/sign/painting/Destroy()
+ . = ..()
+ SSpersistence.painting_frames -= src
+
+/obj/structure/sign/painting/attackby(obj/item/I, mob/user, params)
+ if(!C && istype(I, /obj/item/canvas))
+ frame_canvas(user,I)
+ else if(C && !C.painting_name && istype(I,/obj/item/pen))
+ try_rename(user)
+ else
+ return ..()
+
+/obj/structure/sign/painting/examine(mob/user)
+ . = ..()
+ if(C)
+ C.ui_interact(user,state = GLOB.physical_obscured_state)
+
+/obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(C)
+ C.forceMove(drop_location())
+ C = null
+ to_chat(user, "You remove the painting from the frame.")
+ update_icon()
+ return TRUE
+
+/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas)
+ if(user.transferItemToLoc(new_canvas,src))
+ C = new_canvas
+ if(!C.finalized)
+ C.finalize(user)
+ to_chat(user,"You frame [C].")
+ update_icon()
+
+/obj/structure/sign/painting/proc/try_rename(mob/user)
+ if(!C.painting_name)
+ C.try_rename(user)
+
+/obj/structure/sign/painting/update_icon_state()
+ . = ..()
+ if(C && C.generated_icon)
+ icon_state = null
+ else
+ icon_state = "frame-empty"
-#undef AMT_OF_CANVASES
+/obj/structure/sign/painting/update_overlays()
+ . = ..()
+ if(C && C.generated_icon)
+ var/mutable_appearance/MA = mutable_appearance(C.generated_icon)
+ MA.pixel_x = C.framed_offset_x
+ MA.pixel_y = C.framed_offset_y
+ . += MA
+ var/mutable_appearance/frame = mutable_appearance(C.icon,"[C.icon_state]frame")
+ frame.pixel_x = C.framed_offset_x - 1
+ frame.pixel_y = C.framed_offset_y - 1
+ . += frame
+
+/obj/structure/sign/painting/proc/load_persistent()
+ if(!persistence_id)
+ return
+ if(!SSpersistence.paintings || !SSpersistence.paintings[persistence_id] || !length(SSpersistence.paintings[persistence_id]))
+ return
+ var/list/chosen = pick(SSpersistence.paintings[persistence_id])
+ var/title = chosen["title"]
+ var/author = chosen["ckey"]
+ var/png = "data/paintings/[persistence_id]/[chosen["md5"]].png"
+ if(!fexists(png))
+ stack_trace("Persistent painting [chosen["md5"]].png was not found in [persistence_id] directory.")
+ return
+ var/icon/I = new(png)
+ var/obj/item/canvas/new_canvas
+ var/w = I.Width()
+ var/h = I.Height()
+ for(var/T in typesof(/obj/item/canvas))
+ new_canvas = T
+ if(initial(new_canvas.width) == w && initial(new_canvas.height) == h)
+ new_canvas = new T(src)
+ break
+ new_canvas.fill_grid_from_icon(I)
+ new_canvas.generated_icon = I
+ new_canvas.icon_generated = TRUE
+ new_canvas.finalized = TRUE
+ new_canvas.painting_name = title
+ new_canvas.author_ckey = author
+ C = new_canvas
+ update_icon()
+
+/obj/structure/sign/painting/proc/save_persistent()
+ if(!persistence_id || !C)
+ return
+ if(sanitize_filename(persistence_id) != persistence_id)
+ stack_trace("Invalid persistence_id - [persistence_id]")
+ return
+ var/data = C.get_data_string()
+ var/md5 = md5(data)
+ var/list/current = SSpersistence.paintings[persistence_id]
+ if(!current)
+ current = list()
+ for(var/list/entry in current)
+ if(entry["md5"] == md5)
+ return
+ var/png_directory = "data/paintings/[persistence_id]/"
+ var/png_path = png_directory + "[md5].png"
+ var/result = rustg_dmi_create_png(png_path,"[C.width]","[C.height]",data)
+ if(result)
+ CRASH("Error saving persistent painting: [result]")
+ current += list(list("title" = C.painting_name , "md5" = md5, "ckey" = C.author_ckey))
+ SSpersistence.paintings[persistence_id] = current
+
+/obj/item/canvas/proc/fill_grid_from_icon(icon/I)
+ var/h = I.Height() + 1
+ for(var/x in 1 to width)
+ for(var/y in 1 to height)
+ grid[x][y] = I.GetPixel(x,h-y)
+
+//Presets for art gallery mapping, for paintings to be shared across stations
+/obj/structure/sign/painting/library
+ persistence_id = "library"
+
+/obj/structure/sign/painting/library_secure
+ persistence_id = "library_secure"
+
+/obj/structure/sign/painting/library_private // keep your smut away from prying eyes, or non-librarians at least
+ persistence_id = "library_private"
+
+/obj/structure/sign/painting/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION(VV_HK_REMOVE_PAINTING, "Remove Persistent Painting")
+
+/obj/structure/sign/painting/vv_do_topic(list/href_list)
+ . = ..()
+ if(href_list[VV_HK_REMOVE_PAINTING])
+ if(!check_rights(NONE))
+ return
+ var/mob/user = usr
+ if(!persistence_id || !C)
+ to_chat(user,"This is not a persistent painting.")
+ return
+ var/md5 = md5(C.get_data_string())
+ var/author = C.author_ckey
+ var/list/current = SSpersistence.paintings[persistence_id]
+ if(current)
+ for(var/list/entry in current)
+ if(entry["md5"] == md5)
+ current -= entry
+ var/png = "data/paintings/[persistence_id]/[md5].png"
+ fdel(png)
+ for(var/obj/structure/sign/painting/P in SSpersistence.painting_frames)
+ if(P.C && md5(P.C.get_data_string()) == md5)
+ QDEL_NULL(P.C)
+ log_admin("[key_name(user)] has deleted a persistent painting made by [author].")
+ message_admins("[key_name_admin(user)] has deleted persistent painting made by [author].")
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index d3e8ecf0a6..2225c4c0c2 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -108,7 +108,9 @@
if(!istype(poordude))
return TRUE
user.visible_message("[user] pulls [src] out from under [poordude].", "You pull [src] out from under [poordude].")
- var/C = new item_chair(loc)
+ var/obj/item/chair/C = new item_chair(loc)
+ C.set_custom_materials(custom_materials)
+ TransferComponents(C)
user.put_in_hands(C)
poordude.DefaultCombatKnockdown(20)//rip in peace
user.adjustStaminaLoss(5)
diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
index 6256de247a..500b8d6a49 100644
--- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
+++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
@@ -43,7 +43,7 @@
Snake = L
break
if(Snake)
- alerted = get_actual_viewers(world.view,src)
+ alerted = fov_viewers(world.view,src)
..()
if(LAZYLEN(alerted))
egged = world.time + SNAKE_SPAM_TICKS
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 54e08db210..20151a0bdb 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -267,7 +267,7 @@
var/obj/structure/cable/C = T.get_cable_node()
if(C)
playsound(src, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
- tesla_zap(src, 3, C.newavail() * 0.01, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN | TESLA_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
+ tesla_zap(src, 3, C.newavail() * 0.01, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock.
return ..()
diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm
index b8137d1332..0a5ba6a68c 100644
--- a/code/game/objects/structures/guillotine.dm
+++ b/code/game/objects/structures/guillotine.dm
@@ -130,7 +130,7 @@
// The crowd is pleased
// The delay is to making large crowds have a longer laster applause
var/delay_offset = 0
- for(var/mob/M in get_actual_viewers(world.view, src))
+ for(var/mob/M in fov_viewers(world.view, src))
var/mob/living/carbon/human/C = M
if (ishuman(M))
addtimer(CALLBACK(C, /mob/.proc/emote, "clap"), delay_offset * 0.3)
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index 9a6b24b472..1f9491f4cf 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -8,12 +8,11 @@
max_integrity = 100
var/oreAmount = 5
var/material_drop_type = /obj/item/stack/sheet/metal
+ var/impressiveness = 15
CanAtmosPass = ATMOS_PASS_DENSITY
-
/obj/structure/statue/attackby(obj/item/W, mob/living/user, params)
add_fingerprint(user)
- user.changeNext_move(CLICK_CD_MELEE)
if(!(flags_1 & NODECONSTRUCT_1))
if(default_unfasten_wrench(user, W))
return
@@ -36,8 +35,22 @@
return
user.changeNext_move(CLICK_CD_MELEE)
add_fingerprint(user)
- user.visible_message("[user] rubs some dust off from the [name]'s surface.", \
- "You rub some dust off from the [name]'s surface.")
+ if(!do_after(user, 20, target = src))
+ return
+ user.visible_message("[user] rubs some dust off [src].", \
+ "You take in [src], rubbing some dust off its surface.")
+ if(!ishuman(user)) // only humans have the capacity to appreciate art
+ return
+ var/totalimpressiveness = (impressiveness *(obj_integrity/max_integrity))
+ switch(totalimpressiveness)
+ if(GREAT_ART to 100)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
+ if (GOOD_ART to GREAT_ART)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood)
+ if (BAD_ART to GOOD_ART)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok)
+ if (0 to BAD_ART)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
/obj/structure/statue/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
@@ -58,6 +71,7 @@
material_drop_type = /obj/item/stack/sheet/mineral/uranium
var/last_event = 0
var/active = null
+ impressiveness = 25 // radiation makes an impression
/obj/structure/statue/uranium/nuke
name = "statue of a nuclear fission explosive"
@@ -101,6 +115,7 @@
max_integrity = 200
material_drop_type = /obj/item/stack/sheet/mineral/plasma
desc = "This statue is suitably made from plasma."
+ impressiveness = 20
/obj/structure/statue/plasma/scientist
name = "statue of a scientist"
@@ -151,6 +166,7 @@
max_integrity = 300
material_drop_type = /obj/item/stack/sheet/mineral/gold
desc = "This is a highly valuable statue made from gold."
+ impressiveness = 30
/obj/structure/statue/gold/hos
name = "statue of the head of security"
@@ -178,6 +194,7 @@
max_integrity = 300
material_drop_type = /obj/item/stack/sheet/mineral/silver
desc = "This is a valuable statue made from silver."
+ impressiveness = 25
/obj/structure/statue/silver/md
name = "statue of a medical officer"
@@ -205,6 +222,7 @@
max_integrity = 1000
material_drop_type = /obj/item/stack/sheet/mineral/diamond
desc = "This is a very expensive diamond statue."
+ impressiveness = 60
/obj/structure/statue/diamond/captain
name = "statue of THE captain."
@@ -225,6 +243,7 @@
material_drop_type = /obj/item/stack/sheet/mineral/bananium
desc = "A bananium statue with a small engraving:'HOOOOOOONK'."
var/spam_flag = 0
+ impressiveness = 65
/obj/structure/statue/bananium/clown
name = "statue of a clown"
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 30e451aa14..3d552fa236 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -183,7 +183,7 @@
/obj/structure/table/alt_attack_hand(mob/user)
if(user && Adjacent(user) && !user.incapacitated())
- user.setClickCooldown(4)
+ user.changeNext_move(CLICK_CD_MELEE*0.5)
if(istype(user) && user.a_intent == INTENT_HARM)
user.visible_message("[user] slams [user.p_their()] palms down on [src].", "You slam your palms down on [src].")
playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm
index 3a719d05b9..38e0839617 100644
--- a/code/game/turfs/change_turf.dm
+++ b/code/game/turfs/change_turf.dm
@@ -80,7 +80,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/old_dynamic_lighting = dynamic_lighting
var/old_affecting_lights = affecting_lights
var/old_lighting_object = lighting_object
- var/old_corners = corners
+ var/old_lc_topright = lc_topright
+ var/old_lc_topleft = lc_topleft
+ var/old_lc_bottomright = lc_bottomright
+ var/old_lc_bottomleft = lc_bottomleft
var/old_exl = explosion_level
var/old_exi = explosion_id
@@ -119,7 +122,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
recalc_atom_opacity()
lighting_object = old_lighting_object
affecting_lights = old_affecting_lights
- corners = old_corners
+ lc_topright = old_lc_topright
+ lc_topleft = old_lc_topleft
+ lc_bottomright = old_lc_bottomright
+ lc_bottomleft = old_lc_bottomleft
if (old_opacity != opacity || dynamic_lighting != old_dynamic_lighting)
reconsider_lights()
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 268e8e9109..5243341ac1 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -290,7 +290,7 @@
if(LAZYLEN(dent_decals) >= MAX_DENT_DECALS)
return
- var/mutable_appearance/decal = mutable_appearance('icons/effects/effects.dmi', "", BULLET_HOLE_LAYER)
+ var/mutable_appearance/decal = mutable_appearance('icons/effects/effects.dmi', "", BULLET_HOLE_LAYER, ABOVE_WALL_PLANE)
switch(denttype)
if(WALL_DENT_SHOT)
decal.icon_state = "bullet_hole"
diff --git a/code/game/world.dm b/code/game/world.dm
index 10431e4af9..1c6f3bceba 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -1,6 +1,7 @@
#define RESTART_COUNTER_PATH "data/round_counter.txt"
GLOBAL_VAR(restart_counter)
+GLOBAL_VAR_INIT(tgs_initialized, FALSE)
GLOBAL_VAR(topic_status_lastcache)
GLOBAL_LIST(topic_status_cache)
@@ -23,10 +24,11 @@ GLOBAL_LIST(topic_status_cache)
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
- TgsNew(minimum_required_security_level = TGS_SECURITY_TRUSTED)
GLOB.revdata = new
+ InitTgs()
+
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
//SetupLogs depends on the RoundID, so lets check
@@ -62,6 +64,15 @@ GLOBAL_LIST(topic_status_cache)
if(TEST_RUN_PARAMETER in params)
HandleTestRun()
+/world/proc/InitTgs()
+ TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED)
+ GLOB.revdata.load_tgs_info()
+#ifdef USE_CUSTOM_ERROR_HANDLER
+ if (TgsAvailable())
+ world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them.
+#endif
+ GLOB.tgs_initialized = TRUE
+
/world/proc/HandleTestRun()
//trigger things to run the whole process
Master.sleep_offline_after_initializations = FALSE
@@ -125,6 +136,7 @@ GLOBAL_LIST(topic_status_cache)
GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log"
GLOB.reagent_log = "[GLOB.log_directory]/reagents.log"
GLOB.world_crafting_log = "[GLOB.log_directory]/crafting.log"
+ GLOB.click_log = "[GLOB.log_directory]/click.log"
#ifdef UNIT_TESTS
@@ -144,6 +156,7 @@ GLOBAL_LIST(topic_status_cache)
start_log(GLOB.subsystem_log)
start_log(GLOB.reagent_log)
start_log(GLOB.world_crafting_log)
+ start_log(GLOB.click_log)
GLOB.changelog_hash = md5('html/changelog.html') //for telling if the changelog has changed recently
if(fexists(GLOB.config_error_log))
@@ -223,16 +236,17 @@ GLOBAL_LIST(topic_status_cache)
qdel(src) //shut it down
/world/Reboot(reason = 0, fast_track = FALSE)
- TgsReboot()
if (reason || fast_track) //special reboot, do none of the normal stuff
if (usr)
log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
- to_chat(world, "Rebooting World immediately due to host request")
+ to_chat(world, "Rebooting World immediately due to host request.")
else
to_chat(world, "Rebooting world...")
Master.Shutdown() //run SS shutdowns
+ TgsReboot()
+
if(TEST_RUN_PARAMETER in params)
FinishTestRun()
return
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index a06b674e42..41662c1cad 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -69,11 +69,6 @@
The floor is lava! (DANGEROUS: extremely lame)
Spawn a custom portal storm
- Flip client movement directions
- Randomize client movement directions
- Set each movement direction manually
- Reset movement directions to default
-
Change bomb cap
Mass Purrbation
Mass Remove Purrbation
@@ -603,60 +598,6 @@
purrbation.")
log_admin("[key_name(usr)] has removed everyone from purrbation.")
- if("flipmovement")
- if(!check_rights(R_FUN))
- return
- if(alert("Flip all movement controls?","Confirm","Yes","Cancel") == "Cancel")
- return
- var/list/movement_keys = SSinput.movement_keys
- for(var/i in 1 to movement_keys.len)
- var/key = movement_keys[i]
- movement_keys[key] = turn(movement_keys[key], 180)
- message_admins("[key_name_admin(usr)] has flipped all movement directions.")
- log_admin("[key_name(usr)] has flipped all movement directions.")
-
- if("randommovement")
- if(!check_rights(R_FUN))
- return
- if(alert("Randomize all movement controls?","Confirm","Yes","Cancel") == "Cancel")
- return
- var/list/movement_keys = SSinput.movement_keys
- for(var/i in 1 to movement_keys.len)
- var/key = movement_keys[i]
- movement_keys[key] = turn(movement_keys[key], 45 * rand(1, 8))
- message_admins("[key_name_admin(usr)] has randomized all movement directions.")
- log_admin("[key_name(usr)] has randomized all movement directions.")
-
- if("custommovement")
- if(!check_rights(R_FUN))
- return
- if(alert("Are you sure you want to change every movement key?","Confirm","Yes","Cancel") == "Cancel")
- return
- var/list/movement_keys = SSinput.movement_keys
- var/list/new_movement = list()
- for(var/i in 1 to movement_keys.len)
- var/key = movement_keys[i]
-
- var/msg = "Please input the new movement direction when the user presses [key]. Ex. northeast"
- var/title = "New direction for [key]"
- var/new_direction = text2dir(input(usr, msg, title) as text|null)
- if(!new_direction)
- new_direction = movement_keys[key]
-
- new_movement[key] = new_direction
- SSinput.movement_keys = new_movement
- message_admins("[key_name_admin(usr)] has configured all movement directions.")
- log_admin("[key_name(usr)] has configured all movement directions.")
-
- if("resetmovement")
- if(!check_rights(R_FUN))
- return
- if(alert("Are you sure you want to reset movement keys to default?","Confirm","Yes","Cancel") == "Cancel")
- return
- SSinput.setup_default_movement_keys()
- message_admins("[key_name_admin(usr)] has reset all movement keys.")
- log_admin("[key_name(usr)] has reset all movement keys.")
-
if("customportal")
if(!check_rights(R_FUN))
return
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index 4a7abda53c..3184a169fc 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -24,6 +24,8 @@ GLOBAL_LIST_EMPTY(antagonists)
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
+ var/list/skill_modifiers
+
/datum/antagonist/New()
GLOB.antagonists += src
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
@@ -68,15 +70,19 @@ GLOBAL_LIST_EMPTY(antagonists)
//Proc called when the datum is given to a mind.
/datum/antagonist/proc/on_gain()
- if(owner && owner.current)
- if(!silent)
- greet()
- apply_innate_effects()
- give_antag_moodies()
- remove_blacklisted_quirks()
- if(is_banned(owner.current) && replace_banned)
- replace_banned_player()
- SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
+ if(!(owner?.current))
+ return
+ if(!silent)
+ greet()
+ apply_innate_effects()
+ give_antag_moodies()
+ remove_blacklisted_quirks()
+ if(is_banned(owner.current) && replace_banned)
+ replace_banned_player()
+ if(skill_modifiers)
+ for(var/A in skill_modifiers)
+ ADD_SINGLETON_SKILL_MODIFIER(owner, A, type)
+ SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
@@ -99,6 +105,8 @@ GLOBAL_LIST_EMPTY(antagonists)
clear_antag_moodies()
if(owner)
LAZYREMOVE(owner.antag_datums, src)
+ for(var/A in skill_modifiers)
+ owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type))
if(!silent && owner.current)
farewell()
var/datum/team/team = get_team()
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index 44116dbe36..9132288415 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -21,6 +21,7 @@
landmark_type = /obj/effect/landmark/abductor/agent
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
show_in_antagpanel = TRUE
+ skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
/datum/antagonist/abductor/scientist
name = "Abductor Scientist"
@@ -29,6 +30,7 @@
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans."
show_in_antagpanel = TRUE
+ skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery)
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm
index 82ee77d192..7e52f6fcb6 100644
--- a/code/modules/antagonists/abductor/equipment/glands/electric.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm
@@ -23,5 +23,5 @@
addtimer(CALLBACK(src, .proc/zap), rand(30, 100))
/obj/item/organ/heart/gland/electric/proc/zap()
- tesla_zap(owner, 4, 8000, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN)
+ tesla_zap(owner, 4, 8000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN)
playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE)
\ No newline at end of file
diff --git a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm
index fbdeea6b84..91fb538ca3 100644
--- a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm
+++ b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm
@@ -86,7 +86,8 @@
melee_damage_upper = 4
obj_damage = 20
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
- attacktext = "hits"
+ attack_verb_continuous = "hits"
+ attack_verb_simple = "hit"
attack_sound = 'sound/weapons/genhit1.ogg'
movement_type = FLYING
del_on_death = 1
@@ -205,7 +206,8 @@
melee_damage_lower = 20
melee_damage_upper = 20
obj_damage = 60
- attacktext = "slams"
+ attack_verb_continuous = "slams"
+ attack_verb_simple = "slam"
attack_sound = 'sound/effects/blobattack.ogg'
verb_say = "gurgles"
verb_ask = "demands"
@@ -284,11 +286,11 @@
if(overmind) //if we have an overmind, we're doing chemical reactions instead of pure damage
melee_damage_lower = 4
melee_damage_upper = 4
- attacktext = overmind.blobstrain.blobbernaut_message
+ attack_verb_continuous = overmind.blobstrain.blobbernaut_message
else
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
- attacktext = initial(attacktext)
+ attack_verb_continuous = initial(attack_verb_continuous)
/mob/living/simple_animal/hostile/blob/blobbernaut/death(gibbed)
..(gibbed)
diff --git a/code/modules/antagonists/blob/blob/theblob.dm b/code/modules/antagonists/blob/blob/theblob.dm
index 5717dc557d..6a73dc579b 100644
--- a/code/modules/antagonists/blob/blob/theblob.dm
+++ b/code/modules/antagonists/blob/blob/theblob.dm
@@ -207,8 +207,8 @@
if(prob(100 - severity * 30))
new /obj/effect/temp_visual/emp(get_turf(src))
-/obj/structure/blob/tesla_act(power)
- ..()
+/obj/structure/blob/zap_act(power)
+ . = ..()
if(overmind)
if(overmind.blobstrain.tesla_reaction(src, power))
take_damage(power/400, BURN, "energy")
diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm
index b89b681539..090ef45d89 100644
--- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm
+++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm
@@ -492,7 +492,7 @@
/obj/structure/bloodsucker/candelabrum/process()
if(!lit)
return
- for(var/mob/living/carbon/human/H in get_actual_viewers(7, src))
+ for(var/mob/living/carbon/human/H in fov_viewers(7, src))
var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(AmBloodsucker(H) || T) //We dont want vassals or vampires affected by this
return
diff --git a/code/modules/antagonists/bloodsucker/powers/cloak.dm b/code/modules/antagonists/bloodsucker/powers/cloak.dm
index f8f2bb4e34..5383e8c1ac 100644
--- a/code/modules/antagonists/bloodsucker/powers/cloak.dm
+++ b/code/modules/antagonists/bloodsucker/powers/cloak.dm
@@ -19,7 +19,7 @@
if(!.)
return
// must have nobody around to see the cloak
- for(var/mob/living/M in get_actual_viewers(9, owner) - owner)
+ for(var/mob/living/M in fov_viewers(9, owner) - owner)
to_chat(owner, "You may only vanish into the shadows unseen.")
return FALSE
return TRUE
diff --git a/code/modules/antagonists/bloodsucker/powers/feed.dm b/code/modules/antagonists/bloodsucker/powers/feed.dm
index da53b5cc81..cbb9693fba 100644
--- a/code/modules/antagonists/bloodsucker/powers/feed.dm
+++ b/code/modules/antagonists/bloodsucker/powers/feed.dm
@@ -169,7 +169,7 @@
vision_distance = notice_range, ignored_mobs = target) // Only people who AREN'T the target will notice this action.
// Warn Feeder about Witnesses...
var/was_unnoticed = TRUE
- for(var/mob/living/M in get_actual_viewers(notice_range, owner) - owner - target)
+ for(var/mob/living/M in fov_viewers(notice_range, owner) - owner - target)
if(M.client && !M.silicon_privileges && !M.eye_blind && !M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
was_unnoticed = FALSE
break
diff --git a/code/modules/antagonists/bloodsucker/powers/go_home.dm b/code/modules/antagonists/bloodsucker/powers/go_home.dm
index 4892530d63..c46a7fce6c 100644
--- a/code/modules/antagonists/bloodsucker/powers/go_home.dm
+++ b/code/modules/antagonists/bloodsucker/powers/go_home.dm
@@ -64,7 +64,7 @@
var/turf/T = get_turf(user)
if(T && T.lighting_object && T.get_lumcount()>= 0.1)
// B) Check for Viewers
- for(var/mob/living/M in get_actual_viewers(world.view, get_turf(owner)) - owner)
+ for(var/mob/living/M in fov_viewers(world.view, get_turf(owner)) - owner)
if(M.client && !M.silicon_privileges && !M.eye_blind)
am_seen = TRUE
if (!M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
diff --git a/code/modules/antagonists/bloodsucker/powers/mesmerize.dm b/code/modules/antagonists/bloodsucker/powers/mesmerize.dm
index 04d3be439f..eea80d52f3 100644
--- a/code/modules/antagonists/bloodsucker/powers/mesmerize.dm
+++ b/code/modules/antagonists/bloodsucker/powers/mesmerize.dm
@@ -64,7 +64,7 @@
to_chat(owner, "Your victim's eyes are glazed over. They cannot perceive you.")
return FALSE
// Check: Target See Me? (behind wall)
- if(!(owner in target.visible_atoms()))
+ if(!(owner in target.fov_view()))
// Sub-Check: GET CLOSER
//if (!(owner in range(target_range, get_turf(target)))
// if (display_error)
@@ -117,8 +117,6 @@
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
// 5 second windup
addtimer(CALLBACK(src, .proc/apply_effects, L, target, power_time), 6 SECONDS)
- ADD_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
- ADD_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
/datum/action/bloodsucker/targeted/mesmerize/proc/apply_effects(aggressor, victim, power_time)
var/mob/living/carbon/target = victim
@@ -127,7 +125,6 @@
return
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time)
- REMOVE_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
target.face_atom(L)
target.Stun(power_time)
to_chat(L, "[target] is fixed in place by your hypnotic gaze.")
@@ -136,8 +133,7 @@
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
- REMOVE_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
- if(istype(L) && target.stat == CONSCIOUS && (target in L.visible_atoms(10))) // They Woke Up! (Notice if within view)
+ if(istype(L) && target.stat == CONSCIOUS && (target in L.fov_view(10))) // They Woke Up! (Notice if within view)
to_chat(L, "[target] has snapped out of their trance.")
diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
index 431416ede0..036ea37ada 100644
--- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
@@ -5,6 +5,7 @@
clockwork_desc = "A sigil of some purpose."
icon_state = "sigil"
layer = LOW_OBJ_LAYER
+ plane = ABOVE_WALL_PLANE
alpha = 50
resistance_flags = NONE
var/affects_servants = FALSE
diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm
new file mode 100644
index 0000000000..a681e9b38b
--- /dev/null
+++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm
@@ -0,0 +1,82 @@
+//Subtype of (riot) shield because of already implemented shieldbash stuff aswell as integrity and simillar things
+//ratvarian shield: A shield that absorbs energy from attacks and uses it to empower its bashes with remendous force. It is also quite resistant to damage, though less so against lasers and energy weaponry.
+
+/obj/item/shield/riot/ratvarian
+ name = "ratvarian shield"
+ icon_state = "ratvarian_shield" //Its icons are in the same place the normal shields are in
+ item_state = "ratvarian_shield"
+ desc = "A resilient shield made out of brass.. It feels warm to the touch."
+ var/clockwork_desc = "A powerful shield of ratvarian making. It absorbs blocked attacks to charge devastating bashes."
+ armor = list("melee" = 80, "bullet" = 70, "laser" = -10, "energy" = -20, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
+ shield_flags = SHIELD_FLAGS_DEFAULT
+ max_integrity = 300 //High integrity, extremely strong against melee / bullets, but still quite easy to destroy with lasers and energy
+ repair_material = /obj/item/stack/tile/brass
+ var/dam_absorbed = 0
+ var/bash_mult_steps = 30
+ var/max_bash_mult = 4
+
+/obj/item/shield/riot/ratvarian/examine(mob/user)
+ if((is_servant_of_ratvar(user) || isobserver(user)))
+ desc = clockwork_desc
+ desc +="\n The shield has absorbed [dam_absorbed] damage, multiplying the effectiveness of its bashes by [calc_bash_mult()]"
+ . = ..()
+ desc = initial(desc)
+
+obj/item/shield/riot/ratvarian/proc/calc_bash_mult()
+ var/bash_mult = 0
+ if(!dam_absorbed)
+ return 1
+ else
+ bash_mult += round(clamp(1 + (dam_absorbed / bash_mult_steps), 1, max_bash_mult), 0.1) //Multiplies the effect of bashes by up to [max_bash_mult], though never less than one
+ return bash_mult
+
+/obj/item/shield/riot/ratvarian/proc/calc_bash_absorb_use()
+ var/absorb_use = 0
+ absorb_use = max(0, round(dam_absorbed * (calc_bash_mult() / round(1 + (dam_absorbed / bash_mult_steps), 0.1)), 1)) //Calculates how much of the absorbed damage the bash would actually use, so its not wasted
+ return absorb_use
+
+/obj/item/shield/riot/ratvarian/on_shield_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!damage)
+ return ..()
+
+ if(!is_servant_of_ratvar(owner))
+ owner.visible_message("As [owner] blocks the attack with [src], [owner.p_they()] suddenly drops it, whincing in pain! ", "As you block the attack with [src], it heats up tremendously, forcing you to drop it from the pain alone! ")
+ owner.emote("scream")
+ playsound(src, 'sound/machines/fryer/deep_fryer_emerge.ogg', 50)
+ if(iscarbon(owner)) //Type safety for if a drone somehow got a shield (ratvar protect us)
+ var/mob/living/carbon/C = owner
+ var/obj/item/bodypart/part = C.get_holding_bodypart_of_item(src)
+ C.apply_damage((iscultist(C) ? damage * 2 : damage), BURN, (istype(part, /obj/item/bodypart/l_arm) ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM)) //Deals the damage to the holder instead of absorbing it instead + forcedrops. Doubled if a cultist of Nar'Sie.
+ else
+ owner.adjustFireLoss(iscultist(owner) ? damage * 2 : damage)
+ addtimer(CALLBACK(owner, /mob/living.proc/dropItemToGround, src, TRUE), 1)
+ else if(!is_servant_of_ratvar(attacker)) //No exploiting my snowflake mechanics
+ dam_absorbed += damage
+ playsound(owner, 'sound/machines/clockcult/steam_whoosh.ogg', 30)
+
+ if(damage <= 10) //The shield itself is hard to break, this DOES NOT modify the actual blocking-mechanic
+ damage = 0
+ else
+ damage -= 5
+ return ..()
+
+/obj/item/shield/riot/ratvarian/shatter(mob/living/carbon/human/owner)
+ playsound(owner, 'sound/magic/clockwork/anima_fragment_death.ogg', 50)
+ new /obj/item/clockwork/alloy_shards/large(get_turf(src))
+
+/obj/item/shield/riot/ratvarian/user_shieldbash(mob/living/user, atom/target, harmful)
+ if(!harmful || !is_servant_of_ratvar(user)) // No fun for non-clockies, but you can keep the normal bashes. Until you try to block with it.
+ shieldbash_knockback = initial(shieldbash_knockback)
+ shieldbash_brutedamage = initial(shieldbash_brutedamage) //Prevention for funky stuff that might happen otherwise
+ shieldbash_stamdmg = initial(shieldbash_stamdmg)
+ return ..()
+ var/actual_bash_mult = calc_bash_mult()
+ shieldbash_knockback = round(initial(shieldbash_knockback) * actual_bash_mult, 1) //Modifying the strength of the bash, done with initial() to prevent magic-number issues if the original shieldbash values are changed
+ shieldbash_brutedamage = round(initial(shieldbash_brutedamage) * actual_bash_mult, 1) //Where I think of it, better round this stuff because we don't need even more things that deal like 3.25 damage
+ shieldbash_stamdmg = round(initial(shieldbash_stamdmg) * actual_bash_mult, 1) //Like 20 brute and 60 stam + a fuckton of knockback at the moment (at maximum charge), seems mostly fine? I think?
+ . = ..()
+ if(.) //If this bash actually hit someone
+ if(actual_bash_mult > 1)
+ playsound(user, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
+ dam_absorbed -= calc_bash_absorb_use()
+ return
diff --git a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
index f43f2814d8..dd37f3727c 100644
--- a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
+++ b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
@@ -17,7 +17,8 @@
obj_damage = 40
melee_damage_lower = 12
melee_damage_upper = 12
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
weather_immunities = list("lava")
movement_type = FLYING
@@ -68,14 +69,16 @@
maxHealth = 300
melee_damage_upper = 25
melee_damage_lower = 25
- attacktext = "devastates"
+ attack_verb_continuous = "devastates"
+ attack_verb_simple = "devastate"
speed = -1
obj_damage = 100
max_shield_health = INFINITY
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
melee_damage_upper = 15
melee_damage_lower = 15
- attacktext = "carves"
+ attack_verb_continuous = "carves"
+ attack_verb_simple = "carve"
obj_damage = 50
max_shield_health = 4
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
index 130fc24583..c40168a986 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
@@ -100,6 +100,24 @@
quickbind = TRUE
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
+//Nezbere's shield: Creates a ratvarian shield which absorbs attacks, see ratvarian_shield.dm for details.
+/datum/clockwork_scripture/create_object/nezberes_shield
+ descname = "Shield with empowerable bashes"
+ name = "Nezbere's shield"
+ desc = "Creates a shield which generates charge from blocking damage, using it to empower its bashes tremendously. It is repaired with brass, and while very durable, extremely weak to lasers and, even more so, to energy weaponry."
+ invocations = list("Shield me...", "... from the coming dark!")
+ channel_time = 20
+ power_cost = 600 //Shouldn't be too spammable but not too hard to get either
+ whispered = TRUE
+ creator_message = "You form a ratvarian shield, which is capable of absorbing blocked attacks to empower its bashes."
+ object_path = /obj/item/shield/riot/ratvarian
+ usage_tip = "Bashes will only use charge when performed with intent to harm."
+ tier = SCRIPTURE_SCRIPT
+ space_allowed = TRUE
+ primary_component = VANGUARD_COGWHEEL
+ sort_priority = 5
+ quickbind = TRUE
+ quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes."
//Clockwork Armaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor.
/datum/clockwork_scripture/clockwork_armaments
@@ -113,7 +131,7 @@
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
tier = SCRIPTURE_SCRIPT
primary_component = VANGUARD_COGWHEEL
- sort_priority = 5
+ sort_priority = 6
important = TRUE
quickbind = TRUE
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
@@ -213,7 +231,7 @@
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
tier = SCRIPTURE_SCRIPT
primary_component = GEIS_CAPACITOR
- sort_priority = 6
+ sort_priority = 7
quickbind = TRUE
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm
index a730b52cc1..b6ed7dfe65 100644
--- a/code/modules/antagonists/clockcult/clockcult.dm
+++ b/code/modules/antagonists/clockcult/clockcult.dm
@@ -5,6 +5,7 @@
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
antag_moodlet = /datum/mood_event/cult
+ skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
var/datum/action/innate/hierophant/hierophant_network = new
threat = 3
var/datum/team/clockcult/clock_team
diff --git a/code/modules/antagonists/devil/imp/imp.dm b/code/modules/antagonists/devil/imp/imp.dm
index 1539bc384b..7a6850bfa1 100644
--- a/code/modules/antagonists/devil/imp/imp.dm
+++ b/code/modules/antagonists/devil/imp/imp.dm
@@ -7,9 +7,12 @@
desc = "A large, menacing creature covered in armored black scales."
speak_emote = list("cackles")
emote_hear = list("cackles","screeches")
- response_help = "thinks better of touching"
- response_disarm = "flails at"
- response_harm = "punches"
+ response_help_continuous = "thinks better of touching"
+ response_help_simple = "think better of touching"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punch"
icon = 'icons/mob/mob.dmi'
icon_state = "imp"
icon_living = "imp"
@@ -23,7 +26,8 @@
minbodytemp = 250 //Weak to cold
maxbodytemp = INFINITY
faction = list("hell")
- attacktext = "wildly tears into"
+ attack_verb_continuous = "wildly tears into"
+ attack_verb_simple = "wildly tear into"
maxHealth = 200
health = 200
healable = 0
diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm
index bda1fbabe6..1d773627c7 100644
--- a/code/modules/antagonists/ert/ert.dm
+++ b/code/modules/antagonists/ert/ert.dm
@@ -51,6 +51,7 @@
/datum/antagonist/ert/engineer
role = "Engineer"
outfit = /datum/outfit/ert/engineer
+ skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
/datum/antagonist/ert/engineer/amber
outfit = /datum/outfit/ert/engineer/alert
@@ -61,6 +62,7 @@
/datum/antagonist/ert/medic
role = "Medical Officer"
outfit = /datum/outfit/ert/medic
+ skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery)
/datum/antagonist/ert/medic/amber
outfit = /datum/outfit/ert/medic/alert
diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm
index ad2eb4792a..e91feda006 100644
--- a/code/modules/antagonists/morph/morph.dm
+++ b/code/modules/antagonists/morph/morph.dm
@@ -28,7 +28,8 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
vision_range = 1 // Only attack when target is close
wander = FALSE
- attacktext = "glomps"
+ attack_verb_continuous = "glomps"
+ attack_verb_simple = "glomp"
attack_sound = 'sound/effects/blobattack.ogg'
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index 2907a1c285..a11ecaa3df 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -451,9 +451,9 @@
return
qdel(src)
-/obj/machinery/nuclearbomb/tesla_act(power, tesla_flags)
+/obj/machinery/nuclearbomb/zap_act(power, zap_flags)
..()
- if(tesla_flags & TESLA_MACHINE_EXPLOSIVE)
+ if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
qdel(src)//like the singulo, tesla deletes it. stops it from exploding over and over
#define NUKERANGE 127
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index 7510ad6997..454cde6d72 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -5,6 +5,7 @@
job_rank = ROLE_OPERATIVE
antag_moodlet = /datum/mood_event/focused
threat = 10
+ skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index 5ee673dddc..e06e8691b3 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -31,16 +31,20 @@
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- response_help = "passes through"
- response_disarm = "swings through"
- response_harm = "punches through"
+ response_help_continuous = "passes through"
+ response_help_simple = "pass through"
+ response_disarm_continuous = "swings through"
+ response_disarm_simple = "swing through"
+ response_harm_continuous = "punches through"
+ response_harm_simple = "punch through"
unsuitable_atmos_damage = 0
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
harm_intent_damage = 0
- friendly = "touches"
+ friendly_verb_continuous = "touches"
+ friendly_verb_simple = "touch"
status_flags = 0
wander = FALSE
density = FALSE
diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm
index 5d409a7fb9..6b063559dc 100644
--- a/code/modules/antagonists/slaughter/slaughter.dm
+++ b/code/modules/antagonists/slaughter/slaughter.dm
@@ -6,9 +6,12 @@
desc = "A large, menacing creature covered in armored black scales."
speak_emote = list("gurgles")
emote_hear = list("wails","screeches")
- response_help = "thinks better of touching"
- response_disarm = "flails at"
- response_harm = "punches"
+ response_help_continuous = "thinks better of touching"
+ response_help_simple = "think better of touching"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punch"
icon = 'icons/mob/mob.dmi'
icon_state = "daemon"
icon_living = "daemon"
@@ -24,7 +27,8 @@
minbodytemp = 0
maxbodytemp = INFINITY
faction = list("slaughter")
- attacktext = "wildly tears into"
+ attack_verb_continuous = "wildly tears into"
+ attack_verb_simple = "wildly tear into"
maxHealth = 200
health = 200
healable = 0
@@ -116,8 +120,10 @@
desc = "A large, adorable creature covered in armor with pink bows."
speak_emote = list("giggles","titters","chuckles")
emote_hear = list("guffaws","laughs")
- response_help = "hugs"
- attacktext = "wildly tickles"
+ response_help_continuous = "hugs"
+ response_help_simple = "hug"
+ attack_verb_continuous = "wildly tickles"
+ attack_verb_simple = "wildly tickle"
attack_sound = 'sound/items/bikehorn.ogg'
feast_sound = 'sound/spookoween/scary_horn2.ogg'
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index c1f493ac52..d0e36394ab 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -84,9 +84,11 @@
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD)
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
- attacktext = "shocks"
+ attack_verb_continuous = "shocks"
+ attack_verb_simple = "shock"
attack_sound = 'sound/effects/empulse.ogg'
- friendly = "pinches"
+ friendly_verb_continuous = "pinches"
+ friendly_verb_simple = "pinch"
speed = 0
faction = list("swarmer")
AIStatus = AI_OFF
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 1d30cdbf77..4422f2f174 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -4,6 +4,7 @@
antagpanel_category = "Traitor"
job_rank = ROLE_TRAITOR
antag_moodlet = /datum/mood_event/focused
+ skill_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
var/special_role = ROLE_TRAITOR
var/employer = "The Syndicate"
var/give_objectives = TRUE
diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm
index 68ed0d736e..aa2ec402d8 100644
--- a/code/modules/antagonists/wizard/equipment/spellbook.dm
+++ b/code/modules/antagonists/wizard/equipment/spellbook.dm
@@ -226,7 +226,11 @@
/datum/spellbook_entry/lightningbolt/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success
. = ..()
- user.flags_1 |= TESLA_IGNORE_1
+ ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "lightning_bolt_spell")
+
+/datum/spellbook_entry/lightningbolt/Refund(mob/living/carbon/human/user, obj/item/spellbook/book)
+ . = ..()
+ REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "lightning_bolt_spell")
/datum/spellbook_entry/infinite_guns
name = "Lesser Summon Guns"
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 8f5ab7dd5e..97389848ba 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -17,6 +17,7 @@
active_power_usage = 0
power_channel = ENVIRON
layer = GAS_PIPE_HIDDEN_LAYER //under wires
+ plane = ABOVE_WALL_PLANE
resistance_flags = FIRE_PROOF
max_integrity = 200
obj_flags = CAN_BE_HIT | ON_BLUEPRINTS
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index c164dc5ae3..6b685d4bc1 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -7,6 +7,7 @@
name = "circulator/heat exchanger"
desc = "A gas circulator pump and heat exchanger."
icon_state = "circ-off-0"
+ plane = GAME_PLANE
var/active = FALSE
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index a45728d51f..c229a4ba27 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -32,7 +32,7 @@
var/turf/T = loc
if(level == 2 || (istype(T) && !T.intact))
showpipe = TRUE
- plane = GAME_PLANE
+ plane = ABOVE_WALL_PLANE
else
showpipe = FALSE
plane = FLOOR_PLANE
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 9b7183092d..4f26a2f772 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -6,6 +6,7 @@
max_integrity = 350
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 30, "acid" = 30)
layer = ABOVE_WINDOW_LAYER
+ plane = GAME_PLANE
state_open = FALSE
circuit = /obj/item/circuitboard/machine/cryo_tube
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
@@ -15,8 +16,8 @@
var/volume = 100
var/efficiency = 1
- var/sleep_factor = 0.00125
- var/unconscious_factor = 0.001
+ var/base_knockout = 30 SECONDS
+ var/knockout_factor = 1
var/heat_capacity = 20000
var/conduction_coefficient = 0.3
@@ -53,10 +54,9 @@
var/C
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
C += M.rating
-
+ // 2 bins total, so C ranges from 2 to 8.
efficiency = initial(efficiency) * C
- sleep_factor = initial(sleep_factor) * C
- unconscious_factor = initial(unconscious_factor) * C
+ knockout_factor = initial(knockout_factor) / max(1, (C * 0.33))
heat_capacity = initial(heat_capacity) / C
conduction_coefficient = initial(conduction_coefficient) * C
@@ -188,8 +188,10 @@
if(air1.gases.len)
if(mob_occupant.bodytemperature < T0C) // Sleepytime. Why? More cryo magic.
- mob_occupant.Sleeping((mob_occupant.bodytemperature * sleep_factor) * 2000)
- mob_occupant.Unconscious((mob_occupant.bodytemperature * unconscious_factor) * 2000)
+ // temperature factor goes from 1 to about 2.5
+ var/amount = max(1, (4 * log(T0C - mob_occupant.bodytemperature)) - 20) * knockout_factor * base_knockout
+ mob_occupant.Sleeping(amount)
+ mob_occupant.Unconscious(amount)
if(beaker)
if(reagent_transfer == 0) // Magically transfer reagents. Because cryo magic.
beaker.reagents.trans_to(occupant, 1, efficiency * 0.25) // Transfer reagents.
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
index c1bd59f49b..79ff24e8b7 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
@@ -7,6 +7,7 @@
max_integrity = 800
density = TRUE
layer = ABOVE_WINDOW_LAYER
+ plane = GAME_PLANE
pipe_flags = PIPING_ONE_PER_TURF
var/volume = 10000 //in liters
var/gas_type = 0
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index dddfdf08c1..7af3e57bc7 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -9,6 +9,7 @@
max_integrity = 300
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 30)
layer = OBJ_LAYER
+ plane = GAME_PLANE
circuit = /obj/item/circuitboard/machine/thermomachine
ui_x = 300
ui_y = 230
diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm
index d1d895ca69..6968a5ccd8 100644
--- a/code/modules/cargo/console.dm
+++ b/code/modules/cargo/console.dm
@@ -119,6 +119,7 @@
var/list/data = list()
data["requestonly"] = requestonly
data["supplies"] = list()
+ data["emagged"] = obj_flags & EMAGGED
for(var/pack in SSshuttle.supply_packs)
var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
if(!data["supplies"][P.group])
@@ -133,7 +134,8 @@
"cost" = P.cost,
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
- "access" = P.access
+ "access" = P.access,
+ "can_private_buy" = P.can_private_buy
))
return data
@@ -195,9 +197,10 @@
rank = "Silicon"
var/datum/bank_account/account
- if(self_paid && ishuman(usr))
- var/mob/living/carbon/human/H = usr
- var/obj/item/card/id/id_card = H.get_idcard(TRUE)
+ if(self_paid)
+ if(!pack.can_private_buy && !(obj_flags & EMAGGED))
+ return
+ var/obj/item/card/id/id_card = usr.get_idcard(TRUE)
if(!istype(id_card))
say("No ID card detected.")
return
diff --git a/code/modules/cargo/exports/parts.dm b/code/modules/cargo/exports/parts.dm
index 660d79cae4..da3c0cf31d 100644
--- a/code/modules/cargo/exports/parts.dm
+++ b/code/modules/cargo/exports/parts.dm
@@ -110,7 +110,7 @@
include_subtypes = FALSE
/datum/export/glasswork_lens
- cost = 1800
+ cost = 1600
unit_name = "small glass lens"
export_types = list(/obj/item/glasswork/glass_base/lens)
@@ -133,13 +133,13 @@
include_subtypes = FALSE
/datum/export/glasswork_teaplate
- cost = 1200
+ cost = 1000
unit_name = "tea gear"
export_types = list(/obj/item/tea_plate)
include_subtypes = FALSE
/datum/export/glasswork_teacup
- cost = 1800
+ cost = 1600
unit_name = "tea gear"
export_types = list(/obj/item/tea_cup)
include_subtypes = FALSE
diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm
index be0d2d6bee..120bfbe5e4 100644
--- a/code/modules/cargo/exports/sheets.dm
+++ b/code/modules/cargo/exports/sheets.dm
@@ -120,12 +120,6 @@
message = "of cloth"
export_types = list(/obj/item/stack/sheet/cloth)
-/datum/export/stack/silk
- cost = 200 //The new plasma
- unit_name = "sheets"
- message = "of silk"
- export_types = list(/obj/item/stack/sheet/silk)
-
/datum/export/stack/duracloth
cost = 40
unit_name = "sheets"
diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm
index 1b4ebd6c1a..be2db06346 100644
--- a/code/modules/cargo/gondolapod.dm
+++ b/code/modules/cargo/gondolapod.dm
@@ -2,9 +2,12 @@
name = "gondola"
real_name = "gondola"
desc = "The silent walker. This one seems to be part of a delivery agency."
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "bops"
+ response_disarm_simple = "bop"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
faction = list("gondola")
turns_per_move = 10
icon = 'icons/mob/gondolapod.dmi'
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 96557d58ef..f82e16ad5c 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -15,6 +15,7 @@
var/special_enabled = FALSE
var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console
var/admin_spawned = FALSE //Can only an admin spawn this crate?
+ var/can_private_buy = TRUE //Can it be purchased privately by each crewmember?
/datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account)
var/obj/structure/closet/crate/C
diff --git a/code/modules/cargo/packs/armory.dm b/code/modules/cargo/packs/armory.dm
index bcfbc83001..3a3357cc42 100644
--- a/code/modules/cargo/packs/armory.dm
+++ b/code/modules/cargo/packs/armory.dm
@@ -10,6 +10,7 @@
group = "Armory"
access = ACCESS_ARMORY
crate_type = /obj/structure/closet/crate/secure/weapon
+ can_private_buy = FALSE
/datum/supply_pack/security/armory/bulletarmor
name = "Bulletproof Armor Crate"
diff --git a/code/modules/cargo/packs/engine.dm b/code/modules/cargo/packs/engine.dm
index 89775c07ee..499881a110 100644
--- a/code/modules/cargo/packs/engine.dm
+++ b/code/modules/cargo/packs/engine.dm
@@ -148,7 +148,7 @@
crate_name = "supermatter shard crate"
crate_type = /obj/structure/closet/crate/secure/engineering
dangerous = TRUE
-
+
/datum/supply_pack/engine/tesla_coils
name = "Tesla Coil Crate"
desc = "Whether it's high-voltage executions, creating research points, or just plain old power generation: This pack of four Tesla coils can do it all!"
diff --git a/code/modules/cargo/packs/materials.dm b/code/modules/cargo/packs/materials.dm
index 1ce3a6b084..771f7ce222 100644
--- a/code/modules/cargo/packs/materials.dm
+++ b/code/modules/cargo/packs/materials.dm
@@ -81,32 +81,6 @@
contains = list(/obj/item/stack/sheet/mineral/wood/fifty)
crate_name = "wood planks crate"
-/datum/supply_pack/materials/rawcotton
- name = "Raw Cotton Crate"
- desc = "Plushies have been on the down in the market, and now due to a flood of raw cotton the price of it is so cheap, its a steal! Contains 40 raw cotton sheets."
- cost = 800 // 100 net cost, 20 x 20 = 400. 300 profit if turned into cloth sheets or more if turned to silk then 10 x 200 = 2000
- contains = list(/obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/ten
- )
- crate_name = "cotton crate"
- crate_type = /obj/structure/closet/crate/hydroponics
-
-/datum/supply_pack/materials/rawcottonbulk
- name = "Raw Cotton Crate (Bulk)"
- desc = "We have so much of this stuff we need to get rid of it in -bulk- now. This crate contains 240 raw cotton sheets."
- cost = 1300 // 600 net cost 20 x 120 = 2400 profit if turned into cloth sheets or if turned into silk 200 x 60 = 12000
- contains = list(/obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- /obj/item/stack/sheet/cotton/thirty,
- )
- crate_name = "bulk cotton crate"
- crate_type = /obj/structure/closet/crate/hydroponics
-
/datum/supply_pack/materials/rcdammo
name = "Spare RCD ammo"
desc = "This crate contains sixteen RCD compressed matter packs, to help with any holes or projects people might be working on."
diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm
index 5d02bbe60f..ab188f235b 100644
--- a/code/modules/cargo/packs/medical.dm
+++ b/code/modules/cargo/packs/medical.dm
@@ -252,6 +252,7 @@
crate_name = "virus crate"
crate_type = /obj/structure/closet/crate/secure/plasma
dangerous = TRUE
+ can_private_buy = FALSE
/datum/supply_pack/medical/anitvirus
name = "Virus Containment Crate"
@@ -271,4 +272,4 @@
/obj/item/storage/box/syringes,
/obj/item/storage/box/beakers)
crate_name = "virus containment unit crate"
- crate_type = /obj/structure/closet/crate/secure/plasma
\ No newline at end of file
+ crate_type = /obj/structure/closet/crate/secure/plasma
diff --git a/code/modules/cargo/packs/organic.dm b/code/modules/cargo/packs/organic.dm
index 22cb518926..249faae33d 100644
--- a/code/modules/cargo/packs/organic.dm
+++ b/code/modules/cargo/packs/organic.dm
@@ -370,22 +370,6 @@
/////////////////////////////////// Misc /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-/datum/supply_pack/organic/hunting
- name = "Hunting Gear"
- desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. "
- cost = 3500
- contraband = TRUE
- contains = list(/obj/item/clothing/head/flatcap,
- /obj/item/clothing/suit/hooded/wintercoat/captain,
- /obj/item/reagent_containers/food/drinks/bottle/cognac,
- /obj/item/storage/fancy/cigarettes/cigars/havana,
- /obj/item/clothing/gloves/color/white,
- /obj/item/clothing/under/rank/civilian/curator,
- /obj/item/gun/ballistic/shotgun/lethal)
- access = ACCESS_ARMORY
- crate_name = "sporting crate"
- crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
-
/datum/supply_pack/organic/party
name = "Party Equipment"
desc = "Celebrate both life and death on the station with Nanotrasen's Party Essentials(tm)! Contains seven colored glowsticks, four beers, two ales, a drinking shaker, and a bottle of patron & goldschlager!"
diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm
index 51bb2b728f..fd6fee362d 100644
--- a/code/modules/cargo/packs/science.dm
+++ b/code/modules/cargo/packs/science.dm
@@ -17,6 +17,7 @@
cost = 2500
contains = list (/obj/item/reagent_containers/food/snacks/cube/ape)
crate_name = "ape cube crate"
+ can_private_buy = FALSE
/datum/supply_pack/science/beakers
name = "Chemistry Beakers Crate"
diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm
index d134d7bab8..a48874e974 100644
--- a/code/modules/cargo/packs/security.dm
+++ b/code/modules/cargo/packs/security.dm
@@ -10,6 +10,7 @@
group = "Security"
access = ACCESS_SECURITY
crate_type = /obj/structure/closet/crate/secure/gear
+ can_private_buy = FALSE
/datum/supply_pack/security/ammo
name = "Ammo Crate - General Purpose"
@@ -57,6 +58,7 @@
/obj/item/toy/crayon/white,
/obj/item/clothing/head/fedora/det_hat)
crate_name = "forensics crate"
+ can_private_buy = TRUE
/datum/supply_pack/security/helmets
name = "Helmets Crate"
@@ -134,6 +136,7 @@
/obj/item/grenade/barrier)
cost = 2000
crate_name = "security barriers crate"
+ can_private_buy = TRUE
/datum/supply_pack/security/securityclothes
name = "Security Clothing Crate"
@@ -152,6 +155,7 @@
/obj/item/clothing/suit/armor/hos/navyblue,
/obj/item/clothing/head/beret/sec/navyhos)
crate_name = "security clothing crate"
+ can_private_buy = TRUE
/datum/supply_pack/security/supplies
name = "Security Supplies Crate"
@@ -179,6 +183,7 @@
contains = list(/obj/item/clothing/head/helmet/justice,
/obj/item/clothing/mask/gas/sechailer)
crate_name = "security clothing crate"
+ can_private_buy = TRUE
/datum/supply_pack/security/baton
name = "Stun Batons Crate"
@@ -207,3 +212,19 @@
/obj/item/storage/box/wall_flash,
/obj/item/storage/box/wall_flash)
crate_name = "wall-mounted flash crate"
+
+/datum/supply_pack/security/hunting
+ name = "Hunting Gear"
+ desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. "
+ cost = 3500
+ contraband = TRUE
+ contains = list(/obj/item/clothing/head/flatcap,
+ /obj/item/clothing/suit/hooded/wintercoat/captain,
+ /obj/item/reagent_containers/food/drinks/bottle/cognac,
+ /obj/item/storage/fancy/cigarettes/cigars/havana,
+ /obj/item/clothing/gloves/color/white,
+ /obj/item/clothing/under/rank/civilian/curator,
+ /obj/item/gun/ballistic/shotgun/lethal)
+ access = ACCESS_ARMORY
+ crate_name = "sporting crate"
+ crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
diff --git a/code/modules/cargo/packs/vending.dm b/code/modules/cargo/packs/vending.dm
index 344d19f6c9..810cfd8d6e 100644
--- a/code/modules/cargo/packs/vending.dm
+++ b/code/modules/cargo/packs/vending.dm
@@ -99,6 +99,7 @@
contains = list(/obj/machinery/vending/security)
crate_name = "SecTech supply crate"
crate_type = /obj/structure/closet/crate/secure/gear
+ can_private_buy = FALSE
/datum/supply_pack/vending/snack
name = "Snack Supply Crate"
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index f865cfddbb..47255d9535 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -80,10 +80,24 @@
var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
+ /// Keys currently held
+ var/list/keys_held = list()
+ /// These next two vars are to apply movement for keypresses and releases made while move delayed.
+ /// Because discarding that input makes the game less responsive.
+ /// On next move, add this dir to the move that would otherwise be done
+ var/next_move_dir_add
+ /// On next move, subtract this dir from the move that would otherwise be done
+ var/next_move_dir_sub
+ /// Amount of keydowns in the last keysend checking interval
var/client_keysend_amount = 0
+ /// World tick time where client_keysend_amount will reset
var/next_keysend_reset = 0
+ /// World tick time where keysend_tripped will reset back to false
var/next_keysend_trip_reset = 0
+ /// When set to true, user will be autokicked if they trip the keysends in a second limit again
var/keysend_tripped = FALSE
+ /// custom movement keys for this client
+ var/list/movement_keys = list()
/// Messages currently seen by this client
var/list/seen_messages
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index ab1db47db6..ce7ef441c4 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -265,6 +265,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
else
prefs = new /datum/preferences(src)
GLOB.preferences_datums[ckey] = prefs
+ if(SSinput.initialized)
+ set_macros()
+ update_movement_keys(prefs)
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
@@ -328,9 +331,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
qdel(src)
return
- if(SSinput.initialized)
- set_macros()
-
chatOutput.start() // Starts the chat
if(alert_mob_dupe_login)
@@ -789,7 +789,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
log_game("[key_name(src)] is using the middle click aimbot exploit")
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] is using the middle click aimbot exploit")
add_system_note("aimbot", "Is using the middle click aimbot exploit")
-
+ log_click(object, location, control, params, src, "lockout (spam - minute ab c [ab] s [middragtime])")
+ else
+ log_click(object, location, control, params, src, "lockout (spam - minute)")
log_game("[key_name(src)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
to_chat(src, "[msg]")
@@ -809,8 +811,12 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
return
if(ab) //Citadel edit, things with stuff.
+ log_click(object, location, control, params, src, "dropped (ab c [ab] s [middragtime])")
return
+ if(prefs.log_clicks)
+ log_click(object, location, control, params, src)
+
if (prefs.hotkeys)
// If hotkey mode is enabled, then clicking the map will automatically
// unfocus the text bar. This removes the red color from the text bar
@@ -892,6 +898,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
y = clamp(y+change, min,max)
change_view("[x]x[y]")
+/client/proc/update_movement_keys(datum/preferences/direct_prefs)
+ var/datum/preferences/D = prefs || direct_prefs
+ if(!D?.key_bindings)
+ return
+ movement_keys = list()
+ for(var/key in D.key_bindings)
+ for(var/kb_name in D.key_bindings[key])
+ switch(kb_name)
+ if("North")
+ movement_keys[key] = NORTH
+ if("East")
+ movement_keys[key] = EAST
+ if("West")
+ movement_keys[key] = WEST
+ if("South")
+ movement_keys[key] = SOUTH
+
/client/proc/change_view(new_size)
if (isnull(new_size))
CRASH("change_view called without argument.")
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 100dbc66ae..040b56f124 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1,11 +1,6 @@
- /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
- | THIS FILE CONTAINS HOOKS FOR FOR |
- | CHANGES SPECIFIC TO CITADEL. IF |
- | YOU'RE FIXING A MERGE CONFLICT |
- | HERE, PLEASE ASK FOR REVIEW FROM |
- | ANOTHER MAINTAINER TO ENSURE YOU |
- | DON'T INTRODUCE REGRESSIONS. |
- \* */
+#define DEFAULT_SLOT_AMT 2
+#define HANDS_SLOT_AMT 2
+#define BACKPACK_SLOT_AMT 4
GLOBAL_LIST_EMPTY(preferences_datums)
@@ -20,6 +15,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/muted = 0
var/last_ip
var/last_id
+ var/log_clicks = FALSE
var/icon/custom_holoform_icon
var/list/cached_holoform_icons
@@ -51,6 +47,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/chat_on_map = TRUE
var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH
var/see_chat_non_mob = TRUE
+
+ /// Custom Keybindings
+ var/list/key_bindings = list()
+
+
var/tgui_fancy = TRUE
var/tgui_lock = TRUE
var/windowflashing = TRUE
@@ -189,9 +190,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/uplink_spawn_loc = UPLINK_PDA
- var/sprint_spacebar = FALSE
- var/sprint_toggle = FALSE
-
var/hud_toggle_flash = TRUE
var/hud_toggle_color = "#ffffff"
@@ -204,6 +202,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/vore_flags = 0
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
+ var/toggleeatingnoise = TRUE
+ var/toggledigestionnoise = TRUE
+ var/hound_sleeper = TRUE
+ var/cit_toggles = TOGGLES_CITADEL
//backgrounds
var/mutable_appearance/character_background
@@ -214,6 +216,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/no_tetris_storage = FALSE
+ ///loadout stuff
+ var/gear_points = 10
+ var/list/gear_categories
+ var/list/chosen_gear = list()
+ var/gear_tab
+
+ var/screenshake = 100
+ var/damagescreenshake = 2
+ var/arousable = TRUE
+ var/widescreenpref = TRUE
+ var/autostand = TRUE
+ var/auto_ooc = FALSE
+
/datum/preferences/New(client/C)
parent = C
@@ -233,6 +248,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return
//we couldn't load character data so just randomize the character appearance + name
random_character() //let's create a random character then - rather than a fat, bald and naked man.
+ key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys
+ C?.update_movement_keys(src)
real_name = pref_species.random_name(gender,1)
if(!loaded_preferences_successfully)
save_preferences()
@@ -254,6 +271,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Loadout"
dat += "Game Preferences"
dat += "Content Preferences"
+ dat += "Keybindings"
if(!path)
dat += "