diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm
index d01e4f8da1..37a89ba2ff 100644
--- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm
+++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm
@@ -18,9 +18,7 @@
/obj/item/mining_scanner,
/obj/item/flashlight/lantern,
/obj/item/card/id/mining,
-/obj/item/gps/mining{
- tracking = 0
- },
+/obj/item/gps/mining,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
"d" = (
@@ -34,9 +32,7 @@
/obj/item/mining_scanner,
/obj/item/flashlight/lantern,
/obj/item/card/id/mining,
-/obj/item/gps/mining{
- tracking = 0
- },
+/obj/item/gps/mining,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
"e" = (
@@ -156,9 +152,7 @@
"x" = (
/obj/structure/table/wood,
/obj/machinery/reagentgrinder,
-/obj/item/gps/mining{
- tracking = 0
- },
+/obj/item/gps/mining,
/turf/open/floor/mineral/titanium/purple,
/area/ruin/powered/golem_ship)
"z" = (
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
index 6feb378515..eab08815f3 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
@@ -227,7 +227,7 @@
/area/ruin/unpowered/xenonest)
"ba" = (
/obj/structure/stone_tile/slab,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bb" = (
/obj/structure/stone_tile/cracked{
@@ -241,7 +241,7 @@
dir = 8
},
/obj/item/flashlight/lantern,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bc" = (
/obj/structure/stone_tile/block,
@@ -251,7 +251,7 @@
/obj/structure/stone_tile{
dir = 4
},
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bd" = (
/obj/structure/stone_tile/block,
@@ -262,7 +262,7 @@
dir = 1
},
/obj/effect/decal/cleanable/blood/xeno,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"be" = (
/obj/structure/stone_tile/block,
@@ -272,7 +272,7 @@
/obj/structure/stone_tile{
dir = 1
},
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bf" = (
/obj/structure/stone_tile,
@@ -286,7 +286,7 @@
dir = 4
},
/obj/item/flashlight/lantern,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bg" = (
/obj/structure/alien/weeds,
@@ -303,7 +303,7 @@
/obj/structure/stone_tile{
dir = 8
},
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bi" = (
/obj/structure/alien/weeds,
@@ -336,11 +336,11 @@
dir = 1
},
/obj/structure/stone_tile,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bm" = (
/obj/structure/stone_tile/slab/cracked,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bn" = (
/obj/structure/stone_tile/block{
@@ -352,7 +352,7 @@
/obj/structure/stone_tile{
dir = 4
},
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bo" = (
/obj/structure/stone_tile/surrounding_tile{
@@ -383,7 +383,7 @@
dir = 1
},
/obj/effect/decal/cleanable/blood/xeno,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bs" = (
/obj/structure/stone_tile/block{
@@ -416,7 +416,7 @@
dir = 1
},
/obj/structure/stone_tile/cracked,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bw" = (
/obj/structure/stone_tile/cracked{
@@ -430,7 +430,7 @@
dir = 8
},
/obj/item/flashlight/lantern,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bx" = (
/obj/structure/stone_tile/block{
@@ -441,7 +441,7 @@
dir = 8
},
/obj/effect/decal/cleanable/blood/xeno,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"by" = (
/obj/structure/stone_tile/block{
@@ -451,7 +451,7 @@
/obj/structure/stone_tile/cracked{
dir = 8
},
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bz" = (
/obj/structure/stone_tile/block/cracked{
@@ -461,7 +461,7 @@
/obj/structure/stone_tile{
dir = 8
},
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bA" = (
/obj/structure/stone_tile/cracked{
@@ -475,7 +475,7 @@
},
/obj/structure/stone_tile,
/obj/item/flashlight/lantern,
-/turf/open/indestructible/boss/air,
+/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bB" = (
/obj/structure/alien/weeds,
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_wizard.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_wizard.dmm
index 05155ee2a8..88b906b467 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_wizard.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_wizard.dmm
@@ -90,11 +90,11 @@
/obj/structure/stone_tile/surrounding_tile{
dir = 8
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"l" = (
/obj/structure/stone_tile/block/cracked,
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"m" = (
/obj/structure/stone_tile/surrounding_tile/cracked,
@@ -105,7 +105,7 @@
/obj/structure/stone_tile/surrounding_tile{
dir = 8
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"n" = (
/obj/structure/stone_tile/block/cracked{
@@ -136,14 +136,14 @@
},
/obj/structure/table/bronze,
/obj/item/disk/design_disk/adv/knight_gear,
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"q" = (
/obj/structure/table/bronze,
/obj/item/stack/sheet/mineral/runite{
amount = 5
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"r" = (
/obj/structure/stone_tile/block{
@@ -153,7 +153,7 @@
/obj/item/stack/sheet/mineral/runite{
amount = 5
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"s" = (
/obj/structure/stone_tile/block{
@@ -186,13 +186,13 @@
/obj/structure/stone_tile/surrounding_tile{
dir = 1
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"v" = (
/obj/structure/stone_tile/block{
dir = 1
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"w" = (
/obj/structure/stone_tile/surrounding_tile/cracked{
@@ -205,7 +205,7 @@
/obj/structure/stone_tile/surrounding_tile{
dir = 4
},
-/turf/open/indestructible/necropolis,
+/turf/open/indestructible/necropolis/air,
/area/lavaland/surface/outdoors)
"x" = (
/obj/structure/stone_tile/block{
diff --git a/_maps/RandomRuins/SpaceRuins/arcade.dmm b/_maps/RandomRuins/SpaceRuins/arcade.dmm
index 74bdc9a7b8..c68d3b224e 100644
--- a/_maps/RandomRuins/SpaceRuins/arcade.dmm
+++ b/_maps/RandomRuins/SpaceRuins/arcade.dmm
@@ -3,7 +3,7 @@
/turf/template_noop,
/area/template_noop)
"b" = (
-/turf/open/floor/plating/asteroid,
+/turf/open/floor/plating/asteroid/airless,
/area/ruin/powered)
"c" = (
/turf/closed/mineral/random/high_chance,
@@ -135,7 +135,7 @@
/area/ruin/powered)
"F" = (
/obj/structure/closet/crate/trashcart,
-/turf/open/floor/plating/asteroid,
+/turf/open/floor/plating/asteroid/airless,
/area/ruin/powered)
"G" = (
/obj/structure/chair/sofa/right,
diff --git a/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm b/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm
index e23beb3407..2a25a3b6e7 100644
--- a/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm
+++ b/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm
@@ -3,7 +3,7 @@
/turf/template_noop,
/area/template_noop)
"b" = (
-/turf/open/floor/plating/asteroid,
+/turf/open/floor/plating/asteroid/airless,
/area/ruin/powered)
"c" = (
/turf/closed/mineral/random/high_chance,
@@ -176,8 +176,8 @@
/obj/structure/table,
/obj/effect/decal/cleanable/dirt,
/obj/item/autosurgeon{
- name = "rusted autosurgeon";
desc = "A device that automatically inserts an implant or organ into the user without the hassle of extensive surgery. It has a slot to insert an organ of implant. But this rusted version looks like it could only manage one implant....";
+ name = "rusted autosurgeon";
uses = 1
},
/turf/open/floor/plasteel,
@@ -205,7 +205,7 @@
/obj/machinery/atmospherics/components/unary/outlet_injector/on/layer1{
dir = 4
},
-/turf/open/floor/plating/asteroid,
+/turf/open/floor/plating/asteroid/airless,
/area/ruin/powered)
"K" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
diff --git a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm
index b23f24b0e9..49646fbd71 100644
--- a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm
+++ b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm
@@ -151,6 +151,7 @@
id_tag = "syndie_listeningpost_external";
req_access_txt = "150"
},
+/obj/structure/fans/tiny,
/turf/open/floor/plating,
/area/ruin/space/has_grav/listeningstation)
"aq" = (
diff --git a/_maps/RandomRuins/SpaceRuins/spacehermit.dmm b/_maps/RandomRuins/SpaceRuins/spacehermit.dmm
index 791aac277d..c95e0c7539 100644
--- a/_maps/RandomRuins/SpaceRuins/spacehermit.dmm
+++ b/_maps/RandomRuins/SpaceRuins/spacehermit.dmm
@@ -5,9 +5,6 @@
"ab" = (
/turf/closed/mineral/random/low_chance,
/area/ruin/unpowered)
-"ac" = (
-/turf/open/floor/plating/asteroid,
-/area/ruin/unpowered)
"ad" = (
/obj/machinery/hydroponics/soil,
/turf/open/floor/plating/asteroid,
@@ -327,9 +324,6 @@
/obj/item/flashlight/lamp/bananalamp,
/turf/open/floor/plating/asteroid,
/area/ruin/powered)
-"bt" = (
-/turf/closed/mineral/random/low_chance/earth_like,
-/area/ruin/unpowered)
"bC" = (
/obj/item/pickaxe/titanium,
/turf/open/floor/plating/asteroid,
@@ -396,7 +390,7 @@ aa
aa
aa
aa
-ac
+aA
aO
aA
aA
@@ -2648,7 +2642,7 @@ aa
aa
aa
aa
-ac
+aA
aa
aa
aa
@@ -2699,9 +2693,9 @@ aa
aa
aa
aa
-ac
+aA
ab
-ac
+aA
aa
aa
"}
@@ -2855,9 +2849,9 @@ aa
aa
aa
aa
-ac
+aA
ab
-ac
+aA
aa
aa
"}
@@ -2907,7 +2901,7 @@ aa
aa
aa
aa
-ac
+aA
aa
aa
aa
@@ -2959,7 +2953,7 @@ aa
aa
aa
aa
-bt
+ab
aa
aa
aa
diff --git a/_maps/RandomRuins/SpaceRuinsStation/roid6.dmm b/_maps/RandomRuins/SpaceRuinsStation/roid6.dmm
index 56967b0c37..1bc497d4f9 100644
--- a/_maps/RandomRuins/SpaceRuinsStation/roid6.dmm
+++ b/_maps/RandomRuins/SpaceRuinsStation/roid6.dmm
@@ -80,7 +80,7 @@
/obj/item/shard{
icon_state = "medium"
},
-/turf/open/floor/plating/airless{
+/turf/open/floor/plating{
icon_state = "platingdmg2"
},
/area/ruin/space/has_grav)
diff --git a/_maps/RandomZLevels/VR/murderdome.dmm b/_maps/RandomZLevels/VR/murderdome.dmm
index 740f9fd09f..5b5cbbfcfe 100644
--- a/_maps/RandomZLevels/VR/murderdome.dmm
+++ b/_maps/RandomZLevels/VR/murderdome.dmm
@@ -232,7 +232,9 @@
/area/awaymission/vr/murderdome)
"H" = (
/obj/machinery/telecomms/allinone,
-/turf/open/indestructible,
+/turf/open/indestructible{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/awaymission/vr/murderdome)
"R" = (
/obj/effect/spawner/structure/window/reinforced/indestructable,
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index d91dd5b7c8..a77fcf1bd5 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -4879,6 +4879,10 @@
dir = 4
},
/obj/machinery/holopad,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "hopqueue";
+ name = "HoP Queue Shutters"
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"aiW" = (
@@ -5103,7 +5107,7 @@
/area/security/main)
"ajv" = (
/obj/machinery/computer/med_data{
- dir = 3
+ dir = 4
},
/obj/structure/sign/poster/official/medical_green_cross{
pixel_x = -32
@@ -13347,7 +13351,6 @@
pixel_y = 32
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/machinery/button/door{
@@ -14233,7 +14236,6 @@
pixel_y = 32
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/machinery/button/door{
@@ -21718,7 +21720,6 @@
pixel_y = 32
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/machinery/button/door{
@@ -30891,7 +30892,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"bvH" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
@@ -53437,6 +53438,7 @@
"dfh" = (
/obj/machinery/power/apc{
areastring = "/area/science/circuit";
+ dir = 4;
name = "Circuitry Lab APC";
pixel_x = 30
},
@@ -53681,9 +53683,6 @@
},
/turf/open/floor/mineral/titanium/blue,
/area/crew_quarters/toilet)
-"dVU" = (
-/turf/open/floor/plating,
-/area/space/nearstation)
"dXq" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
@@ -53736,7 +53735,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 6
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"egt" = (
/obj/effect/turf_decal/tile/bar,
@@ -54365,7 +54364,7 @@
"fIs" = (
/obj/structure/grille,
/obj/structure/lattice,
-/turf/open/floor/plating,
+/turf/open/space/basic,
/area/space/nearstation)
"fJY" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
@@ -54387,6 +54386,7 @@
/obj/structure/chair/office/dark{
dir = 1
},
+/obj/effect/landmark/start/atmospheric_technician,
/turf/open/floor/plasteel,
/area/engine/atmos)
"fMp" = (
@@ -54522,19 +54522,6 @@
},
/turf/open/floor/carpet,
/area/crew_quarters/cryopod)
-"ghq" = (
-/obj/structure/lattice/catwalk,
-/obj/item/stack/marker_beacon{
- anchored = 1;
- icon_state = "markerburgundy-on";
- light_color = "#FA644B";
- light_power = 3;
- light_range = 3;
- name = "Docking Beacon";
- picked_color = "Burgundy"
- },
-/turf/open/floor/plating,
-/area/space/nearstation)
"ghD" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
@@ -54691,7 +54678,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 9
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"gJi" = (
/obj/structure/lattice/catwalk,
@@ -54776,7 +54763,6 @@
dir = 8
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/structure/mirror{
@@ -54928,7 +54914,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 10
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"hxn" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -56574,7 +56560,6 @@
},
/area/maintenance/bar)
"mqZ" = (
-/obj/structure/reagent_dispensers/keg/aphro/strong,
/obj/item/reagent_containers/glass/beaker,
/turf/open/floor/plating,
/area/maintenance/bar)
@@ -57075,6 +57060,7 @@
dir = 4;
pixel_y = 5
},
+/obj/item/clothing/head/hardhat/cakehat,
/turf/open/floor/wood,
/area/crew_quarters/bar)
"oby" = (
@@ -57198,7 +57184,6 @@
dir = 8
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/structure/mirror{
@@ -57290,7 +57275,7 @@
/area/crew_quarters/theatre)
"oyN" = (
/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"oyX" = (
/obj/machinery/atmospherics/components/binary/pump/on{
@@ -57847,7 +57832,6 @@
pixel_y = 32
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/turf/open/floor/mineral/titanium/blue,
@@ -57910,7 +57894,6 @@
pixel_y = 32
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/machinery/light/small{
@@ -58131,7 +58114,7 @@
dir = 5
},
/obj/machinery/camera{
- c_tag = "Bar Backroom"
+ c_tag = "Gravity Generator - Fore"
},
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
@@ -58414,7 +58397,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"slk" = (
/obj/machinery/door/airlock/maintenance{
@@ -58671,9 +58654,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/engine/engine_smes)
-"sQX" = (
-/turf/open/floor/plating,
-/area/space)
"sRH" = (
/obj/machinery/autolathe/secure{
name = "public autolathe"
@@ -58790,7 +58770,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 5
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"trb" = (
/obj/machinery/light{
@@ -59013,7 +58993,7 @@
/area/hallway/primary/central)
"uaw" = (
/obj/machinery/power/apc{
- areastring = "/area/storage/art";
+ areastring = "/area/maintenance/bar";
dir = 1;
name = "Maint bar";
pixel_y = 24
@@ -59426,7 +59406,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"vbi" = (
/obj/structure/table,
@@ -60525,7 +60505,7 @@
name = "Docking Beacon";
picked_color = "Burgundy"
},
-/turf/open/space/basic,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"xOx" = (
/obj/structure/chair/comfy/brown{
@@ -60673,7 +60653,6 @@
pixel_y = 32
},
/obj/structure/sink{
- dir = 1;
pixel_y = 25
},
/obj/machinery/button/door{
@@ -66759,11 +66738,11 @@ aaa
aaa
aaa
aaa
-ghq
+xLX
aaa
aaa
aaa
-ghq
+xLX
aaa
aaa
aaa
@@ -67010,9 +66989,9 @@ aaa
aaa
aaa
aaa
-ghq
+xLX
aaa
-ghq
+xLX
aaa
aaa
aaa
@@ -67024,9 +67003,9 @@ gXs
aaa
aaa
aaa
-ghq
+xLX
aaa
-ghq
+xLX
aaa
aaa
aaa
@@ -76575,7 +76554,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aaa
aaa
@@ -76832,7 +76811,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aaa
aaa
@@ -77089,7 +77068,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aaa
aaa
@@ -77346,7 +77325,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aaa
aaa
@@ -77603,7 +77582,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aaa
aaa
@@ -77860,7 +77839,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aaa
aaa
@@ -78117,7 +78096,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aoV
bZm
@@ -78374,13 +78353,13 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aoV
bVz
aaf
aaf
-sQX
+aoV
aaa
aaS
aaf
@@ -78631,7 +78610,7 @@ aaa
aaa
aaa
aaa
-aag
+aaa
aaa
aag
bVz
@@ -78888,7 +78867,7 @@ aaa
aaa
aaa
aaa
-aag
+gJi
aaa
aaf
bVz
@@ -79145,7 +79124,7 @@ aaa
aaa
aaa
aaa
-aag
+gJi
aaa
aaf
bVz
@@ -84195,7 +84174,7 @@ aaa
aaa
gXs
gXs
-dVU
+aaH
abc
abu
abu
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index db191d5b2d..4a18b67e02 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -288,6 +288,15 @@
dir = 4
},
/obj/item/toy/poolnoodle/red,
+/obj/machinery/power/apc{
+ areastring = "/area/crew_quarters/fitness/pool";
+ dir = 1;
+ name = "Pool APC";
+ pixel_y = 24
+ },
+/obj/structure/cable/white{
+ icon_state = "0-4"
+ },
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/pool)
"aaH" = (
@@ -492,8 +501,8 @@
dir = 4
},
/turf/open/floor/plasteel/yellowsiding/corner{
- icon_state = "yellowcornersiding";
- dir = 8
+ dir = 8;
+ icon_state = "yellowcornersiding"
},
/area/crew_quarters/fitness/pool)
"aba" = (
@@ -510,8 +519,8 @@
dir = 8
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abb" = (
@@ -604,8 +613,8 @@
dir = 4
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 8
+ dir = 8;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abn" = (
@@ -619,8 +628,8 @@
dir = 8
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abo" = (
@@ -704,8 +713,8 @@
name = "pool camera"
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abv" = (
@@ -724,8 +733,8 @@
dir = 4
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 8
+ dir = 8;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"aby" = (
@@ -765,8 +774,8 @@
dir = 8
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abC" = (
@@ -904,8 +913,8 @@
pixel_x = -23
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abP" = (
@@ -972,8 +981,8 @@
pixel_x = -26
},
/turf/open/floor/plasteel/yellowsiding/corner{
- icon_state = "yellowcornersiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowcornersiding"
},
/area/crew_quarters/fitness/pool)
"abW" = (
@@ -982,8 +991,8 @@
dir = 8
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 1
+ dir = 1;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abX" = (
@@ -995,8 +1004,8 @@
dir = 4
},
/turf/open/floor/plasteel/yellowsiding/corner{
- icon_state = "yellowcornersiding";
- dir = 1
+ dir = 1;
+ icon_state = "yellowcornersiding"
},
/area/crew_quarters/fitness/pool)
"abY" = (
@@ -31108,6 +31117,11 @@
/obj/effect/turf_decal/tile/green{
dir = 8
},
+/obj/machinery/power/apc{
+ areastring = "/area/hydroponics";
+ name = "Hydroponics APC";
+ pixel_y = -24
+ },
/turf/open/floor/plasteel,
/area/hydroponics)
"beS" = (
@@ -64485,8 +64499,8 @@
/area/library)
"cel" = (
/obj/structure/chair/sofa/right{
- icon_state = "sofaend_right";
- dir = 8
+ dir = 8;
+ icon_state = "sofaend_right"
},
/obj/structure/sign/painting/library{
pixel_x = 32
@@ -92830,6 +92844,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"dad" = (
@@ -101794,6 +101811,13 @@
/obj/effect/turf_decal/tile/purple{
dir = 4
},
+/obj/structure/cable/white,
+/obj/machinery/power/apc{
+ areastring = "/area/science/misc_lab";
+ dir = 4;
+ name = "Science Lounge APC";
+ pixel_x = 26
+ },
/turf/open/floor/plasteel/white,
/area/science/misc_lab)
"dqi" = (
@@ -113343,6 +113367,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/light/small,
/turf/open/floor/plasteel/dark/telecomms,
/area/science/server)
"dKg" = (
@@ -125579,6 +125604,20 @@
},
/turf/open/floor/plasteel/dark,
/area/science/mixing)
+"ePP" = (
+/obj/machinery/door/firedoor,
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/machinery/door/airlock/public/glass{
+ name = "Pool"
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness/pool)
"eTv" = (
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -125974,7 +126013,6 @@
/turf/open/floor/plating,
/area/chapel/office)
"ijB" = (
-/obj/structure/reagent_dispensers/keg/aphro/strong,
/obj/item/reagent_containers/glass/beaker,
/turf/open/floor/plating,
/area/crew_quarters/abandoned_gambling_den)
@@ -127072,6 +127110,25 @@
},
/turf/open/floor/plasteel,
/area/science/research/abandoned)
+"pQQ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/turf/open/floor/plasteel/dark,
+/area/crew_quarters/fitness/pool)
"pWb" = (
/obj/structure/table/wood/fancy,
/obj/structure/window/reinforced{
@@ -127298,6 +127355,24 @@
},
/turf/open/floor/plasteel,
/area/science/circuit)
+"tqP" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel{
+ heat_capacity = 1e+006
+ },
+/area/crew_quarters/fitness/recreation)
"twt" = (
/obj/machinery/vr_sleeper,
/obj/effect/turf_decal/tile/neutral{
@@ -127768,8 +127843,8 @@
/area/science/mixing)
"xER" = (
/obj/structure/chair/sofa/left{
- icon_state = "sofaend_left";
- dir = 8
+ dir = 8;
+ icon_state = "sofaend_left"
},
/turf/open/floor/wood,
/area/library)
@@ -127849,6 +127924,22 @@
/obj/structure/fans/tiny/invisible,
/turf/open/space/basic,
/area/space)
+"yfK" = (
+/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
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness/recreation)
"yiv" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/neutral{
@@ -181500,10 +181591,10 @@ cCl
cWD
cAz
dac
-cxy
-aav
-aaz
-aaH
+yfK
+tqP
+ePP
+pQQ
aaV
aaN
aaN
diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm
index 1fc5ae5729..fbe5b954ff 100644
--- a/_maps/map_files/KiloStation/KiloStation.dmm
+++ b/_maps/map_files/KiloStation/KiloStation.dmm
@@ -13176,6 +13176,9 @@
dir = 8
},
/obj/effect/decal/cleanable/blood/old,
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel,
/area/security/courtroom)
"avX" = (
@@ -30472,6 +30475,7 @@
/obj/machinery/light{
dir = 1
},
+/obj/machinery/airalarm/directional/north,
/turf/open/floor/plasteel/dark,
/area/science/research)
"aXx" = (
@@ -43673,10 +43677,6 @@
initial_gas_mix = "o2=14;n2=23;TEMP=300"
},
/area/maintenance/central/secondary)
-"bsm" = (
-/obj/machinery/status_display/evac,
-/turf/open/floor/plasteel,
-/area/engine/supermatter)
"bsn" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -57346,9 +57346,7 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"bOe" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer1{
@@ -58566,9 +58564,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"bQb" = (
/obj/structure/flora/rock,
@@ -58931,7 +58927,7 @@
dir = 8
},
/obj/machinery/power/apc{
- areastring = "/area/janitor";
+ areastring = "/area/vacant_room/commissary";
dir = 4;
name = "Vacant Commissary APC";
pixel_x = 27;
@@ -61286,9 +61282,7 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"bUk" = (
/obj/effect/turf_decal/tile/red,
@@ -61568,9 +61562,7 @@
/turf/closed/wall,
/area/engine/atmos)
"bUN" = (
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"bUP" = (
/obj/machinery/door/airlock/external{
@@ -62889,9 +62881,9 @@
pixel_x = 24
},
/obj/machinery/button/electrochromatic{
+ id = "!interrogation_room";
pixel_x = 38;
- pixel_y = -5;
- id = "!interrogation_room"
+ pixel_y = -5
},
/turf/open/floor/plasteel,
/area/security/warden)
@@ -67995,9 +67987,7 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"ceV" = (
/obj/effect/turf_decal/tile/yellow{
@@ -68022,18 +68012,14 @@
dir = 1
},
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"ceX" = (
/obj/machinery/light{
dir = 8
},
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"ceY" = (
/obj/machinery/airalarm{
@@ -68881,9 +68867,7 @@
/area/engine/engineering)
"cgI" = (
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"cgJ" = (
/obj/machinery/door/poddoor/preopen,
@@ -80507,9 +80491,7 @@
/area/maintenance/fore)
"cDp" = (
/obj/structure/lattice/catwalk,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"cDq" = (
/obj/machinery/door/airlock/maintenance{
@@ -80897,9 +80879,6 @@
pixel_x = 4;
pixel_y = 4
},
-/obj/item/storage/pill_bottle/dice{
- pixel_x = -4
- },
/obj/item/pen/red{
pixel_x = 4;
pixel_y = 4
@@ -84679,9 +84658,6 @@
},
/area/security/vacantoffice)
"fyr" = (
-/obj/machinery/light{
- dir = 4
- },
/obj/effect/decal/cleanable/cobweb/cobweb2,
/turf/closed/mineral/random/labormineral,
/area/space/nearstation)
@@ -84924,9 +84900,7 @@
"jAT" = (
/obj/structure/lattice/catwalk,
/obj/machinery/light,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"jHJ" = (
/obj/machinery/atmospherics/pipe/simple/general/visible{
@@ -84938,10 +84912,6 @@
/obj/structure/sign/warning/electricshock,
/turf/closed/wall/r_wall/rust,
/area/ai_monitored/turret_protected/ai_upload)
-"jPE" = (
-/obj/structure/cable,
-/turf/closed/mineral/random/labormineral,
-/area/space/nearstation)
"jQY" = (
/obj/structure/table/wood,
/obj/item/paper_bin,
@@ -85378,9 +85348,7 @@
"rNm" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/lattice/catwalk,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/hallway/secondary/entry)
"swG" = (
/obj/item/reagent_containers/food/drinks/drinkingglass{
@@ -119966,7 +119934,7 @@ ckw
cmw
xON
axa
-jPE
+aeu
aeu
aeU
dQe
@@ -121750,7 +121718,7 @@ clM
axW
cnk
coo
-ayn
+axU
aLH
aLx
aLz
@@ -122270,7 +122238,7 @@ aLF
aag
aag
aag
-bsm
+aLF
cuA
cuW
bYI
diff --git a/_maps/map_files/LambdaStation/lambda.dmm b/_maps/map_files/LambdaStation/lambda.dmm
index 4d2d8cb624..9000c90388 100644
--- a/_maps/map_files/LambdaStation/lambda.dmm
+++ b/_maps/map_files/LambdaStation/lambda.dmm
@@ -44383,7 +44383,6 @@
/turf/open/floor/plasteel/white,
/area/hallway/primary/aft)
"bFB" = (
-/obj/structure/reagent_dispensers/keg/aphro/strong,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/wood{
icon_state = "wood-broken5"
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index d6e413f1de..6415c984bf 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -2292,8 +2292,7 @@
/turf/open/floor/plating,
/area/crew_quarters/fitness/recreation)
"aeD" = (
-/obj/machinery/door/airlock/external,
-/turf/open/floor/plating,
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"aeE" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -3116,9 +3115,6 @@
},
/turf/open/floor/plasteel,
/area/security/prison)
-"afQ" = (
-/turf/open/floor/plating,
-/area/hallway/primary/port)
"afR" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
@@ -3188,8 +3184,14 @@
/turf/open/floor/plasteel/dark,
/area/ai_monitored/security/armory)
"afZ" = (
-/obj/structure/girder,
-/turf/open/floor/plating,
+/obj/machinery/camera{
+ c_tag = "Arrivals - Lounge";
+ dir = 4
+ },
+/obj/structure/chair/comfy{
+ dir = 4
+ },
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"aga" = (
/obj/effect/turf_decal/tile/neutral{
@@ -3670,8 +3672,10 @@
/turf/open/floor/plasteel/dark,
/area/security/prison)
"agQ" = (
-/obj/item/electronics/airlock,
-/turf/open/floor/plating,
+/obj/machinery/holopad{
+ pixel_y = -15
+ },
+/turf/open/floor/carpet,
/area/hallway/primary/port)
"agR" = (
/obj/machinery/airalarm{
@@ -4281,9 +4285,7 @@
},
/area/maintenance/fore)
"ahT" = (
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
+/turf/open/floor/carpet,
/area/hallway/primary/port)
"ahU" = (
/obj/effect/decal/cleanable/cobweb/cobweb2,
@@ -4802,13 +4804,14 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"aiT" = (
-/obj/effect/decal/cleanable/oil{
- icon_state = "floor5"
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/turf/open/floor/plating{
- icon_state = "panelscorched"
+/obj/machinery/light{
+ dir = 4
},
-/area/hallway/primary/port)
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
"aiU" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/obj/effect/turf_decal/tile/neutral{
@@ -4830,9 +4833,13 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"aiW" = (
-/turf/open/floor/plating{
- icon_state = "platingdmg1"
+/obj/structure/chair/comfy{
+ dir = 8
},
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"aiX" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
@@ -4936,12 +4943,11 @@
/turf/open/floor/plating,
/area/maintenance/port/fore)
"ajk" = (
-/obj/structure/shuttle/engine/propulsion/right{
- dir = 4
- },
-/turf/open/floor/plating{
- icon_state = "platingdmg3"
+/obj/structure/table/wood,
+/obj/item/flashlight/lamp/green{
+ pixel_y = 3
},
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"ajl" = (
/obj/item/soap/deluxe,
@@ -5035,8 +5041,10 @@
/turf/open/floor/plasteel/dark,
/area/security/warden)
"ajs" = (
-/obj/item/stack/sheet/metal/ten,
-/turf/open/floor/plating,
+/obj/item/kirbyplants{
+ icon_state = "plant-08"
+ },
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"ajt" = (
/obj/structure/closet{
@@ -5059,8 +5067,20 @@
/turf/open/floor/plasteel/dark,
/area/security/warden)
"aju" = (
-/obj/item/stack/sheet/mineral/wood/twenty,
-/turf/open/floor/plating,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/cable/yellow{
+ icon_state = "2-8"
+ },
+/obj/structure/cable/yellow{
+ icon_state = "2-4"
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
/area/hallway/primary/port)
"ajv" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
@@ -6921,9 +6941,17 @@
/turf/open/floor/plating,
/area/maintenance/fore)
"amv" = (
-/obj/item/stack/sheet/metal/ten,
-/obj/item/wrench,
-/turf/open/floor/plating,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral,
+/turf/open/floor/plasteel,
/area/hallway/primary/port)
"amw" = (
/obj/structure/window/reinforced,
@@ -6961,10 +6989,6 @@
/obj/structure/window/reinforced,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
-"amB" = (
-/obj/effect/decal/cleanable/blood/old,
-/turf/open/floor/plating,
-/area/hallway/primary/port)
"amC" = (
/obj/structure/chair{
dir = 4
@@ -24081,9 +24105,10 @@
icon_state = "map-right-MS";
pixel_y = 32
},
-/turf/open/floor/plasteel/white/corner{
+/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"aVE" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
@@ -31733,28 +31758,22 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
+/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bjX" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/obj/machinery/door/firedoor,
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/turf/open/floor/plasteel/cafeteria,
+/area/hallway/secondary/entry)
"bjY" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/machinery/light{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
+/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bjZ" = (
@@ -31814,6 +31833,12 @@
dir = 1
},
/obj/structure/cable,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bke" = (
@@ -31826,6 +31851,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bkf" = (
@@ -31845,6 +31873,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bkg" = (
@@ -32650,6 +32681,10 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/light{
+ dir = 1;
+ light_color = "#cee5d2"
+ },
/turf/open/floor/plasteel/dark,
/area/ai_monitored/turret_protected/aisat/foyer)
"blC" = (
@@ -32823,39 +32858,23 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 8
},
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/corner,
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/obj/structure/cable/yellow{
icon_state = "2-4"
},
-/turf/open/floor/plasteel/white/corner,
+/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"blU" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/machinery/door/firedoor,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
-"blV" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/obj/effect/turf_decal/stripes/line,
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
"blW" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -32864,7 +32883,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
@@ -32875,7 +32893,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
@@ -32890,7 +32907,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
@@ -32904,7 +32920,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
@@ -32918,7 +32933,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
@@ -32931,10 +32945,13 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bmc" = (
@@ -32944,8 +32961,8 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/obj/effect/turf_decal/stripes/corner{
- dir = 1
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
},
/turf/open/floor/plasteel,
/area/hallway/primary/port)
@@ -32956,6 +32973,9 @@
/obj/structure/cable/yellow{
icon_state = "2-8"
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bme" = (
@@ -33830,30 +33850,9 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
-"bnL" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/machinery/newscaster{
- pixel_x = 28;
- pixel_y = 1
- },
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
-/turf/open/floor/plasteel/white/corner,
-/area/hallway/secondary/entry)
"bnR" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/bot,
-/obj/structure/sign/mining,
-/turf/open/floor/plasteel,
+/obj/structure/chair/comfy,
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"bnS" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
@@ -33863,7 +33862,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/effect/turf_decal/stripes/line{
+/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/turf/open/floor/plasteel,
@@ -33878,6 +33877,9 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bnU" = (
@@ -34956,29 +34958,19 @@
"bqc" = (
/obj/machinery/holopad,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/machinery/light{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
+/obj/structure/cable/yellow{
+ icon_state = "2-4"
+ },
+/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bqd" = (
-/obj/machinery/door/firedoor,
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
+/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bqj" = (
@@ -34987,7 +34979,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/effect/turf_decal/stripes/line{
+/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/turf/open/floor/plasteel,
@@ -36130,13 +36122,9 @@
/turf/open/floor/plasteel/dark,
/area/ai_monitored/turret_protected/aisat_interior)
"bsf" = (
-/obj/machinery/light,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
/turf/open/floor/plasteel/dark,
/area/ai_monitored/turret_protected/aisat/foyer)
"bsg" = (
@@ -36217,16 +36205,10 @@
/area/hallway/secondary/entry)
"bso" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
+/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bsu" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
@@ -36236,7 +36218,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/effect/turf_decal/stripes/line{
+/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/turf/open/floor/plasteel,
@@ -36248,6 +36230,7 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bsw" = (
@@ -37020,29 +37003,25 @@
/area/hallway/secondary/entry)
"btY" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/effect/turf_decal/stripes/line{
- dir = 8
+/obj/structure/disposalpipe/segment{
+ dir = 9
},
-/obj/machinery/camera{
- c_tag = "Port Primary Hallway - Port";
- dir = 4
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
},
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"btZ" = (
-/obj/machinery/light{
- dir = 4
- },
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bua" = (
@@ -37703,16 +37682,10 @@
/turf/closed/wall,
/area/aisat)
"bvu" = (
-/obj/structure/table/wood,
/obj/machinery/light/small{
dir = 8
},
-/obj/item/radio/off{
- pixel_y = 4
- },
-/obj/item/screwdriver{
- pixel_y = 10
- },
+/obj/machinery/announcement_system,
/turf/open/floor/plasteel/grimy,
/area/tcommsat/computer)
"bvv" = (
@@ -37847,26 +37820,23 @@
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bvK" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bvL" = (
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
+/obj/structure/cable/yellow{
+ icon_state = "2-4"
},
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bvT" = (
/obj/structure/disposalpipe/segment{
@@ -37878,15 +37848,16 @@
/turf/open/floor/plating,
/area/maintenance/department/science/xenobiology)
"bvV" = (
-/obj/structure/extinguisher_cabinet{
- pixel_x = 27
- },
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
+/obj/structure/cable/yellow{
+ icon_state = "1-8"
+ },
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bvW" = (
@@ -38677,28 +38648,36 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/turf/open/floor/plasteel,
+/obj/structure/cable/yellow{
+ icon_state = "2-4"
+ },
+/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bxC" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
},
-/turf/open/floor/plasteel,
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bxD" = (
/obj/effect/turf_decal/tile/blue{
- dir = 4
+ dir = 8
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/light{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
},
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/structure/cable/yellow{
+ icon_state = "2-8"
+ },
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bxL" = (
@@ -38718,15 +38697,13 @@
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
/obj/structure/cable/yellow{
icon_state = "1-4"
},
-/obj/structure/cable/yellow{
- icon_state = "2-4"
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
},
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"bxO" = (
@@ -39242,7 +39219,7 @@
dir = 4
},
/obj/machinery/computer/station_alert,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 4
},
/turf/open/floor/plasteel/dark/corner{
@@ -39262,7 +39239,7 @@
dir = 4
},
/obj/structure/closet/secure_closet/atmospherics,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 4
},
/turf/open/floor/plasteel/dark/corner{
@@ -39279,10 +39256,10 @@
dir = 4
},
/obj/structure/closet/secure_closet/atmospherics,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/dark/corner{
dir = 1
},
@@ -39295,9 +39272,6 @@
pixel_y = 24
},
/obj/machinery/computer/atmos_control,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
- dir = 4
- },
/turf/open/floor/plasteel/checker,
/area/engine/atmos)
"byW" = (
@@ -39311,7 +39285,7 @@
dir = 4
},
/obj/machinery/computer/atmos_control,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 4
},
/turf/open/floor/plasteel/checker,
@@ -39330,12 +39304,12 @@
pixel_x = -26
},
/obj/machinery/pipedispenser/disposal/transit_tube,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
- dir = 4
- },
/obj/effect/turf_decal/stripes/line{
dir = 6
},
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"byY" = (
@@ -39343,7 +39317,7 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 4
},
/turf/open/floor/plasteel,
@@ -39356,14 +39330,14 @@
dir = 8
},
/obj/machinery/pipedispenser,
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/camera{
c_tag = "Atmospherics - Entrance";
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bza" = (
@@ -39609,23 +39583,14 @@
/turf/open/floor/plasteel/dark,
/area/aisat)
"bzw" = (
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/machinery/door/firedoor,
-/obj/machinery/newscaster{
- pixel_x = 28;
- pixel_y = 1
+/obj/machinery/door/airlock{
+ name = "Port Emergency Storage"
},
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
-/area/hallway/secondary/entry)
+/turf/open/floor/plating,
+/area/maintenance/port)
"bzx" = (
/turf/closed/wall,
/area/security/vacantoffice)
@@ -40217,12 +40182,15 @@
/area/tcommsat/computer)
"bAW" = (
/obj/structure/table/wood,
-/obj/item/folder/blue,
/obj/machinery/status_display/evac{
pixel_y = 31
},
-/obj/item/folder/blue,
-/obj/item/pen,
+/obj/item/radio/off{
+ pixel_y = 4
+ },
+/obj/item/screwdriver{
+ pixel_y = 10
+ },
/turf/open/floor/plasteel/grimy,
/area/tcommsat/computer)
"bAX" = (
@@ -40285,45 +40253,22 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
-"bBd" = (
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
-/obj/structure/cable/yellow{
- icon_state = "2-4"
- },
-/turf/open/floor/plasteel,
-/area/hallway/secondary/entry)
"bBf" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
+/obj/structure/table/wood,
+/obj/machinery/light_switch{
+ pixel_x = -28
},
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/item/folder,
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"bBg" = (
/turf/open/floor/wood,
/area/security/vacantoffice)
"bBh" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/obj/structure/cable/yellow{
- icon_state = "2-8"
- },
-/obj/structure/cable/yellow{
- icon_state = "2-4"
- },
-/turf/open/floor/plasteel,
+/obj/structure/table/wood,
+/obj/item/reagent_containers/food/snacks/chips,
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"bBi" = (
/obj/structure/table/wood,
@@ -41039,33 +40984,29 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
-/area/hallway/secondary/entry)
-"bCI" = (
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
+"bCI" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
},
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/white/corner,
-/area/hallway/secondary/entry)
+/turf/open/floor/plating,
+/area/maintenance/port)
"bCJ" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/obj/item/storage/toolbox/emergency,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
},
-/obj/machinery/door/firedoor,
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/area/maintenance/port)
"bCK" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -41074,66 +41015,35 @@
/turf/open/floor/plating,
/area/maintenance/starboard)
"bCL" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 1
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/machinery/firealarm{
- pixel_y = -24
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"bCM" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/item/radio/intercom{
- pixel_y = -28
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/obj/structure/table/wood,
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"bCN" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/stripes/line{
dir = 8
},
/obj/machinery/door/firedoor,
-/obj/machinery/power/apc{
- areastring = "/area/hallway/secondary/entry";
- dir = 8;
- name = "Arrivals APC";
- pixel_x = -26
- },
-/obj/structure/cable/yellow{
- icon_state = "0-4"
- },
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bCP" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/structure/sign/map/right{
- desc = "A framed picture of the station. Clockwise from security at the top (red), you see engineering (yellow), science (purple), escape (red and white), medbay (green), arrivals (blue and white), and finally cargo (brown).";
- icon_state = "map-right-MS";
- pixel_y = -32
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/turf/open/floor/plating,
+/area/crew_quarters/toilet/auxiliary)
"bCQ" = (
/obj/machinery/door/firedoor,
-/obj/structure/cable/yellow{
- icon_state = "2-8"
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/turf/open/floor/plasteel,
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bCR" = (
/obj/machinery/power/apc/highcap/five_k{
@@ -41143,7 +41053,7 @@
},
/obj/structure/cable/yellow,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
+ dir = 9
},
/turf/open/floor/plasteel,
/area/crew_quarters/toilet/auxiliary)
@@ -41152,9 +41062,6 @@
dir = 8;
pixel_x = 24
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 10
- },
/turf/open/floor/plasteel,
/area/crew_quarters/toilet/auxiliary)
"bCV" = (
@@ -41792,44 +41699,43 @@
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bEo" = (
-/obj/machinery/door/airlock{
- name = "Port Emergency Storage"
- },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/item/storage/box/lights/mixed,
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/turf/open/floor/plating,
/area/maintenance/port)
"bEp" = (
-/obj/machinery/door/firedoor,
-/turf/open/floor/plasteel,
-/area/hallway/secondary/entry)
+/obj/machinery/vending/coffee,
+/turf/open/floor/plasteel/dark,
+/area/hallway/primary/port)
"bEq" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall,
-/area/security/vacantoffice)
-"bEs" = (
-/obj/structure/table/wood,
-/obj/item/paper_bin{
- pixel_x = -2;
- pixel_y = 6
- },
-/obj/machinery/newscaster{
- pixel_y = 32
+/obj/structure/light_construct{
+ dir = 8
},
/turf/open/floor/wood,
/area/security/vacantoffice)
-"bEt" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/structure/disposalpipe/segment,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
+"bEs" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/obj/effect/turf_decal/stripes/line{
+/obj/machinery/power/apc{
+ areastring = "/area/hallway/secondary/entry";
+ dir = 4;
+ name = "Arrivals APC";
+ pixel_x = 26
+ },
+/obj/structure/cable/yellow{
+ icon_state = "0-8"
+ },
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
+"bEt" = (
+/obj/structure/chair/comfy{
dir = 8
},
-/obj/machinery/door/firedoor,
-/turf/open/floor/plasteel,
+/turf/open/floor/plasteel/grimy,
/area/hallway/primary/port)
"bEu" = (
/obj/machinery/door/airlock{
@@ -42693,7 +42599,7 @@
name = "Distribution Loop";
req_access_txt = "24"
},
-/obj/machinery/atmospherics/pipe/simple/orange/visible,
+/obj/machinery/atmospherics/pipe/simple/orange/hidden,
/turf/open/floor/plasteel,
/area/engine/atmos)
"bFQ" = (
@@ -42807,18 +42713,18 @@
/turf/open/floor/carpet,
/area/crew_quarters/theatre)
"bGh" = (
-/obj/machinery/announcement_system,
-/turf/open/floor/plasteel/grimy,
-/area/tcommsat/computer)
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/ai_monitored/turret_protected/aisat/foyer)
"bGj" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
+/obj/machinery/vending/cola/random,
+/obj/machinery/newscaster{
+ pixel_x = -30
},
-/obj/machinery/door/firedoor,
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
-/turf/open/floor/plasteel,
+/turf/open/floor/plasteel/dark,
/area/hallway/primary/port)
"bGk" = (
/obj/structure/cable/yellow{
@@ -42842,8 +42748,9 @@
/turf/open/floor/plasteel,
/area/crew_quarters/toilet/auxiliary)
"bGm" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 6
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/shower{
+ dir = 8
},
/turf/open/floor/plasteel,
/area/crew_quarters/toilet/auxiliary)
@@ -43438,18 +43345,20 @@
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bHJ" = (
-/obj/item/tank/internals/oxygen,
-/obj/item/tank/internals/oxygen,
-/obj/item/clothing/mask/breath,
-/obj/item/clothing/mask/breath,
-/obj/machinery/light/small{
+/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/turf/open/floor/plating,
-/area/maintenance/port)
+/obj/machinery/newscaster{
+ pixel_x = 28;
+ pixel_y = 1
+ },
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
"bHK" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
- dir = 1
+/obj/structure/table/wood,
+/obj/item/book/manual/wiki/security_space_law{
+ pixel_x = -3;
+ pixel_y = 5
},
/turf/open/floor/wood,
/area/security/vacantoffice)
@@ -43463,9 +43372,11 @@
/turf/open/floor/carpet,
/area/security/vacantoffice)
"bHM" = (
-/obj/structure/table/wood,
-/turf/open/floor/wood,
-/area/security/vacantoffice)
+/obj/structure/chair/comfy{
+ dir = 4
+ },
+/turf/open/floor/plasteel/grimy,
+/area/hallway/primary/port)
"bHN" = (
/obj/machinery/shower{
dir = 4
@@ -44151,9 +44062,10 @@
/turf/open/floor/plasteel/grimy,
/area/tcommsat/computer)
"bJj" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 1
+/obj/machinery/door/airlock/maintenance{
+ req_one_access_txt = "12;27;37"
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/cable/yellow{
icon_state = "1-2"
},
@@ -44191,26 +44103,23 @@
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bJp" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
-/turf/open/floor/plasteel,
-/area/hallway/secondary/entry)
+/obj/machinery/vending/snack/random,
+/turf/open/floor/plasteel/dark,
+/area/hallway/primary/port)
"bJq" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/item/storage/box/lights/mixed,
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
/turf/open/floor/plating,
/area/maintenance/port)
"bJr" = (
-/obj/machinery/atmospherics/components/unary/portables_connector/visible{
- dir = 1
- },
-/obj/machinery/portable_atmospherics/canister/air,
-/turf/open/floor/plating,
-/area/maintenance/port)
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plasteel,
+/area/hallway/secondary/entry)
"bJs" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 10
@@ -44224,9 +44133,6 @@
/obj/item/radio/intercom{
pixel_x = -29
},
-/obj/machinery/light/small{
- dir = 8
- },
/turf/open/floor/wood,
/area/security/vacantoffice)
"bJu" = (
@@ -44250,8 +44156,10 @@
/turf/open/floor/carpet,
/area/security/vacantoffice)
"bJw" = (
-/obj/structure/chair/office{
- dir = 8
+/obj/structure/table/wood,
+/obj/item/paper_bin{
+ pixel_x = -2;
+ pixel_y = 6
},
/turf/open/floor/carpet,
/area/security/vacantoffice)
@@ -44260,15 +44168,6 @@
dir = 8;
pixel_x = 24
},
-/obj/structure/table/wood,
-/obj/item/camera_film{
- pixel_x = 6;
- pixel_y = 7
- },
-/obj/item/camera_film{
- pixel_x = -3;
- pixel_y = 5
- },
/turf/open/floor/wood,
/area/security/vacantoffice)
"bJy" = (
@@ -44764,19 +44663,19 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bKy" = (
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 4
},
/turf/closed/wall,
/area/engine/atmos)
"bKz" = (
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
+/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 10
},
/turf/closed/wall,
/area/engine/atmos)
"bKA" = (
-/obj/machinery/atmospherics/pipe/simple/orange/visible,
+/obj/machinery/atmospherics/pipe/simple/orange/hidden,
/turf/closed/wall,
/area/engine/atmos)
"bKB" = (
@@ -44956,15 +44855,11 @@
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bKX" = (
-/obj/machinery/door/airlock/maintenance{
- req_one_access_txt = "12;27;37"
+/obj/structure/chair/comfy{
+ dir = 1
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
+/turf/open/floor/plasteel/grimy,
+/area/hallway/primary/port)
"bKY" = (
/obj/machinery/power/apc{
areastring = "/area/security/vacantoffice";
@@ -45503,7 +45398,7 @@
/area/engine/atmos)
"bMe" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/orange/visible,
+/obj/machinery/atmospherics/pipe/simple/orange/hidden,
/turf/open/floor/plating,
/area/engine/atmos)
"bMf" = (
@@ -45730,7 +45625,7 @@
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"bMC" = (
-/obj/structure/chair/office,
+/obj/structure/chair/office/dark,
/turf/open/floor/wood,
/area/security/vacantoffice)
"bMD" = (
@@ -45993,19 +45888,15 @@
/turf/open/floor/carpet,
/area/bridge/showroom/corporate)
"bNd" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+/obj/item/tank/internals/oxygen,
+/obj/item/tank/internals/oxygen,
+/obj/item/clothing/mask/breath,
+/obj/item/clothing/mask/breath,
+/obj/machinery/light/small{
dir = 4
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/machinery/camera{
- c_tag = "Port Primary Hallway - Mining Shuttle";
- dir = 1
- },
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/turf/open/floor/plating,
+/area/maintenance/port)
"bNe" = (
/obj/structure/table/wood,
/obj/item/phone{
@@ -46049,17 +45940,11 @@
/turf/open/floor/wood,
/area/bridge/showroom/corporate)
"bNh" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/structure/disposalpipe/segment{
- dir = 6
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/obj/structure/table/wood,
+/obj/item/folder/red,
+/obj/item/pen/red,
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"bNi" = (
/obj/structure/window/reinforced{
dir = 8
@@ -46322,12 +46207,17 @@
/turf/open/floor/wood,
/area/crew_quarters/theatre)
"bNK" = (
-/obj/machinery/disposal/bin,
-/obj/structure/disposalpipe/trunk{
- dir = 1
+/obj/machinery/airalarm{
+ dir = 8;
+ pixel_x = 24
},
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/obj/structure/table/wood,
+/obj/item/paper_bin{
+ pixel_x = -2;
+ pixel_y = 6
+ },
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"bNL" = (
/obj/structure/table,
/obj/item/stock_parts/subspace/transmitter,
@@ -47710,9 +47600,6 @@
dir = 8;
pixel_x = 24
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 9
- },
/turf/open/floor/plating,
/area/crew_quarters/toilet/auxiliary)
"bQQ" = (
@@ -65013,10 +64900,8 @@
/obj/machinery/light_switch{
pixel_y = 28
},
-/obj/structure/closet/l3closet/scientist{
- pixel_x = -2
- },
/obj/effect/turf_decal/stripes/line,
+/obj/structure/closet/bombcloset,
/turf/open/floor/plasteel,
/area/science/mixing)
"cyA" = (
@@ -65047,7 +64932,6 @@
"cyD" = (
/obj/machinery/atmospherics/components/unary/portables_connector/visible,
/obj/effect/turf_decal/stripes/line,
-/obj/machinery/portable_atmospherics/canister,
/turf/open/floor/plasteel,
/area/science/mixing)
"cyE" = (
@@ -65059,7 +64943,6 @@
network = list("ss13","rd")
},
/obj/machinery/atmospherics/components/unary/portables_connector/visible,
-/obj/machinery/portable_atmospherics/canister,
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plasteel,
/area/science/mixing)
@@ -65092,7 +64975,9 @@
dir = 4
},
/obj/machinery/portable_atmospherics/canister,
-/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"cyI" = (
@@ -65108,11 +64993,7 @@
/obj/machinery/light_switch{
pixel_y = 28
},
-/obj/machinery/portable_atmospherics/scrubber,
-/obj/effect/turf_decal/stripes/line{
- dir = 9
- },
-/turf/open/floor/plasteel,
+/turf/open/floor/plasteel/white,
/area/science/mixing)
"cyK" = (
/turf/closed/wall/r_wall,
@@ -65523,10 +65404,14 @@
/turf/open/floor/plasteel/white,
/area/science/mixing)
"czB" = (
-/obj/machinery/portable_atmospherics/pump,
-/obj/effect/turf_decal/stripes/line{
- dir = 8
+/obj/machinery/light{
+ dir = 4
},
+/obj/structure/window/reinforced{
+ dir = 1;
+ pixel_y = 2
+ },
+/obj/machinery/portable_atmospherics/pump,
/turf/open/floor/plasteel,
/area/science/mixing)
"czC" = (
@@ -66204,12 +66089,15 @@
/turf/open/floor/plasteel/white,
/area/science/mixing)
"cAG" = (
-/obj/structure/window/reinforced,
-/obj/machinery/portable_atmospherics/scrubber,
-/obj/item/storage/firstaid/toxin,
-/obj/effect/turf_decal/stripes/line{
- dir = 10
+/obj/structure/extinguisher_cabinet{
+ pixel_x = 27
},
+/obj/machinery/camera{
+ c_tag = "Toxins - Mixing Area";
+ dir = 8;
+ network = list("ss13","rd")
+ },
+/obj/machinery/portable_atmospherics/scrubber,
/turf/open/floor/plasteel,
/area/science/mixing)
"cAH" = (
@@ -66924,10 +66812,10 @@
/turf/open/floor/plasteel/white,
/area/science/research)
"cCt" = (
-/obj/structure/closet/bombcloset,
/obj/effect/turf_decal/stripes/line{
dir = 1
},
+/obj/machinery/portable_atmospherics/canister,
/turf/open/floor/plasteel,
/area/science/mixing)
"cCu" = (
@@ -68084,19 +67972,14 @@
dir = 1;
pixel_y = 2
},
-/obj/machinery/light{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/stripes/line{
- dir = 5
- },
/turf/open/floor/plasteel,
/area/science/mixing)
"cEz" = (
-/obj/structure/closet/wardrobe/grey,
-/turf/open/floor/plating,
-/area/maintenance/starboard/aft)
+/obj/machinery/portable_atmospherics/scrubber,
+/obj/item/storage/firstaid/toxin,
+/turf/open/floor/plasteel,
+/area/science/mixing)
"cEA" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -68481,18 +68364,7 @@
/turf/open/floor/plasteel/white,
/area/science/mixing)
"cFs" = (
-/obj/structure/extinguisher_cabinet{
- pixel_x = 27
- },
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/camera{
- c_tag = "Toxins - Mixing Area";
- dir = 8;
- network = list("ss13","rd")
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
/turf/open/floor/plasteel,
/area/science/mixing)
"cFu" = (
@@ -68978,9 +68850,6 @@
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/stripes/line{
- dir = 6
- },
/obj/machinery/portable_atmospherics/pump,
/turf/open/floor/plasteel,
/area/science/mixing)
@@ -70211,9 +70080,7 @@
/obj/structure/cable/yellow{
icon_state = "1-4"
},
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 4
- },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
"cIm" = (
@@ -79125,13 +78992,10 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/machinery/door/firedoor,
/obj/structure/sign/poster/official/random{
pixel_y = 32
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
+/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"dhQ" = (
@@ -79209,14 +79073,11 @@
/turf/open/floor/wood,
/area/crew_quarters/theatre)
"dhZ" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
+/obj/structure/urinal{
+ pixel_y = 29
},
-/obj/structure/cable/yellow{
- icon_state = "1-8"
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/turf/open/floor/plating,
+/area/crew_quarters/toilet/auxiliary)
"dib" = (
/obj/structure/table/wood,
/obj/item/lipstick{
@@ -79252,10 +79113,6 @@
/area/hallway/secondary/entry)
"did" = (
/obj/structure/table/wood,
-/obj/machinery/light_switch{
- pixel_x = -28
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/item/folder,
/turf/open/floor/wood,
/area/security/vacantoffice)
@@ -79271,13 +79128,11 @@
/turf/open/floor/wood,
/area/crew_quarters/theatre)
"dig" = (
-/obj/machinery/airalarm{
- dir = 8;
- pixel_x = 24
+/obj/item/kirbyplants{
+ icon_state = "plant-03"
},
-/obj/structure/table/wood,
-/turf/open/floor/wood,
-/area/security/vacantoffice)
+/turf/open/floor/plasteel/grimy,
+/area/hallway/primary/port)
"dih" = (
/obj/machinery/light/small,
/obj/structure/sign/poster/official/random{
@@ -79666,15 +79521,15 @@
},
/area/medical/medbay/aft)
"diP" = (
-/obj/structure/cable/yellow{
- icon_state = "1-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 9
- },
/obj/structure/sign/poster/contraband/random{
pixel_y = -32
},
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
"diQ" = (
@@ -79850,20 +79705,10 @@
/turf/open/space/basic,
/area/space)
"djW" = (
-/obj/machinery/light{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/obj/structure/reagent_dispensers/fueltank,
/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/area/maintenance/port)
"djX" = (
/obj/structure/closet/crate/coffin,
/obj/machinery/door/window/eastleft{
@@ -80398,9 +80243,7 @@
pixel_y = -24
},
/obj/structure/cable/yellow,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
"dAh" = (
@@ -81264,6 +81107,12 @@
},
/turf/closed/wall,
/area/maintenance/starboard)
+"dQg" = (
+/obj/machinery/door/airlock/maintenance{
+ req_one_access_txt = "12;27;37"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port)
"dYu" = (
/obj/machinery/door/airlock/external{
name = "Auxiliary Airlock"
@@ -81274,9 +81123,16 @@
/turf/open/floor/plating,
/area/hallway/secondary/entry)
"eiS" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plasteel,
-/area/crew_quarters/toilet/auxiliary)
+/obj/machinery/disposal/bin,
+/obj/structure/disposalpipe/trunk{
+ dir = 4
+ },
+/obj/machinery/camera{
+ c_tag = "Port Primary Hallway - True Port";
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/hallway/primary/port)
"eoK" = (
/obj/structure/disposalpipe/segment{
dir = 9
@@ -81380,6 +81236,12 @@
},
/turf/open/floor/plasteel/white,
/area/science/circuit)
+"fDG" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 6
+ },
+/turf/open/floor/plasteel,
+/area/crew_quarters/toilet/auxiliary)
"fFM" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -81456,6 +81318,13 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
+"gGH" = (
+/obj/structure/cable/yellow{
+ icon_state = "2-4"
+ },
+/obj/effect/spawner/lootdrop/maintenance,
+/turf/open/floor/plating,
+/area/maintenance/starboard/aft)
"gGT" = (
/obj/effect/landmark/start/scientist,
/obj/structure/chair/office/light{
@@ -81589,12 +81458,25 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"iSt" = (
-/obj/machinery/door/airlock/grunge,
-/obj/structure/cable/yellow{
- icon_state = "1-2"
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
},
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
+"jdf" = (
+/obj/machinery/door/airlock{
+ id_tag = "AuxShower";
+ name = "Shower"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
-/area/security/vacantoffice)
+/area/crew_quarters/toilet/auxiliary)
"jeV" = (
/obj/machinery/conveyor/inverted{
dir = 10;
@@ -81662,15 +81544,18 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"jBe" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/neutral{
dir = 4
},
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/structure/sign/poster/official/random{
- pixel_y = -32
- },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"jKK" = (
@@ -81702,15 +81587,27 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/obj/machinery/door/firedoor,
/obj/structure/cable/yellow{
icon_state = "4-8"
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"jQK" = (
+/obj/structure/lattice,
+/turf/closed/wall/r_wall,
+/area/aisat)
+"jRo" = (
+/obj/structure/table/wood,
+/obj/machinery/newscaster{
+ pixel_y = 32
+ },
+/obj/item/clipboard,
+/obj/item/paper,
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"kfu" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/white,
@@ -81789,15 +81686,18 @@
/turf/open/floor/plasteel/white,
/area/science/circuit)
"kQP" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/machinery/navbeacon{
+ codes_txt = "patrol;next_patrol=6-Port-Central";
+ location = "5-Customs"
+ },
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
},
/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
+ dir = 4
},
/turf/open/floor/plasteel,
/area/hallway/primary/port)
@@ -81843,6 +81743,9 @@
/turf/open/floor/plasteel/white,
/area/science/circuit)
"lws" = (
+/obj/structure/chair/office/dark{
+ dir = 8
+ },
/turf/open/floor/carpet,
/area/security/vacantoffice)
"lzk" = (
@@ -81920,31 +81823,34 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
"maP" = (
-/obj/item/storage/toolbox/emergency,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 10
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
},
-/turf/open/floor/plating{
- icon_state = "panelscorched"
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
},
-/area/maintenance/port)
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
"mcS" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 9
- },
-/obj/structure/disposalpipe/segment{
- dir = 9
+ dir = 4
},
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/structure/sign/map/left{
- desc = "A framed picture of the station. Clockwise from security at the top (red), you see engineering (yellow), science (purple), escape (red and white), medbay (green), arrivals (blue and white), and finally cargo (brown).";
- icon_state = "map-left-MS";
- pixel_y = -32
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/item/radio/intercom{
+ name = "Station Intercom (General)";
+ pixel_y = -28
+ },
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
"mjJ" = (
/obj/machinery/nuclearbomb/beer{
pixel_x = 2;
@@ -81956,6 +81862,12 @@
/obj/structure/lattice,
/turf/closed/wall,
/area/crew_quarters/cryopod)
+"mot" = (
+/obj/structure/chair/office/dark{
+ dir = 8
+ },
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"mvj" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -81997,19 +81909,23 @@
},
/area/maintenance/port/aft)
"nhy" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/structure/disposalpipe/segment,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/corner{
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
+/obj/effect/landmark/event_spawn,
+/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"nix" = (
+/obj/machinery/light/small{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/ai_monitored/turret_protected/aisat/foyer)
"njd" = (
/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
@@ -82293,9 +82209,22 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
"pHS" = (
-/obj/structure/closet/firecloset,
-/turf/open/floor/plating,
-/area/maintenance/port)
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
"pMX" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -82328,6 +82257,15 @@
},
/turf/open/floor/plating,
/area/maintenance/aft)
+"pVL" = (
+/obj/structure/cable/yellow{
+ icon_state = "1-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/starboard/aft)
"pZb" = (
/obj/structure/cable/yellow{
icon_state = "2-4"
@@ -82340,6 +82278,13 @@
},
/turf/open/floor/plating,
/area/maintenance/port)
+"qkY" = (
+/obj/machinery/door/airlock/grunge,
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel,
+/area/security/vacantoffice)
"qqg" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
@@ -82419,11 +82364,18 @@
/turf/open/floor/plasteel,
/area/security/prison)
"rbE" = (
-/obj/effect/turf_decal/tile/blue{
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/turf/open/floor/plasteel/white/corner,
-/area/hallway/secondary/entry)
+/obj/machinery/firealarm{
+ pixel_y = -24
+ },
+/obj/effect/turf_decal/tile/neutral,
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
"roa" = (
/obj/structure/chair/stool,
/obj/machinery/light/small{
@@ -82472,19 +82424,16 @@
/turf/closed/wall,
/area/quartermaster/miningoffice)
"rNX" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/obj/effect/turf_decal/tile/neutral{
- dir = 1
+ dir = 8
},
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/obj/machinery/navbeacon{
- codes_txt = "patrol;next_patrol=6-Port-Central";
- location = "5-Customs"
- },
-/obj/structure/cable/yellow{
- icon_state = "4-8"
+/obj/structure/sign/poster/official/random{
+ pixel_y = -32
},
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"rQK" = (
@@ -82555,15 +82504,16 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"syk" = (
-/obj/machinery/door/airlock{
- id_tag = "AuxShower";
- name = "Shower"
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
},
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
-/area/crew_quarters/toilet/auxiliary)
+/area/hallway/primary/port)
"sFv" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -82615,6 +82565,10 @@
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
+"sZN" = (
+/obj/structure/closet/firecloset,
+/turf/open/floor/plating,
+/area/maintenance/port)
"tap" = (
/obj/machinery/power/apc/auto_name/east,
/obj/structure/cable/yellow{
@@ -82623,33 +82577,14 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
"tre" = (
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/stripes/corner{
- dir = 8
- },
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
-/obj/structure/cable/yellow{
- icon_state = "2-8"
- },
-/obj/structure/cable/yellow{
- icon_state = "2-4"
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
},
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/structure/cable/yellow{
- icon_state = "1-4"
- },
-/obj/structure/cable/yellow{
- icon_state = "1-8"
- },
-/turf/open/floor/plasteel/white/corner,
-/area/hallway/secondary/entry)
+/turf/open/floor/plating,
+/area/maintenance/port)
"tsx" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -82659,6 +82594,13 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard)
+"txh" = (
+/obj/machinery/door/airlock/hatch{
+ name = "Telecomms Control Room";
+ req_one_access_txt = "19; 61"
+ },
+/turf/open/floor/plasteel/dark,
+/area/tcommsat/computer)
"txj" = (
/obj/structure/chair/office/light{
dir = 1
@@ -82682,6 +82624,13 @@
},
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
+"tUa" = (
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
+/obj/machinery/portable_atmospherics/canister/air,
+/turf/open/floor/plating,
+/area/maintenance/port)
"tVY" = (
/obj/structure/closet/crate,
/obj/item/target/alien,
@@ -82807,6 +82756,18 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"vuY" = (
+/obj/structure/table/wood,
+/obj/item/camera_film{
+ pixel_x = 6;
+ pixel_y = 7
+ },
+/obj/item/camera_film{
+ pixel_x = -3;
+ pixel_y = 5
+ },
+/turf/open/floor/wood,
+/area/security/vacantoffice)
"vxG" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -82861,10 +82822,21 @@
/turf/open/floor/plating,
/area/security/prison)
"wlH" = (
-/obj/effect/decal/cleanable/cobweb/cobweb2,
-/obj/structure/reagent_dispensers/fueltank,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/item/radio/intercom{
+ pixel_y = -28
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
/turf/open/floor/plasteel,
-/area/maintenance/port)
+/area/hallway/primary/port)
"wmt" = (
/obj/effect/decal/cleanable/flour,
/turf/open/floor/plating,
@@ -82921,7 +82893,10 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
"xfI" = (
-/obj/machinery/vending/cola/random,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"xgC" = (
@@ -82936,13 +82911,21 @@
/turf/open/floor/plasteel/white,
/area/science/circuit)
"xmb" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/structure/cable/yellow{
- icon_state = "1-2"
+/obj/structure/sign/map/left{
+ desc = "A framed picture of the station. Clockwise from security at the top (red), you see engineering (yellow), science (purple), escape (red and white), medbay (green), arrivals (blue and white), and finally cargo (brown).";
+ icon_state = "map-left-MS";
+ pixel_y = -32
},
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
"xse" = (
@@ -83021,26 +83004,22 @@
/turf/open/floor/plasteel,
/area/security/prison)
"xLL" = (
-/obj/structure/table/wood,
-/obj/item/folder/white{
- pixel_x = 4;
- pixel_y = -3
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
},
-/obj/item/book/manual/wiki/security_space_law{
- pixel_x = -3;
- pixel_y = 5
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
+/obj/structure/sign/map/right{
+ desc = "A framed picture of the station. Clockwise from security at the top (red), you see engineering (yellow), science (purple), escape (red and white), medbay (green), arrivals (blue and white), and finally cargo (brown).";
+ icon_state = "map-right-MS";
+ pixel_y = -32
},
-/turf/open/floor/wood,
-/area/security/vacantoffice)
+/obj/effect/turf_decal/tile/neutral,
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
"xTV" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 6
- },
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/closed/wall,
+/area/security/vacantoffice)
"xVl" = (
/turf/closed/wall,
/area/hallway/secondary/service)
@@ -96315,7 +96294,7 @@ bxL
bvJ
bxB
bCQ
-bBd
+bCH
bCH
bEn
dic
@@ -96568,18 +96547,18 @@ bjV
bnK
bqb
bbI
-btT
+bJr
bvK
bxC
-bEp
-bJp
-rbE
alK
alK
alK
alK
alK
alK
+dQg
+alK
+alK
alK
bPF
asa
@@ -96822,7 +96801,7 @@ bgv
biv
bjW
blT
-bnL
+bso
bqc
bso
bso
@@ -96833,9 +96812,9 @@ tre
bCI
bEo
bJj
-xTV
+bbL
bJq
-bKX
+bbL
bbL
bbL
bPG
@@ -97079,20 +97058,20 @@ bbK
biw
bjX
blU
-baE
-baE
-baE
-baE
-baE
-baE
-baE
-jPu
-bCJ
+aiT
+bEs
+bHJ
+aiT
+iSt
+mcS
alK
auF
-maP
-bJr
+bCJ
+tUa
alK
+apz
+aob
+alC
aqK
aqO
alC
@@ -97335,21 +97314,21 @@ beL
bgw
bix
bjY
-blV
+bqd
baE
-afQ
-afQ
-afQ
-afZ
-afQ
baE
+baE
+baE
+bqd
+nhy
+alK
djW
bNd
+sZN
alK
-wlH
-bHJ
-pHS
-alK
+amZ
+aob
+aob
oWR
aob
bPH
@@ -97593,15 +97572,15 @@ bgx
biy
bjZ
blW
-baE
+ajk
afZ
-afQ
+bHM
ajs
-afQ
-afQ
-baE
-bBf
-kQP
+jBe
+pHS
+bzx
+bzx
+bzx
bzx
bzx
bzx
@@ -97850,13 +97829,13 @@ bgy
biz
bka
blX
-baE
-afQ
-afQ
-afQ
-afQ
-afQ
-baE
+bnR
+ahT
+ahT
+bKX
+jPu
+rbE
+xTV
bBf
bCL
bEq
@@ -98105,19 +98084,19 @@ bda
beO
bgz
biA
-bnR
+bka
blY
aeD
agQ
-afQ
-afQ
-afQ
-afQ
-baE
+ahT
+aeD
+kQP
rNX
-jBe
bzx
bBg
+bBg
+bBg
+bBg
pZb
bJu
bKZ
@@ -98364,16 +98343,16 @@ bgA
biz
bkb
blZ
-baE
+bnR
ahT
-afQ
-afQ
+ahT
+bKX
aju
-afQ
-baE
-bBh
-xmb
-iSt
+syk
+qkY
+bGk
+bGk
+bGk
bGk
bKZ
bHL
@@ -98621,18 +98600,18 @@ bpt
bcW
bkc
bma
-baE
-ahT
+bBh
+bEt
aiW
-afQ
+dig
amv
-afQ
-baE
-bBf
+wlH
+bzx
+bBi
bCM
-bzx
-bzx
-bHM
+bBg
+bBg
+bBg
bJv
drp
heE
@@ -98879,21 +98858,21 @@ bcW
dhP
bqd
baE
-aiT
-ajk
-afQ
-amB
-afQ
baE
-djW
-bsx
+baE
+baE
+bqd
xfI
bzx
-bEs
+jRo
+mot
+bBg
+bBg
+bBg
bJw
lws
bMC
-xLL
+bOg
bzx
bRe
xDn
@@ -99135,18 +99114,18 @@ bgC
biB
bkd
bmb
-baE
-baE
-baE
-baE
-baE
-baE
-baE
-bBf
+bEp
+bGj
+bJp
+eiS
+jBe
+xmb
+bzx
+vuY
bNh
bNK
-bzx
-dig
+bBg
+bBg
bJx
bLa
bMD
@@ -99396,12 +99375,12 @@ bnS
bqj
bsu
btY
-bqj
-bsu
-bEt
-nhy
-mcS
-bvW
+maP
+xLL
+bzx
+bzx
+bzx
+bzx
bzx
bzx
bzx
@@ -99655,7 +99634,7 @@ bsv
btZ
bvV
bxN
-bGj
+bvW
dhZ
bCP
bvW
@@ -99913,9 +99892,9 @@ baE
bvW
bxO
bvW
-bvW
-bvW
-bvW
+dhZ
+fDG
+jdf
bGm
bHO
bvW
@@ -100173,7 +100152,7 @@ bzA
bBm
bCR
bvW
-syk
+bvW
bvW
bvW
bLd
@@ -100429,7 +100408,7 @@ bxQ
bzB
bBn
bCS
-eiS
+bBn
bQN
dih
bvW
@@ -117170,16 +117149,16 @@ cvX
cwY
crR
cyJ
-czB
-cAG
+cBs
+cBs
cBB
cCC
cDp
+czB
+cAG
+cEz
cyK
-cyK
-cyK
-cyK
-cPe
+dxQ
dvY
cJY
cKM
@@ -117433,9 +117412,9 @@ cBC
cyK
cyK
cyK
-dvY
-dyc
-cub
+cyK
+cyK
+cyK
diP
dvY
cJZ
@@ -117691,9 +117670,9 @@ cCD
uun
rSL
dvY
-cEz
-dxQ
dyc
+gGH
+pVL
dvY
cKa
cKO
@@ -136403,9 +136382,9 @@ bnw
bpJ
brW
aRy
-bvt
-aaa
-aTU
+aRy
+aRy
+jQK
aaa
aaa
aaa
@@ -136659,9 +136638,9 @@ blC
bnx
bpK
bsf
-aRy
-aRy
-aRy
+bGh
+nix
+bGh
aRy
aRy
aRy
@@ -136918,7 +136897,7 @@ bpL
brY
btL
btL
-btL
+txh
btL
btL
bCD
@@ -137175,7 +137154,7 @@ bpM
brZ
btL
bvu
-bGh
+bxq
bzn
bAU
bCD
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index c42cca5029..f3b1b2afb6 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -5281,16 +5281,8 @@
/turf/open/floor/plating,
/area/asteroid/nearstation)
"ail" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/effect/landmark/start/chief_medical_officer,
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/turf/closed/wall,
+/area/medical/genetics)
"aim" = (
/obj/structure/chair/office/dark{
dir = 8
@@ -5559,21 +5551,28 @@
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"aiJ" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/turf_decal/tile/yellow{
+/obj/machinery/light{
dir = 1
},
-/obj/effect/turf_decal/tile/yellow,
-/obj/effect/turf_decal/tile/yellow{
- dir = 4
+/obj/machinery/power/apc/highcap/five_k{
+ areastring = "/area/medical/chemistry";
+ dir = 1;
+ name = "Chemistry Lab APC";
+ pixel_y = 25
+ },
+/obj/structure/cable/white{
+ icon_state = "0-2"
+ },
+/obj/item/kirbyplants{
+ icon_state = "plant-21"
+ },
+/obj/machinery/camera{
+ c_tag = "Chemistry"
},
/obj/effect/turf_decal/tile/yellow{
dir = 8
},
-/obj/effect/landmark/start/chemist,
-/turf/open/floor/plasteel,
+/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"aiK" = (
/obj/structure/closet/crate/bin,
@@ -5659,23 +5658,20 @@
/turf/open/floor/plasteel/white,
/area/science/research)
"aiQ" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/tile/blue{
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 1
},
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
+/obj/structure/cable/white{
+ icon_state = "2-4"
},
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 1
},
-/obj/effect/landmark/start/paramedic,
/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
+/area/hallway/primary/port/aft)
"aiR" = (
/obj/machinery/suit_storage_unit/security,
/obj/machinery/firealarm{
@@ -6168,21 +6164,8 @@
/turf/open/floor/plasteel,
/area/hallway/primary/starboard/fore)
"ajG" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/obj/effect/landmark/start/chief_medical_officer,
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/turf/closed/wall/r_wall,
+/area/crew_quarters/heads/cmo)
"ajH" = (
/obj/structure/plasticflaps/opaque,
/obj/effect/turf_decal/delivery,
@@ -10485,21 +10468,8 @@
/turf/open/floor/plasteel,
/area/hallway/primary/starboard/fore)
"aqo" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/machinery/door/airlock/external{
- name = "External Airlock";
- req_access_txt = "13"
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/turf/closed/wall/r_wall,
+/area/maintenance/port/aft)
"aqp" = (
/obj/machinery/autolathe,
/obj/structure/extinguisher_cabinet{
@@ -10587,17 +10557,15 @@
/turf/open/floor/plating,
/area/crew_quarters/heads/hos)
"aqx" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 4
+/obj/structure/cable/white{
+ icon_state = "2-4"
},
-/obj/effect/landmark/xeno_spawn,
-/obj/structure/sign/warning/vacuum{
- pixel_x = -32;
- pixel_y = 32
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
},
-/obj/effect/turf_decal/delivery,
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/obj/effect/decal/cleanable/cobweb,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aqy" = (
/obj/structure/cable/white,
/obj/effect/spawner/structure/window/reinforced,
@@ -12702,24 +12670,14 @@
/turf/open/floor/wood,
/area/security/detectives_office)
"atE" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
+/obj/structure/cable/white{
+ icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/machinery/door/airlock/external{
- name = "External Airlock";
- req_access_txt = "13"
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"atF" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -14003,15 +13961,16 @@
/turf/open/floor/wood,
/area/security/detectives_office)
"avB" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/structure/sign/warning/vacuum{
- pixel_x = -32;
- pixel_y = 32
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
},
-/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"avC" = (
/obj/structure/sign/poster/ripped,
/turf/closed/wall/rust,
@@ -14668,11 +14627,16 @@
/turf/open/floor/engine/o2,
/area/engine/atmos)
"awB" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/turf/open/floor/plating,
-/area/maintenance/port)
+/turf/open/floor/plating{
+ icon_state = "platingdmg1"
+ },
+/area/maintenance/port/aft)
"awC" = (
/obj/machinery/atmospherics/pipe/simple/green/visible{
dir = 4
@@ -14708,27 +14672,46 @@
/area/maintenance/starboard/aft)
"awE" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 10
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
},
/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"awF" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plasteel,
/area/engine/atmos)
"awG" = (
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"awH" = (
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"awH" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
},
-/obj/machinery/light/small,
-/obj/structure/closet/emcloset/anchored,
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/turf/closed/wall/r_wall,
+/area/maintenance/port/aft)
"awI" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
dir = 5
@@ -14756,11 +14739,15 @@
/turf/open/floor/plasteel/dark/corner,
/area/engine/atmos)
"awL" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"awM" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -15023,69 +15010,72 @@
/turf/open/floor/plasteel,
/area/maintenance/starboard)
"axh" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/structure/closet,
+/obj/effect/spawner/lootdrop/maintenance{
+ lootcount = 3;
+ name = "3maintenance loot spawner"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/turf/open/floor/plating/airless,
-/area/maintenance/port)
+/obj/effect/turf_decal/delivery,
+/obj/effect/turf_decal/stripes/line{
+ dir = 9
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"axi" = (
/obj/machinery/air_sensor/atmos/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"axj" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "2-4"
+ },
+/turf/open/floor/wood,
+/area/library)
"axk" = (
+/obj/structure/girder,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"axl" = (
+/obj/structure/closet/firecloset,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/delivery,
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/structure/closet/crate,
-/obj/item/stack/ore/silver,
-/obj/item/stack/ore/iron,
-/obj/item/stack/ore/iron,
-/obj/item/stack/ore/iron,
-/obj/item/pickaxe/emergency,
/turf/open/floor/plasteel,
-/area/maintenance/port)
-"axl" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"axm" = (
/obj/machinery/atmospherics/components/unary/thermomachine/freezer,
/turf/open/floor/plasteel,
/area/engine/atmos)
"axn" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
+/obj/structure/rack,
+/obj/item/reagent_containers/food/drinks/bottle/whiskey,
+/obj/effect/spawner/lootdrop/maintenance,
+/obj/machinery/light/small,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+/obj/effect/turf_decal/delivery,
+/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"axo" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
/obj/effect/turf_decal/stripes/line{
@@ -15362,22 +15352,20 @@
/turf/open/floor/carpet,
/area/crew_quarters/dorms)
"axL" = (
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
+/obj/structure/rack,
+/obj/effect/spawner/lootdrop/maintenance{
+ lootcount = 2;
+ name = "2maintenance loot spawner"
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
+/obj/effect/turf_decal/delivery,
/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
+ dir = 1
},
/turf/open/floor/plasteel,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"axM" = (
/obj/structure/table/wood,
/obj/item/lipstick/random{
@@ -15527,12 +15515,11 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/bar/atrium)
"axU" = (
-/obj/structure/table/wood,
-/obj/item/paper_bin,
-/obj/item/pen,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/closed/wall,
+/area/maintenance/port/aft)
"axV" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/newscaster{
@@ -15549,19 +15536,17 @@
/turf/closed/wall,
/area/hallway/secondary/exit)
"axX" = (
-/obj/effect/landmark/xeno_spawn,
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 1
- },
-/turf/open/floor/wood,
-/area/maintenance/port)
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/closed/wall/r_wall/rust,
+/area/maintenance/port/aft)
"axY" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
+/obj/structure/cable/white{
+ icon_state = "1-2"
},
-/obj/item/cigbutt,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/landmark/event_spawn,
/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"axZ" = (
/turf/closed/wall/r_wall/rust,
/area/security/prison)
@@ -17489,6 +17474,13 @@
},
/turf/open/floor/plasteel,
/area/security/prison)
+"aBn" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/turf/open/floor/wood,
+/area/library)
"aBo" = (
/obj/structure/cable/white{
icon_state = "2-4"
@@ -18182,6 +18174,12 @@
/obj/machinery/atmospherics/miner/nitrogen,
/turf/open/floor/engine/n2,
/area/engine/atmos)
+"aCx" = (
+/turf/open/floor/wood,
+/area/library)
+"aCy" = (
+/turf/closed/wall,
+/area/crew_quarters/heads/cmo)
"aCz" = (
/obj/machinery/atmospherics/components/unary/portables_connector/visible{
dir = 1
@@ -18205,6 +18203,15 @@
},
/turf/open/floor/plasteel/white/corner,
/area/engine/atmos)
+"aCB" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/library)
"aCC" = (
/obj/machinery/firealarm{
dir = 1;
@@ -18606,6 +18613,13 @@
dir = 1
},
/area/hallway/secondary/exit)
+"aDf" = (
+/obj/effect/landmark/barthpot,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 9
+ },
+/turf/open/floor/wood,
+/area/library)
"aDg" = (
/obj/structure/cable/white{
icon_state = "1-8"
@@ -18648,12 +18662,90 @@
},
/turf/open/space/basic,
/area/space)
+"aDk" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 1
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/green{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
"aDl" = (
/obj/effect/turf_decal/stripes/line{
dir = 8
},
/turf/open/floor/plasteel,
/area/engine/atmos)
+"aDm" = (
+/obj/structure/bookcase/random/fiction,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plasteel/dark,
+/area/library)
+"aDn" = (
+/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
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plasteel/dark,
+/area/library)
+"aDo" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plasteel/dark,
+/area/library)
+"aDp" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
+"aDq" = (
+/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
+ },
+/obj/structure/closet/crate/bin,
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/turf/open/floor/plasteel/dark,
+/area/library)
"aDr" = (
/obj/structure/sign/warning/nosmoking,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
@@ -19129,6 +19221,106 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aEg" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/closed/wall/r_wall,
+/area/maintenance/port/aft)
+"aEh" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/extinguisher_cabinet{
+ pixel_y = 26
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/machinery/camera{
+ c_tag = "Aft Primary Hallway 4"
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
+"aEi" = (
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 1
+ },
+/obj/item/radio/intercom{
+ name = "Station Intercom";
+ pixel_y = 24
+ },
+/obj/structure/cable/white{
+ icon_state = "2-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
+"aEj" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plating{
+ icon_state = "platingdmg2"
+ },
+/area/maintenance/port/aft)
+"aEk" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/power/apc{
+ areastring = "/area/hallway/primary/port/aft";
+ dir = 1;
+ name = "Port Quarter Hallway APC";
+ pixel_y = 24
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "0-8"
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
+"aEl" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/obj/effect/turf_decal/tile/green{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
+"aEm" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port/aft)
"aEn" = (
/obj/machinery/shieldgen,
/obj/structure/sign/warning/nosmoking{
@@ -19786,6 +19978,17 @@
/obj/effect/landmark/blobstart,
/turf/open/floor/plating,
/area/maintenance/starboard/central)
+"aFh" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/turf/open/floor/plasteel{
+ heat_capacity = 1e+006
+ },
+/area/hallway/primary/port/aft)
"aFi" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -19796,6 +19999,21 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
+"aFj" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/turf/open/floor/plasteel{
+ heat_capacity = 1e+006
+ },
+/area/hallway/primary/port/aft)
"aFk" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -19819,6 +20037,10 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aFm" = (
+/obj/machinery/status_display,
+/turf/closed/wall,
+/area/medical/genetics)
"aFn" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 4
@@ -19838,6 +20060,25 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aFo" = (
+/turf/closed/wall/rust,
+/area/medical/genetics)
+"aFp" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aFq" = (
/obj/machinery/power/emitter,
/obj/machinery/light/small,
@@ -20192,6 +20433,13 @@
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"aFM" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aFN" = (
/obj/structure/extinguisher_cabinet{
pixel_x = -26
@@ -20347,6 +20595,10 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
+"aFZ" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/closed/wall,
+/area/crew_quarters/heads/cmo)
"aGa" = (
/obj/effect/landmark/event_spawn,
/obj/item/beacon,
@@ -20380,9 +20632,28 @@
},
/turf/open/floor/plating,
/area/hallway/secondary/exit)
+"aGd" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/turf/open/floor/plasteel{
+ heat_capacity = 1e+006
+ },
+/area/hallway/primary/port/aft)
"aGe" = (
/turf/closed/wall/r_wall,
/area/engine/gravity_generator)
+"aGf" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "geneticsbot";
+ name = "Genetics Privacy Shutters"
+ },
+/turf/open/floor/plating,
+/area/medical/genetics)
"aGg" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -20439,6 +20710,29 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
+"aGl" = (
+/obj/machinery/door/firedoor,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/table/reinforced,
+/obj/machinery/door/window/southleft{
+ name = "Genetics Desk";
+ req_access_txt = "5; 9; 68"
+ },
+/obj/item/folder/yellow,
+/obj/item/pen,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "geneticsbot";
+ name = "Genetics Privacy Shutters"
+ },
+/turf/open/floor/plasteel,
+/area/medical/genetics)
"aGm" = (
/obj/structure/sign/warning/radiation,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
@@ -20604,6 +20898,19 @@
},
/turf/open/floor/plasteel,
/area/maintenance/port/central)
+"aGC" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aGD" = (
/obj/machinery/power/apc/highcap/five_k{
areastring = "/area/maintenance/port/central";
@@ -20631,6 +20938,24 @@
},
/turf/open/floor/plating,
/area/maintenance/port/central)
+"aGF" = (
+/obj/structure/mirror{
+ pixel_x = -28
+ },
+/obj/machinery/shower{
+ dir = 4;
+ name = "emergency shower"
+ },
+/obj/machinery/newscaster{
+ pixel_y = 32
+ },
+/obj/machinery/door/window/southleft,
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
"aGG" = (
/obj/structure/cable/white{
icon_state = "4-8"
@@ -20909,6 +21234,97 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
+"aGY" = (
+/obj/structure/bed/dogbed/runtime,
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/delivery,
+/obj/structure/sign/poster/official/medical_green_cross{
+ pixel_x = -32
+ },
+/obj/machinery/camera{
+ c_tag = "CMO's Office";
+ dir = 4
+ },
+/mob/living/simple_animal/pet/cat/Runtime,
+/turf/open/floor/plasteel/dark,
+/area/crew_quarters/heads/cmo)
+"aGZ" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/loading_area,
+/obj/effect/turf_decal/stripes/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/corner{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 9
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
+"aHa" = (
+/obj/machinery/firealarm{
+ dir = 1;
+ pixel_y = -24
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/delivery,
+/obj/structure/table/glass,
+/obj/item/storage/firstaid/brute{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/storage/firstaid/brute{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/firstaid/regular,
+/obj/item/storage/firstaid/brute{
+ pixel_x = -3;
+ pixel_y = -3
+ },
+/obj/structure/window/reinforced/spawner/east,
+/obj/structure/window/reinforced/spawner/north,
+/turf/open/floor/plasteel,
+/area/medical/medbay/zone3)
+"aHb" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/closed/wall,
+/area/medical/morgue)
+"aHc" = (
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/machinery/door/window/southright,
+/obj/item/radio/intercom{
+ name = "Station Intercom";
+ pixel_y = 26
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
+"aHd" = (
+/obj/structure/window/reinforced,
+/obj/machinery/clonepod,
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
"aHe" = (
/obj/effect/turf_decal/bot_white/right,
/obj/effect/turf_decal/tile/neutral{
@@ -20923,6 +21339,15 @@
},
/turf/open/floor/plasteel/dark,
/area/engine/gravity_generator)
+"aHf" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "geneticsbot";
+ name = "Genetics Privacy Shutters"
+ },
+/turf/open/floor/plating,
+/area/medical/genetics)
"aHg" = (
/obj/machinery/camera{
c_tag = "Gravity Generator Room";
@@ -20945,6 +21370,17 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/engine/engineering)
+"aHi" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/door/airlock/grunge{
+ name = "Morgue";
+ req_access_txt = "5"
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aHj" = (
/obj/structure/cable/white{
icon_state = "4-8"
@@ -21078,6 +21514,11 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aHs" = (
+/obj/effect/turf_decal/tile/blue,
+/obj/machinery/vending/medical,
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aHt" = (
/obj/structure/cable/white{
icon_state = "4-8"
@@ -21281,6 +21722,37 @@
},
/turf/open/floor/plating,
/area/maintenance/port/central)
+"aHG" = (
+/obj/machinery/power/apc{
+ areastring = "/area/medical/genetics";
+ dir = 8;
+ name = "Genetics Lab APC";
+ pixel_x = -26;
+ pixel_y = 3
+ },
+/obj/structure/cable/white{
+ icon_state = "0-4"
+ },
+/obj/structure/table,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/button/door{
+ id = "geneticsbot";
+ name = "Genetics Shutter Control";
+ pixel_x = -24;
+ pixel_y = -8;
+ req_access_txt = "5; 9; 68"
+ },
+/obj/item/clothing/gloves/color/latex,
+/obj/item/storage/box/disks{
+ pixel_x = -2;
+ pixel_y = 4
+ },
+/obj/item/storage/box/rxglasses,
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
"aHH" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -21308,6 +21780,25 @@
},
/turf/open/floor/plating,
/area/maintenance/port/central)
+"aHJ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/obj/structure/chair/office/light{
+ dir = 4
+ },
+/obj/effect/landmark/start/geneticist,
+/turf/open/floor/plasteel{
+ heat_capacity = 1e+006
+ },
+/area/medical/genetics)
+"aHK" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/closed/wall,
+/area/medical/morgue)
"aHL" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/closed/wall,
@@ -21444,6 +21935,23 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/kitchen)
+"aHX" = (
+/obj/structure/sign/warning/nosmoking{
+ pixel_x = 32
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/computer/scan_consolenew{
+ dir = 8
+ },
+/obj/effect/turf_decal/bot,
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
"aHY" = (
/obj/structure/table,
/obj/item/paper_bin,
@@ -22083,6 +22591,66 @@
},
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/exit)
+"aJd" = (
+/obj/machinery/computer/cloning{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aJe" = (
+/obj/structure/table,
+/obj/machinery/airalarm/unlocked{
+ dir = 4;
+ pixel_x = -23
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/item/clipboard,
+/obj/item/folder/white,
+/obj/item/storage/pill_bottle/mutadone{
+ pixel_x = -8;
+ pixel_y = 8
+ },
+/obj/item/storage/pill_bottle/mannitol{
+ pixel_x = -8;
+ pixel_y = 2
+ },
+/obj/item/radio/headset/headset_medsci,
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
+"aJf" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
+ },
+/turf/open/floor/plasteel{
+ heat_capacity = 1e+006
+ },
+/area/medical/genetics)
+"aJg" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/dna_scannernew,
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/delivery,
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = 24
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
"aJh" = (
/obj/machinery/light{
dir = 8
@@ -22190,6 +22758,20 @@
},
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
+"aJo" = (
+/obj/item/radio/intercom{
+ name = "Station Intercom";
+ pixel_x = -26
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/machinery/vending/wardrobe/gene_wardrobe,
+/obj/effect/turf_decal/tile/purple{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
"aJp" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -22236,6 +22818,20 @@
/obj/machinery/atmospherics/pipe/simple/green/visible,
/turf/closed/wall/r_wall,
/area/engine/supermatter)
+"aJv" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/landmark/start/geneticist,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
"aJw" = (
/obj/machinery/atmospherics/components/binary/pump{
dir = 1;
@@ -22244,6 +22840,17 @@
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel/dark,
/area/engine/engineering)
+"aJx" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aJy" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -22266,6 +22873,22 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aJA" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/requests_console{
+ department = "Genetics";
+ name = "Genetics RC";
+ pixel_x = 28;
+ pixel_y = 0
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
"aJB" = (
/obj/structure/table/reinforced,
/obj/item/stack/sheet/metal/fifty,
@@ -22482,6 +23105,28 @@
},
/turf/open/floor/plasteel,
/area/hydroponics)
+"aJN" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/landmark/blobstart,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aJO" = (
+/obj/machinery/camera{
+ c_tag = "Genetics Cloning";
+ dir = 4
+ },
+/obj/machinery/airalarm{
+ dir = 4;
+ pixel_x = -22
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
"aJP" = (
/obj/effect/turf_decal/tile/blue{
dir = 1
@@ -22719,6 +23364,59 @@
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aKk" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aKl" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
+ },
+/area/maintenance/port/aft)
+"aKm" = (
+/turf/closed/wall,
+/area/maintenance/port/aft)
+"aKn" = (
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/closed/wall,
+/area/maintenance/port/aft)
+"aKo" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/door/airlock/external{
+ name = "External Airlock";
+ req_access_txt = "13"
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aKp" = (
/obj/machinery/airalarm{
dir = 4;
@@ -22755,6 +23453,18 @@
},
/turf/open/floor/plasteel/dark,
/area/engine/gravity_generator)
+"aKr" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
+/obj/effect/landmark/xeno_spawn,
+/obj/structure/sign/warning/vacuum{
+ pixel_x = -32;
+ pixel_y = 32
+ },
+/obj/effect/turf_decal/delivery,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aKs" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/command/glass{
@@ -22897,6 +23607,25 @@
},
/turf/open/floor/engine,
/area/engine/supermatter)
+"aKB" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/door/airlock/external{
+ name = "External Airlock";
+ req_access_txt = "13"
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aKC" = (
/obj/machinery/atmospherics/components/binary/pump{
name = "Gas to Chamber"
@@ -22915,6 +23644,16 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/dark,
/area/engine/engineering)
+"aKF" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/sign/warning/vacuum{
+ pixel_x = -32;
+ pixel_y = 32
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aKG" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -22962,6 +23701,12 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
+"aKJ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aKK" = (
/obj/structure/table/reinforced,
/obj/structure/cable/white{
@@ -23177,6 +23922,9 @@
},
/turf/open/floor/plasteel,
/area/hydroponics)
+"aKV" = (
+/turf/closed/wall/r_wall,
+/area/medical/virology)
"aKW" = (
/obj/machinery/seed_extractor,
/obj/effect/turf_decal/bot,
@@ -23431,6 +24179,56 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
+"aLn" = (
+/obj/machinery/smartfridge/chemistry/virology/preloaded,
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aLo" = (
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/structure/extinguisher_cabinet{
+ pixel_x = -26
+ },
+/obj/structure/disposalpipe/trunk,
+/obj/effect/turf_decal/stripes/red/full,
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/obj/machinery/disposal/bin{
+ name = "corpse disposal unit"
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aLp" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aLq" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aLr" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aLs" = (
+/turf/closed/wall/r_wall/rust,
+/area/maintenance/port/aft)
"aLt" = (
/obj/effect/turf_decal/tile/brown{
dir = 1
@@ -23441,6 +24239,77 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aLu" = (
+/obj/structure/disposalpipe/segment,
+/obj/structure/window/reinforced/spawner/north,
+/obj/machinery/door/window/eastright{
+ name = "Monkey Pen";
+ req_access_txt = "5; 9; 68"
+ },
+/turf/open/floor/plasteel/freezer,
+/area/medical/genetics)
+"aLv" = (
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aLw" = (
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/medical/virology)
+"aLx" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue,
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aLy" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plating{
+ icon_state = "platingdmg3"
+ },
+/area/maintenance/port/aft)
+"aLz" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/machinery/light/small,
+/obj/structure/closet/emcloset/anchored,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aLA" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/tile/purple,
+/obj/structure/chair/office/light,
+/obj/effect/landmark/start/geneticist,
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aLB" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aLC" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/item/cigbutt,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aLD" = (
/obj/machinery/power/port_gen/pacman,
/obj/effect/turf_decal/stripes/line{
@@ -23538,6 +24407,12 @@
/obj/item/clothing/glasses/meson/engine,
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
+"aLL" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating/airless,
+/area/maintenance/port/aft)
"aLM" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -23632,6 +24507,11 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aLX" = (
+/obj/structure/table/wood,
+/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aLY" = (
/obj/effect/turf_decal/tile/yellow{
dir = 1
@@ -23812,6 +24692,12 @@
},
/turf/open/floor/plasteel,
/area/hydroponics)
+"aMl" = (
+/obj/structure/disposalpipe/segment,
+/obj/structure/window/reinforced/spawner/east,
+/obj/item/storage/box/monkeycubes,
+/turf/open/floor/plasteel/freezer,
+/area/medical/genetics)
"aMm" = (
/obj/structure/cable/white{
icon_state = "2-4"
@@ -23931,6 +24817,48 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/bar/atrium)
+"aMv" = (
+/obj/structure/table/wood,
+/obj/item/clothing/gloves/color/black,
+/obj/item/taperecorder,
+/obj/machinery/light/small{
+ dir = 1
+ },
+/obj/structure/sign/poster/contraband/random{
+ pixel_y = 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{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aMw" = (
+/obj/structure/rack,
+/obj/item/storage/briefcase{
+ pixel_x = -3;
+ pixel_y = 3
+ },
+/obj/item/storage/secure/briefcase,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/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/maintenance/port/aft)
"aMx" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 10
@@ -23993,6 +24921,56 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aMD" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/structure/sign/poster/contraband/random,
+/turf/closed/wall,
+/area/maintenance/port/aft)
+"aME" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/reagent_dispensers/fueltank,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aMF" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/closet/crate,
+/obj/item/stack/ore/silver,
+/obj/item/stack/ore/iron,
+/obj/item/stack/ore/iron,
+/obj/item/stack/ore/iron,
+/obj/item/pickaxe/emergency,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aMG" = (
+/obj/structure/girder,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aMH" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aMI" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aMJ" = (
/turf/closed/wall/r_wall,
/area/tcommsat/server)
@@ -24057,6 +25035,22 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aMQ" = (
+/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
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aMR" = (
/obj/machinery/camera{
c_tag = "Supermatter Chamber";
@@ -24115,6 +25109,17 @@
},
/turf/open/floor/engine,
/area/engine/supermatter)
+"aMY" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/machinery/dna_scannernew,
+/obj/effect/turf_decal/delivery,
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
"aMZ" = (
/obj/structure/cable{
icon_state = "1-8"
@@ -24297,6 +25302,43 @@
},
/turf/open/floor/plasteel/dark,
/area/hydroponics)
+"aNo" = (
+/obj/machinery/light_switch{
+ pixel_x = -24;
+ pixel_y = -38
+ },
+/obj/machinery/button/door{
+ desc = "A remote control switch for the medbay foyer.";
+ id = "cloningfoyer";
+ name = "Cloning Doors Control";
+ normaldoorcontrol = 1;
+ pixel_x = -24;
+ pixel_y = -24
+ },
+/obj/structure/closet/crate/freezer/surplus_limbs,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aNp" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/door/airlock/medical/glass{
+ name = "Genetics";
+ req_access_txt = "5; 9; 68"
+ },
+/turf/open/floor/plasteel,
+/area/medical/genetics)
"aNq" = (
/obj/machinery/hydroponics/constructable,
/obj/structure/cable/white,
@@ -24514,6 +25556,94 @@
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
/area/hallway/secondary/exit)
+"aNL" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aNM" = (
+/obj/machinery/holopad,
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/bot,
+/obj/effect/landmark/start/geneticist,
+/turf/open/floor/plasteel,
+/area/medical/genetics)
+"aNN" = (
+/obj/machinery/dna_scannernew,
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aNO" = (
+/obj/machinery/camera{
+ c_tag = "Genetics Lab";
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/machinery/computer/scan_consolenew{
+ icon_state = "computer";
+ dir = 1
+ },
+/obj/effect/turf_decal/bot,
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
+"aNP" = (
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/medical/genetics)
+"aNQ" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/medical/glass{
+ id_tag = "cloningfoyer";
+ name = "Cloning Lab";
+ req_access_txt = "5"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/mapping_helpers/airlock/unres{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/medical/genetics)
+"aNR" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/open/floor/plating,
+/area/medical/genetics)
+"aNS" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment,
+/obj/effect/landmark/start/paramedic,
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aNT" = (
/obj/machinery/announcement_system,
/obj/machinery/status_display/ai{
@@ -24606,6 +25736,42 @@
/obj/machinery/power/supermatter_crystal/shard/engine,
/turf/open/floor/engine,
/area/engine/supermatter)
+"aOb" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
+/obj/machinery/requests_console{
+ announcementConsole = 1;
+ department = "Chief Medical Officer's Desk";
+ departmentType = 5;
+ name = "Chief Medical Officer RC";
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/heads/cmo)
+"aOc" = (
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aOd" = (
/obj/machinery/power/apc{
areastring = "/area/engine/engineering";
@@ -24619,6 +25785,29 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aOe" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/door/airlock/command{
+ name = "Chief Medical Officer's Office";
+ req_access_txt = "40"
+ },
+/obj/machinery/door/firedoor,
+/obj/structure/cable/white{
+ icon_state = "2-8"
+ },
+/turf/open/floor/plasteel,
+/area/crew_quarters/heads/cmo)
"aOf" = (
/obj/machinery/door/airlock{
name = "Custodial Closet";
@@ -24634,6 +25823,24 @@
},
/turf/open/floor/plasteel,
/area/janitor)
+"aOg" = (
+/obj/structure/cable/white{
+ icon_state = "2-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/newscaster{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aOh" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -24660,6 +25867,19 @@
/obj/structure/sign/departments/botany,
/turf/closed/wall,
/area/hydroponics)
+"aOl" = (
+/obj/structure/closet/secure_closet/CMO,
+/obj/machinery/airalarm{
+ dir = 4;
+ pixel_x = -22
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/bot,
+/turf/open/floor/plasteel/dark,
+/area/crew_quarters/heads/cmo)
"aOm" = (
/obj/item/kirbyplants{
icon_state = "plant-21"
@@ -24733,6 +25953,13 @@
},
/turf/closed/wall,
/area/hallway/primary/central)
+"aOs" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/structure/rack,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aOt" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall,
@@ -24823,6 +26050,24 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aOA" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/medical/genetics)
+"aOB" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
"aOC" = (
/obj/machinery/atmospherics/pipe/simple/general/visible{
dir = 5
@@ -24849,6 +26094,22 @@
},
/turf/open/floor/circuit/green,
/area/engine/supermatter)
+"aOE" = (
+/obj/structure/cable/white{
+ icon_state = "2-4"
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/landmark/event_spawn,
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aOF" = (
/obj/structure/cable{
icon_state = "1-8"
@@ -24870,60 +26131,101 @@
/turf/open/floor/engine,
/area/engine/engineering)
"aOH" = (
-/turf/closed/wall/r_wall,
-/area/maintenance/port)
-"aOI" = (
/obj/structure/cable/white{
- icon_state = "2-4"
+ icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 6
- },
-/obj/effect/decal/cleanable/cobweb,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"aOL" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 4
},
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/maintenance/port)
-"aOM" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"aON" = (
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
/obj/effect/turf_decal/stripes/line{
dir = 8
},
-/obj/effect/turf_decal/stripes/line{
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aOI" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 6
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aOJ" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
+"aOK" = (
+/obj/machinery/light/small{
+ dir = 4
+ },
+/obj/machinery/computer/card/minor/cmo{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/keycard_auth{
+ pixel_x = 24;
+ pixel_y = -24
+ },
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = 24;
+ pixel_y = -6
+ },
+/obj/machinery/computer/security/telescreen/cmo{
+ dir = 1;
+ icon_state = "telescreen";
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/heads/cmo)
+"aOL" = (
+/obj/structure/table/wood,
+/obj/item/flashlight/lamp,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aOM" = (
+/obj/structure/table/wood,
+/obj/item/paper_bin,
+/obj/item/pen,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aON" = (
+/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
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aOO" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -24962,49 +26264,49 @@
heat_capacity = 1e+006
},
/area/hallway/primary/port/aft)
-"aOR" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/obj/structure/cable/white{
- icon_state = "2-4"
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
+"aOQ" = (
+/obj/machinery/suit_storage_unit/cmo,
/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
-"aOS" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
-"aOT" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/delivery,
+/turf/open/floor/plasteel/dark,
+/area/crew_quarters/heads/cmo)
+"aOR" = (
+/obj/structure/table/glass,
+/obj/item/storage/box/bodybags{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/box/bodybags,
+/obj/item/pen,
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = 24
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
+ },
+/obj/effect/turf_decal/tile/purple,
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
+"aOS" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 4
+ },
+/turf/closed/wall,
+/area/maintenance/port/aft)
+"aOT" = (
/obj/structure/cable/white{
- icon_state = "1-8"
+ icon_state = "1-4"
},
-/obj/structure/cable/white{
- icon_state = "4-8"
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aOU" = (
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
@@ -25023,92 +26325,77 @@
/turf/open/floor/plasteel,
/area/hallway/primary/port/aft)
"aOV" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/structure/extinguisher_cabinet{
- pixel_y = 26
+/obj/effect/landmark/blobstart,
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
},
-/obj/structure/cable/white{
- icon_state = "4-8"
+/area/maintenance/port/aft)
+"aOW" = (
+/obj/structure/disposalpipe/segment,
+/turf/closed/wall,
+/area/medical/genetics)
+"aOX" = (
+/obj/machinery/requests_console{
+ department = "Medbay";
+ departmentType = 1;
+ name = "Medbay RC";
+ pixel_x = -30
},
/obj/machinery/camera{
- c_tag = "Aft Primary Hallway 4"
- },
-/obj/effect/turf_decal/tile/green{
- dir = 1
+ c_tag = "Medbay Storage"
},
+/obj/machinery/rnd/production/techfab/department/medical,
+/obj/effect/turf_decal/bot,
+/obj/effect/turf_decal/stripes/box,
+/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
-"aOW" = (
-/obj/machinery/light{
- dir = 1
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/obj/item/radio/intercom{
- name = "Station Intercom";
- pixel_y = 24
- },
+/area/medical/medbay/zone3)
+"aOY" = (
/obj/structure/cable/white{
- icon_state = "2-8"
+ icon_state = "1-2"
},
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/turf_decal/tile/purple{
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/blue{
dir = 1
},
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/landmark/start/medical_doctor,
/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
-"aOX" = (
+/area/medical/medbay/zone3)
+"aOZ" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
+/obj/structure/cable/white{
+ icon_state = "0-4"
+ },
/obj/machinery/power/apc{
- areastring = "/area/hallway/primary/port/aft";
+ areastring = "/area/crew_quarters/heads/cmo";
dir = 1;
- name = "Port Quarter Hallway APC";
- pixel_y = 24
+ name = "CMO's Office APC";
+ pixel_y = 26
},
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "0-8"
- },
-/obj/effect/turf_decal/tile/green{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
-"aOY" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "1-8"
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
-"aOZ" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port/aft)
+/obj/effect/landmark/start/chief_medical_officer,
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/heads/cmo)
"aPa" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -25191,6 +26478,21 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"aPg" = (
+/obj/item/kirbyplants{
+ icon_state = "plant-22"
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 6
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/zone3)
"aPh" = (
/obj/machinery/light{
dir = 1
@@ -25394,6 +26696,34 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
+"aPv" = (
+/obj/structure/table/glass,
+/obj/item/storage/firstaid/o2{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/storage/firstaid/o2{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/firstaid/regular,
+/obj/item/storage/firstaid/o2{
+ pixel_x = -3;
+ pixel_y = -3
+ },
+/obj/structure/cable/white,
+/obj/effect/turf_decal/delivery,
+/obj/machinery/power/apc{
+ areastring = "/area/medical/medbay/zone3";
+ name = "Medbay APC";
+ pixel_y = -26
+ },
+/obj/machinery/door/window/northleft{
+ name = "First-Aid Supplies";
+ req_access_txt = "5"
+ },
+/turf/open/floor/plasteel,
+/area/medical/medbay/zone3)
"aPw" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -25432,10 +26762,141 @@
},
/turf/open/floor/plasteel/dark,
/area/hallway/primary/starboard)
+"aPz" = (
+/obj/effect/turf_decal/delivery,
+/obj/structure/window/reinforced/spawner/west,
+/obj/structure/window/reinforced/spawner/north,
+/obj/structure/table/glass,
+/obj/item/storage/firstaid/toxin{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/storage/firstaid/toxin{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/firstaid/regular,
+/obj/item/storage/firstaid/toxin{
+ pixel_x = -3;
+ pixel_y = -3
+ },
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/obj/structure/disposalpipe/segment,
+/turf/open/floor/plasteel,
+/area/medical/medbay/zone3)
+"aPA" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/door/airlock/grunge{
+ name = "Morgue";
+ req_access_txt = "5"
+ },
+/obj/machinery/door/firedoor,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aPB" = (
+/obj/structure/disposalpipe/segment,
+/turf/closed/wall,
+/area/medical/morgue)
+"aPC" = (
+/obj/machinery/computer/security/telescreen/entertainment,
+/obj/structure/bodycontainer/morgue{
+ icon_state = "morgue1";
+ dir = 2
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aPD" = (
+/obj/machinery/light,
+/obj/structure/noticeboard{
+ dir = 1;
+ pixel_y = -32
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
+ },
+/obj/effect/turf_decal/delivery,
+/obj/structure/table/glass,
+/obj/item/storage/firstaid/fire{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/storage/firstaid/fire{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/firstaid/regular,
+/obj/item/storage/firstaid/fire{
+ pixel_x = -3;
+ pixel_y = -3
+ },
+/obj/machinery/door/window/northright{
+ name = "First-Aid Supplies";
+ req_access_txt = "5"
+ },
+/turf/open/floor/plasteel,
+/area/medical/medbay/zone3)
+"aPE" = (
+/obj/structure/bodycontainer/morgue{
+ icon_state = "morgue1";
+ dir = 2
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aPF" = (
+/obj/structure/chair/office/light{
+ dir = 4
+ },
+/obj/effect/landmark/start/chief_medical_officer,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/heads/cmo)
"aPG" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/tcommsat/server)
+"aPH" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/structure/disposalpipe/trunk{
+ dir = 1
+ },
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = 24
+ },
+/obj/structure/disposaloutlet{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aPI" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -25497,89 +26958,69 @@
/turf/open/floor/engine,
/area/engine/engineering)
"aPO" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 1
},
-/turf/closed/wall/r_wall,
-/area/maintenance/port)
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/cable/white{
+ icon_state = "2-4"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aPP" = (
/obj/structure/cable/white{
- icon_state = "1-2"
+ icon_state = "1-8"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"aPQ" = (
-/obj/structure/closet,
-/obj/effect/spawner/lootdrop/maintenance{
- lootcount = 3;
- name = "3maintenance loot spawner"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/delivery,
-/obj/effect/turf_decal/stripes/line{
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
},
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"aPR" = (
-/obj/structure/girder,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
+"aPQ" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aPR" = (
+/turf/open/floor/wood{
+ icon_state = "wood-broken5"
+ },
+/area/maintenance/port/aft)
"aPS" = (
-/obj/structure/closet/firecloset,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/delivery,
-/obj/effect/turf_decal/stripes/line{
+/obj/effect/landmark/xeno_spawn,
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"aPT" = (
-/obj/structure/rack,
-/obj/item/reagent_containers/food/drinks/bottle/whiskey,
-/obj/effect/spawner/lootdrop/maintenance,
-/obj/machinery/light/small,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/turf/open/floor/wood{
+ icon_state = "wood-broken6"
},
-/obj/effect/turf_decal/delivery,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"aPU" = (
-/obj/structure/rack,
-/obj/effect/spawner/lootdrop/maintenance{
- lootcount = 2;
- name = "2maintenance loot spawner"
- },
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/delivery,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"aPV" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+ dir = 5
},
/turf/closed/wall,
-/area/maintenance/port)
+/area/maintenance/port/aft)
+"aPV" = (
+/obj/structure/barricade/wooden,
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aPW" = (
/obj/machinery/vending/snack/random,
/obj/machinery/firealarm{
@@ -25696,16 +27137,18 @@
},
/area/hallway/primary/port/aft)
"aQe" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
+/obj/structure/table/glass,
+/obj/effect/turf_decal/tile/blue{
dir = 8
},
-/turf/open/floor/plasteel{
- heat_capacity = 1e+006
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
-/area/hallway/primary/port/aft)
+/obj/item/paper_bin,
+/obj/item/pen,
+/obj/item/stamp/cmo,
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/heads/cmo)
"aQf" = (
/obj/machinery/firealarm{
dir = 1;
@@ -25730,6 +27173,39 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"aQh" = (
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/machinery/airalarm{
+ dir = 4;
+ pixel_x = -22
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aQi" = (
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aQj" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
/obj/effect/turf_decal/tile/yellow{
@@ -25912,6 +27388,94 @@
},
/turf/open/floor/plasteel/dark,
/area/hallway/primary/starboard)
+"aQB" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/sign/poster/contraband/random,
+/turf/closed/wall,
+/area/maintenance/port/aft)
+"aQC" = (
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aQD" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/structure/cable/white{
+ icon_state = "2-4"
+ },
+/obj/effect/landmark/blobstart,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aQE" = (
+/obj/machinery/light/small{
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "0-8"
+ },
+/obj/structure/table/wood,
+/obj/item/storage/box/bodybags{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/box/bodybags,
+/obj/machinery/power/apc{
+ areastring = "/area/medical/morgue";
+ dir = 4;
+ name = "Morgue APC";
+ pixel_x = 26
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/machinery/camera{
+ c_tag = "Morgue";
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aQF" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/closed/wall/rust,
+/area/maintenance/port/aft)
"aQG" = (
/obj/machinery/atmospherics/pipe/simple/general/visible{
dir = 6
@@ -25950,6 +27514,19 @@
},
/turf/open/floor/plasteel/grimy,
/area/tcommsat/server)
+"aQI" = (
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aQJ" = (
/obj/machinery/meter,
/obj/effect/turf_decal/stripes/corner{
@@ -25969,6 +27546,17 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aQL" = (
+/obj/structure/table/wood,
+/obj/item/clothing/gloves/color/latex,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aQM" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -26010,6 +27598,14 @@
},
/turf/open/floor/engine,
/area/engine/engineering)
+"aQQ" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/barricade/wooden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aQR" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -26038,9 +27634,39 @@
/turf/open/floor/engine,
/area/engine/engineering)
"aQU" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall/r_wall,
-/area/maintenance/port)
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aQV" = (
+/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
+ },
+/obj/machinery/computer/arcade{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aQW" = (
/turf/closed/wall,
/area/library)
@@ -26083,30 +27709,17 @@
/turf/closed/wall,
/area/medical/morgue)
"aRc" = (
-/obj/effect/spawner/structure/window/reinforced/tinted,
-/turf/open/floor/plating,
-/area/medical/morgue)
+/obj/structure/chair/stool/bar,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"aRd" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/grunge{
- name = "Morgue";
- req_access_txt = "5"
- },
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/medical/morgue)
+/obj/effect/decal/cleanable/blood/splatter,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"aRe" = (
-/obj/effect/spawner/structure/window/reinforced/tinted,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plating,
-/area/medical/morgue)
+/turf/closed/wall/r_wall,
+/area/medical/virology)
"aRf" = (
/turf/closed/wall,
/area/medical/chemistry)
@@ -26138,6 +27751,11 @@
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
/area/medical/chemistry)
+"aRj" = (
+/turf/open/floor/wood{
+ icon_state = "wood-broken2"
+ },
+/area/maintenance/port/aft)
"aRk" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/camera{
@@ -26153,6 +27771,44 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"aRl" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/cable/white,
+/turf/open/floor/plating,
+/area/crew_quarters/heads/cmo)
+"aRm" = (
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
+"aRn" = (
+/obj/structure/chair/stool/bar,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aRo" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/newscaster{
+ pixel_y = -32
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/holopad,
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/heads/cmo)
+"aRp" = (
+/obj/structure/bodycontainer/morgue{
+ icon_state = "morgue1";
+ dir = 2
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aRq" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/tile/purple,
@@ -26214,6 +27870,20 @@
},
/turf/open/floor/plasteel,
/area/science/research)
+"aRw" = (
+/obj/structure/bodycontainer/morgue{
+ icon_state = "morgue1";
+ dir = 2
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
"aRx" = (
/obj/machinery/door/airlock/maintenance_hatch{
name = "Maintenance Hatch";
@@ -26236,6 +27906,38 @@
"aRz" = (
/turf/closed/wall,
/area/maintenance/starboard)
+"aRA" = (
+/obj/structure/table/glass,
+/obj/effect/turf_decal/tile/green{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/green{
+ dir = 1
+ },
+/obj/structure/reagent_dispensers/virusfood{
+ pixel_x = -32
+ },
+/obj/item/storage/box/beakers{
+ pixel_x = -6;
+ pixel_y = 8
+ },
+/obj/item/storage/box/monkeycubes{
+ pixel_x = 4;
+ pixel_y = 6
+ },
+/obj/item/storage/box/syringes{
+ pixel_x = -3;
+ pixel_y = 2
+ },
+/obj/item/reagent_containers/dropper{
+ pixel_y = -8
+ },
+/obj/item/reagent_containers/syringe/antiviral{
+ pixel_x = 2;
+ pixel_y = -10
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
"aRB" = (
/obj/effect/turf_decal/bot,
/obj/structure/table,
@@ -26248,6 +27950,10 @@
},
/turf/open/floor/plasteel/dark,
/area/tcommsat/server)
+"aRC" = (
+/obj/machinery/computer/slot_machine,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aRD" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -26391,14 +28097,12 @@
/turf/open/floor/engine,
/area/engine/engineering)
"aRS" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
+/obj/machinery/vending/cigarette,
+/obj/machinery/newscaster{
+ pixel_x = -32
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plating{
- icon_state = "platingdmg2"
- },
-/area/maintenance/port)
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aRT" = (
/obj/structure/table/wood,
/obj/item/flashlight/lamp,
@@ -26427,6 +28131,23 @@
},
/turf/open/floor/plasteel/dark,
/area/library)
+"aRV" = (
+/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
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aRW" = (
/obj/structure/chair/office/dark{
dir = 4
@@ -26518,44 +28239,31 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aSe" = (
-/obj/structure/bodycontainer/morgue,
-/obj/effect/decal/cleanable/cobweb,
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
+/obj/machinery/vending/wallmed{
+ pixel_y = 32
+ },
+/obj/effect/turf_decal/tile/green{
dir = 4
},
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/obj/effect/turf_decal/tile/green{
+ dir = 1
+ },
+/obj/machinery/holopad,
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
"aSf" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/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{
+/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aSg" = (
-/obj/structure/sign/warning/nosmoking{
- pixel_x = 32
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/obj/item/cigbutt,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aSh" = (
/turf/closed/wall,
/area/medical/medbay/zone3)
@@ -26582,26 +28290,11 @@
/turf/open/floor/plasteel,
/area/medical/chemistry)
"aSk" = (
-/obj/machinery/light{
- dir = 1
- },
-/obj/machinery/power/apc/highcap/five_k{
- areastring = "/area/medical/chemistry";
- dir = 1;
- name = "Chemistry Lab APC";
- pixel_y = 25
- },
/obj/structure/cable/white{
- icon_state = "0-2"
- },
-/obj/item/kirbyplants{
- icon_state = "plant-21"
- },
-/obj/machinery/camera{
- c_tag = "Chemistry"
+ icon_state = "1-2"
},
/obj/effect/turf_decal/tile/yellow{
- dir = 1
+ dir = 8
},
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
@@ -26615,6 +28308,19 @@
/obj/item/storage/pill_bottle/mutadone,
/turf/open/floor/plasteel,
/area/medical/chemistry)
+"aSm" = (
+/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/maintenance/port/aft)
"aSn" = (
/obj/machinery/chem_dispenser,
/obj/machinery/button/door{
@@ -26629,6 +28335,54 @@
},
/turf/open/floor/plasteel,
/area/medical/chemistry)
+"aSo" = (
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/landmark/event_spawn,
+/turf/open/floor/plasteel/dark,
+/area/medical/morgue)
+"aSp" = (
+/obj/structure/table/glass,
+/obj/machinery/reagentgrinder{
+ pixel_y = 5
+ },
+/obj/effect/turf_decal/tile/green{
+ dir = 8
+ },
+/obj/item/reagent_containers/spray/cleaner{
+ pixel_x = -8;
+ pixel_y = 2
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aSq" = (
+/obj/structure/table/wood,
+/obj/item/storage/briefcase,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aSr" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aSs" = (
+/obj/structure/chair/stool/bar,
+/turf/open/floor/wood{
+ icon_state = "wood-broken"
+ },
+/area/maintenance/port/aft)
"aSt" = (
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
@@ -26761,10 +28515,43 @@
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plasteel,
/area/maintenance/starboard/aft)
+"aSG" = (
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aSH" = (
/obj/structure/sign/poster/contraband/random,
/turf/closed/wall,
/area/maintenance/starboard)
+"aSI" = (
+/obj/structure/chair/stool/bar,
+/turf/open/floor/wood{
+ icon_state = "wood-broken5"
+ },
+/area/maintenance/port/aft)
+"aSJ" = (
+/obj/structure/chair/office/light,
+/obj/effect/landmark/start/virologist,
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aSK" = (
+/obj/effect/turf_decal/tile/green{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/green,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aSL" = (
+/obj/structure/chair/stool/bar,
+/turf/open/floor/wood{
+ icon_state = "wood-broken2"
+ },
+/area/maintenance/port/aft)
"aSM" = (
/obj/machinery/door/airlock/command{
name = "Telecomms Server Room";
@@ -26810,6 +28597,22 @@
/obj/machinery/vending/wardrobe/engi_wardrobe,
/turf/open/floor/engine,
/area/engine/engineering)
+"aSQ" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aSR" = (
/obj/structure/table/reinforced,
/obj/item/tank/internals/plasma,
@@ -26909,12 +28712,15 @@
/turf/open/floor/engine,
/area/engine/engineering)
"aTb" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
+/obj/structure/table/wood,
+/obj/item/toy/cards/deck/syndicate{
+ pixel_y = 6
+ },
+/obj/machinery/light/small{
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
"aTc" = (
/obj/structure/chair/office/dark{
dir = 8
@@ -26988,96 +28794,90 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aTj" = (
-/obj/structure/table,
-/obj/item/storage/box/bodybags{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/box/bodybags,
-/obj/machinery/airalarm/unlocked{
- dir = 4;
- pixel_x = -23
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aTk" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+/obj/effect/turf_decal/tile/green{
dir = 4
},
-/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/medical/morgue)
-"aTl" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
-"aTm" = (
-/obj/structure/mirror{
- pixel_x = -28
- },
-/obj/machinery/shower{
- dir = 4;
- name = "emergency shower"
- },
-/obj/machinery/newscaster{
- pixel_y = 32
- },
-/obj/machinery/door/window/southleft,
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/medbay/zone3)
-"aTn" = (
/obj/machinery/light{
dir = 1
},
-/obj/machinery/door/window/southright,
-/obj/item/radio/intercom{
- name = "Station Intercom";
+/obj/structure/closet/secure_closet/medical1,
+/obj/item/radio/headset/headset_med,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
+ },
+/obj/machinery/airalarm{
+ pixel_y = 23
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aTl" = (
+/obj/machinery/vending/wardrobe/viro_wardrobe,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/structure/extinguisher_cabinet{
pixel_y = 26
},
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/medical/virology)
+"aTm" = (
+/obj/structure/table/glass,
+/obj/effect/turf_decal/tile/green{
dir = 8
},
-/turf/open/floor/plasteel/dark,
-/area/medical/medbay/zone3)
+/obj/effect/turf_decal/tile/green,
+/obj/item/paper_bin,
+/obj/item/pen,
+/obj/item/book/manual/wiki/infections{
+ pixel_x = -15;
+ pixel_y = 2
+ },
+/obj/item/stack/sheet/mineral/plasma{
+ pixel_x = -12
+ },
+/obj/item/stack/sheet/mineral/plasma{
+ pixel_x = -14;
+ pixel_y = 3
+ },
+/obj/item/hand_labeler,
+/obj/item/clothing/gloves/color/latex,
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aTn" = (
+/obj/effect/landmark/start/virologist,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/power/apc/highcap/five_k{
+ areastring = "/area/medical/virology";
+ dir = 1;
+ name = "Virology APC";
+ pixel_y = 24
+ },
+/obj/structure/cable/white{
+ icon_state = "0-4"
+ },
+/obj/machinery/camera{
+ c_tag = "Virology"
+ },
+/turf/open/floor/plasteel,
+/area/medical/virology)
"aTo" = (
-/obj/structure/window/reinforced,
-/obj/machinery/clonepod,
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/medbay/zone3)
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/closed/wall/r_wall,
+/area/medical/virology)
"aTp" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -27092,11 +28892,12 @@
/area/medical/chemistry)
"aTr" = (
/obj/structure/cable/white{
- icon_state = "1-2"
+ icon_state = "1-4"
},
/obj/effect/turf_decal/tile/yellow{
- dir = 1
+ dir = 8
},
+/obj/effect/landmark/start/chemist,
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"aTs" = (
@@ -27117,6 +28918,19 @@
/obj/machinery/chem_master,
/turf/open/floor/plasteel,
/area/medical/chemistry)
+"aTv" = (
+/obj/machinery/airalarm{
+ dir = 4;
+ pixel_x = -22
+ },
+/obj/machinery/light/small{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 1
+ },
+/turf/open/floor/plasteel/freezer,
+/area/medical/virology)
"aTw" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/effect/turf_decal/tile/blue{
@@ -27325,6 +29139,12 @@
icon_state = "platingdmg1"
},
/area/maintenance/starboard/aft)
+"aTQ" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 8
+ },
+/turf/closed/wall/r_wall,
+/area/medical/virology)
"aTR" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -27359,6 +29179,40 @@
icon_state = "panelscorched"
},
/area/maintenance/starboard/aft)
+"aTU" = (
+/obj/structure/sign/poster/contraband/random,
+/turf/closed/wall/rust,
+/area/maintenance/port/aft)
+"aTV" = (
+/obj/structure/table/wood,
+/obj/item/wrench,
+/obj/item/storage/secure/briefcase{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/storage/briefcase,
+/obj/machinery/light/small{
+ 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/maintenance/port/aft)
+"aTW" = (
+/obj/structure/bed,
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
+/turf/open/floor/plasteel/freezer,
+/area/medical/virology)
"aTX" = (
/obj/machinery/light{
dir = 8
@@ -27421,13 +29275,23 @@
/turf/closed/wall/r_wall/rust,
/area/engine/engineering)
"aUb" = (
+/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
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/landmark/event_spawn,
/obj/structure/cable/white{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/landmark/blobstart,
-/turf/open/floor/plating,
-/area/maintenance/port)
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aUc" = (
/obj/machinery/power/apc{
areastring = "/area/library";
@@ -27478,74 +29342,114 @@
/turf/open/floor/wood,
/area/library)
"aUh" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "1-8"
- },
-/turf/open/floor/wood,
-/area/library)
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
+/turf/closed/wall/r_wall,
+/area/medical/virology)
"aUi" = (
-/obj/structure/cable/white{
- icon_state = "2-8"
- },
-/turf/open/floor/wood,
-/area/library)
+/turf/closed/wall/rust,
+/area/maintenance/port/aft)
"aUj" = (
/obj/machinery/photocopier,
/turf/open/floor/plasteel/dark,
/area/library)
"aUk" = (
-/obj/structure/bodycontainer/morgue,
-/obj/item/radio/intercom{
- name = "Station Intercom";
- pixel_x = -26
+/obj/structure/table/wood,
+/obj/item/storage/pill_bottle,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aUl" = (
+/obj/machinery/computer/slot_machine,
+/obj/machinery/light/small,
+/obj/structure/sign/poster/contraband/random{
+ pixel_y = -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{
+ dir = 8
+ },
/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/area/maintenance/port/aft)
+"aUm" = (
+/obj/machinery/computer/slot_machine,
+/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/maintenance/port/aft)
"aUn" = (
/obj/effect/spawner/structure/window/reinforced/tinted,
/turf/open/floor/plating,
/area/medical/medbay/zone3)
"aUo" = (
-/obj/machinery/camera{
- c_tag = "Genetics Cloning";
- dir = 4
+/obj/structure/table/wood,
+/obj/item/coin/iron{
+ icon_state = "coin_bananium_heads";
+ name = "arcade coin";
+ pixel_x = 6
},
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -22
+/obj/item/coin/iron{
+ icon_state = "coin_bananium_heads";
+ name = "arcade coin";
+ pixel_x = -6
},
-/obj/effect/turf_decal/tile/blue{
- dir = 1
+/obj/item/coin/iron{
+ icon_state = "coin_bananium_heads";
+ name = "arcade coin";
+ pixel_y = 6
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/obj/item/instrument/guitar,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aUp" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/obj/effect/turf_decal/tile/blue{
+/obj/structure/table/wood,
+/obj/item/reagent_containers/blood/random,
+/obj/item/reagent_containers/syringe{
+ pixel_y = 5
+ },
+/obj/item/reagent_containers/syringe,
+/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/effect/turf_decal/tile/blue{
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
dir = 4
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
-"aUq" = (
-/obj/machinery/computer/cloning{
+/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/tile/blue{
- dir = 4
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aUq" = (
+/obj/structure/table/wood,
+/obj/item/clipboard,
+/obj/item/toy/syndicateballoon,
+/obj/item/newspaper,
+/obj/item/clothing/head/bowler,
+/obj/machinery/power/apc{
+ areastring = "/area/maintenance/port/aft";
+ dir = 8;
+ name = "Port Quarter Maintenance APC";
+ pixel_x = -26;
+ pixel_y = 3
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/obj/structure/cable/white{
+ icon_state = "0-4"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aUr" = (
/obj/machinery/status_display,
/turf/closed/wall,
@@ -27563,27 +29467,41 @@
/turf/open/floor/plasteel/dark,
/area/medical/chemistry)
"aUt" = (
+/obj/effect/turf_decal/bot,
+/obj/machinery/holopad,
/obj/structure/cable/white{
- icon_state = "1-4"
+ icon_state = "4-8"
},
-/obj/effect/turf_decal/tile/yellow{
+/turf/open/floor/plasteel,
+/area/medical/chemistry)
+"aUu" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
},
-/turf/open/floor/plasteel/white,
-/area/medical/chemistry)
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aUv" = (
-/obj/machinery/holopad,
/obj/structure/cable/white{
icon_state = "2-8"
},
-/obj/effect/turf_decal/bot,
-/turf/open/floor/plasteel,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/effect/landmark/start/chemist,
+/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"aUw" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/obj/effect/turf_decal/tile/yellow{
dir = 4
},
+/obj/structure/closet/crate/bin,
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"aUx" = (
@@ -27722,6 +29640,73 @@
},
/turf/closed/wall/r_wall,
/area/science/research)
+"aUJ" = (
+/obj/machinery/computer/security/telescreen/entertainment{
+ pixel_y = -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{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aUK" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/machinery/door/airlock/virology{
+ name = "Virology Access";
+ req_access_txt = "39"
+ },
+/obj/machinery/door/firedoor,
+/turf/open/floor/plasteel,
+/area/medical/virology)
+"aUL" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aUM" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Medbay Maintenance";
+ req_access_txt = "5"
+ },
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aUN" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aUO" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -27824,18 +29809,22 @@
/turf/open/floor/wood,
/area/library)
"aUZ" = (
-/obj/effect/landmark/barthpot,
-/turf/open/floor/wood,
-/area/library)
-"aVa" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 10
+ dir = 4
},
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aVa" = (
/obj/structure/cable/white{
- icon_state = "1-2"
+ icon_state = "1-4"
},
-/turf/open/floor/wood,
-/area/library)
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aVb" = (
/obj/structure/table/wood,
/obj/item/storage/crayons,
@@ -27860,117 +29849,109 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aVc" = (
-/obj/structure/bodycontainer/morgue,
-/obj/machinery/light{
- dir = 8
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
-"aVd" = (
/obj/structure/cable/white{
- icon_state = "1-2"
+ icon_state = "2-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/structure/cable/white{
+ icon_state = "2-4"
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- 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/stripes/line,
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
+/area/maintenance/port/aft)
+"aVd" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
},
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/obj/structure/cable/white{
+ icon_state = "2-4"
+ },
+/obj/structure/cable/white{
+ icon_state = "2-8"
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aVe" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aVf" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/grunge{
- name = "Morgue";
- req_access_txt = "5"
+/obj/structure/cable/white{
+ icon_state = "4-8"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
+/obj/structure/cable/white{
+ icon_state = "1-8"
},
+/obj/structure/cable/white{
+ icon_state = "1-4"
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
-"aVg" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
-/obj/effect/turf_decal/tile/blue{
dir = 1
},
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aVg" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating{
+ icon_state = "platingdmg3"
+ },
+/area/maintenance/port/aft)
"aVh" = (
-/obj/machinery/holopad,
-/obj/effect/landmark/start/medical_doctor,
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 4
+/obj/structure/cable/white{
+ icon_state = "2-8"
},
-/obj/effect/turf_decal/bot,
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aVi" = (
-/obj/machinery/dna_scannernew,
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/area/maintenance/port/aft)
"aVj" = (
-/obj/structure/table/glass,
-/obj/item/stack/sheet/mineral/plasma,
-/obj/item/stack/sheet/mineral/plasma,
-/obj/item/stack/sheet/mineral/plasma,
-/obj/item/reagent_containers/glass/bottle/charcoal{
- pixel_x = 6
+/obj/machinery/chem_master,
+/obj/effect/turf_decal/stripes/line{
+ dir = 9
},
-/obj/item/reagent_containers/glass/bottle/epinephrine,
-/obj/item/reagent_containers/dropper,
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/plasteel,
/area/medical/chemistry)
-"aVl" = (
-/obj/effect/turf_decal/tile/yellow{
- dir = 8
+"aVk" = (
+/obj/structure/closet/emcloset,
+/obj/effect/turf_decal/stripes/line{
+ dir = 10
},
-/turf/open/floor/plasteel/white,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aVl" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
/area/medical/chemistry)
"aVm" = (
/obj/structure/cable/white{
@@ -27981,16 +29962,11 @@
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"aVn" = (
-/obj/structure/closet/crate/bin,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/requests_console{
- department = "Chemistry Lab";
- name = "Chemistry RC";
- pixel_x = 32;
- receive_ore_updates = 1
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
},
-/obj/effect/turf_decal/tile/yellow,
-/turf/open/floor/plasteel/white,
+/obj/machinery/chem_heater,
+/turf/open/floor/plasteel,
/area/medical/chemistry)
"aVo" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
@@ -28179,6 +30155,39 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/science/research)
+"aVF" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aVG" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aVH" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aVI" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aVJ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
+ },
+/obj/structure/cable/white{
+ icon_state = "2-4"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aVK" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 6
@@ -28194,14 +30203,14 @@
/turf/open/space,
/area/asteroid/nearstation)
"aVM" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 9
+ },
/obj/structure/cable/white{
- icon_state = "1-2"
+ icon_state = "1-8"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/maintenance/port)
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aVN" = (
/obj/structure/table/wood,
/obj/item/storage/bag/books,
@@ -28245,9 +30254,15 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aVR" = (
-/obj/structure/bookcase/random/fiction,
-/turf/open/floor/plasteel/dark,
-/area/library)
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/structure/reagent_dispensers/watertank,
+/obj/machinery/light/small{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aVS" = (
/obj/structure/bookcase/random/fiction,
/obj/effect/turf_decal/tile/neutral{
@@ -28287,22 +30302,15 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aVW" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/effect/turf_decal/tile/neutral{
+/obj/structure/rack,
+/obj/item/storage/toolbox/mechanical,
+/obj/item/clothing/head/welding,
+/obj/machinery/light/small,
+/obj/effect/turf_decal/stripes/line{
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)
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aVX" = (
/obj/structure/easel,
/obj/item/canvas/twentythreeXnineteen,
@@ -28314,24 +30322,18 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aVY" = (
-/obj/structure/table,
-/obj/item/clothing/gloves/color/latex,
-/obj/structure/extinguisher_cabinet{
- pixel_x = -26
+/obj/machinery/door/airlock/grunge{
+ name = "Crematorium";
+ req_access_txt = "27"
},
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
-"aVZ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/cable/white{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
+/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
@@ -28343,19 +30345,39 @@
dir = 8
},
/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
-"aWa" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
+/area/maintenance/port/aft)
+"aVZ" = (
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
},
-/obj/effect/turf_decal/tile/neutral{
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aWa" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
},
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/obj/effect/turf_decal/bot,
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/obj/item/storage/backpack,
+/obj/item/crowbar,
+/obj/item/wrench,
+/obj/structure/rack,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aWb" = (
/obj/effect/spawner/structure/window/reinforced/tinted,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
@@ -28364,123 +30386,78 @@
/turf/open/floor/plating,
/area/medical/medbay/zone3)
"aWc" = (
-/obj/machinery/light_switch{
- pixel_x = -24;
- pixel_y = -38
+/obj/structure/cable/white{
+ icon_state = "1-4"
},
-/obj/machinery/button/door{
- desc = "A remote control switch for the medbay foyer.";
- id = "cloningfoyer";
- name = "Cloning Doors Control";
- normaldoorcontrol = 1;
- pixel_x = -24;
- pixel_y = -24
+/obj/structure/cable/white{
+ icon_state = "1-2"
},
-/obj/structure/closet/crate/freezer/surplus_limbs,
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
-"aWd" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+/obj/effect/landmark/blobstart,
+/turf/open/floor/plating{
+ icon_state = "platingdmg1"
+ },
+/area/maintenance/port/aft)
+"aWd" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/landmark/event_spawn,
+/obj/item/tank/internals/oxygen/red,
+/obj/item/clothing/mask/gas,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aWe" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
-"aWe" = (
-/obj/structure/table/glass,
-/obj/item/storage/box/bodybags{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/box/bodybags,
-/obj/item/pen,
-/obj/machinery/firealarm{
- dir = 8;
- pixel_x = 24
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 10
- },
-/obj/effect/turf_decal/tile/blue,
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/area/maintenance/port/aft)
"aWf" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/requests_console{
+ department = "Chemistry Lab";
+ name = "Chemistry RC";
+ pixel_x = 32;
+ receive_ore_updates = 1
+ },
+/obj/effect/turf_decal/tile/yellow,
/obj/structure/table/glass,
-/obj/item/folder/white,
-/obj/item/reagent_containers/glass/beaker/large{
- pixel_x = -3
- },
-/obj/item/reagent_containers/glass/beaker{
- pixel_x = 3
+/obj/item/stack/sheet/mineral/plasma,
+/obj/item/stack/sheet/mineral/plasma,
+/obj/item/stack/sheet/mineral/plasma,
+/obj/item/reagent_containers/glass/bottle/charcoal{
+ pixel_x = 6
},
+/obj/item/reagent_containers/glass/bottle/epinephrine,
/obj/item/reagent_containers/dropper,
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/tile/neutral,
-/turf/open/floor/plasteel/dark,
+/obj/item/reagent_containers/dropper,
+/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"aWg" = (
-/obj/structure/table/glass,
-/obj/item/assembly/igniter,
-/obj/item/assembly/igniter,
-/obj/item/assembly/igniter,
-/obj/item/assembly/timer{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/assembly/timer{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/assembly/timer{
- pixel_x = 3;
- pixel_y = 3
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
},
+/obj/machinery/chem_dispenser,
+/turf/open/floor/plasteel,
+/area/medical/chemistry)
+"aWh" = (
/obj/machinery/firealarm{
dir = 1;
pixel_y = -24
},
/obj/machinery/light,
+/obj/structure/chair/office/light{
+ dir = 8
+ },
+/obj/effect/landmark/start/chemist,
/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/chemistry)
-"aWh" = (
-/obj/structure/table/glass,
-/obj/item/clothing/glasses/science{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/clothing/glasses/science,
-/obj/item/stack/cable_coil/white{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/stack/cable_coil/white,
-/obj/item/grenade/chem_grenade,
-/obj/item/grenade/chem_grenade,
-/obj/item/grenade/chem_grenade,
-/obj/item/grenade/chem_grenade,
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/plasteel,
/area/medical/chemistry)
"aWi" = (
/obj/structure/cable/white{
@@ -28498,21 +30475,39 @@
/area/medical/chemistry)
"aWj" = (
/obj/structure/table/glass,
-/obj/item/clipboard,
-/obj/item/toy/figure/chemist,
-/obj/machinery/light_switch{
- pixel_x = 24;
- pixel_y = -24
+/obj/item/clothing/glasses/science{
+ pixel_x = 3;
+ pixel_y = 3
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
+/obj/item/clothing/glasses/science,
+/obj/item/stack/cable_coil/white{
+ pixel_x = 3;
+ pixel_y = 3
},
-/obj/effect/turf_decal/tile/neutral{
+/obj/item/stack/cable_coil/white,
+/obj/item/grenade/chem_grenade,
+/obj/item/grenade/chem_grenade,
+/obj/item/grenade/chem_grenade,
+/obj/item/grenade/chem_grenade,
+/obj/item/assembly/igniter,
+/obj/item/assembly/igniter,
+/obj/item/assembly/igniter,
+/obj/item/assembly/timer{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/assembly/timer{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/assembly/timer{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/plasteel,
/area/medical/chemistry)
"aWk" = (
/obj/structure/table,
@@ -28627,6 +30622,46 @@
},
/turf/open/floor/circuit/green/telecomms/mainframe,
/area/science/research)
+"aWv" = (
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aWw" = (
+/obj/structure/sign/warning/biohazard{
+ pixel_x = -32
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aWx" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/landmark/blobstart,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aWy" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/bot,
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/portable_atmospherics/canister/oxygen,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aWz" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
/obj/structure/lattice,
@@ -28689,12 +30724,13 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aWF" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/cable/white{
icon_state = "1-2"
},
-/turf/open/floor/plasteel/dark,
-/area/library)
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aWG" = (
/obj/machinery/bookbinder,
/obj/machinery/status_display{
@@ -28713,68 +30749,72 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aWH" = (
-/obj/structure/bodycontainer/morgue,
-/obj/machinery/power/apc{
- areastring = "/area/medical/morgue";
- name = "Morgue APC";
- pixel_y = -26
- },
-/obj/structure/cable/white{
- icon_state = "0-4"
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
-"aWI" = (
-/obj/effect/decal/cleanable/blood/old,
-/obj/structure/cable/white{
- icon_state = "1-8"
- },
-/turf/open/floor/plating,
-/area/medical/morgue)
-"aWJ" = (
-/obj/structure/closet/crate/bin,
-/obj/machinery/camera{
- c_tag = "Medbay Morgue";
- dir = 8
- },
-/obj/effect/turf_decal/tile/neutral{
+/obj/structure/closet/firecloset,
+/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aWI" = (
+/obj/structure/cable/white{
+ icon_state = "4-8"
},
-/turf/open/floor/plasteel/dark,
-/area/medical/morgue)
+/obj/effect/turf_decal/delivery,
+/obj/effect/turf_decal/stripes/line{
+ dir = 9
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aWJ" = (
+/obj/machinery/light/small{
+ dir = 1
+ },
+/obj/effect/turf_decal/delivery,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
"aWK" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/medical/medbay/zone3)
"aWL" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/medical/glass{
- id_tag = "cloningfoyer";
- name = "Cloning Lab";
- req_access_txt = "5"
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/obj/effect/mapping_helpers/airlock/unres{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/newscaster{
+ pixel_x = 32
},
/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
+/area/medical/virology)
"aWM" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plating,
-/area/medical/medbay/zone3)
+/obj/machinery/door/airlock/virology{
+ name = "Virology Access";
+ req_access_txt = "39"
+ },
+/obj/machinery/door/firedoor,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
"aWN" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/medical/glass{
@@ -28942,6 +30982,27 @@
/obj/structure/lattice/catwalk,
/turf/open/space,
/area/asteroid/nearstation)
+"aXd" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/machinery/light/small,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 9
+ },
+/obj/structure/cable/white{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aXe" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/cable/white{
+ icon_state = "1-8"
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aXf" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/closed/wall,
@@ -28966,13 +31027,19 @@
/turf/open/floor/plasteel/dark,
/area/library)
"aXi" = (
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
+/obj/structure/bonfire,
+/obj/item/reagent_containers/food/drinks/bottle/orangejuice{
+ desc = "For the weary spacemen on their quest to rekindle the first plasma fire.";
+ name = "Carton of Estus"
},
-/obj/structure/closet/crate/bin,
-/turf/open/floor/plasteel/dark,
-/area/library)
+/obj/item/nullrod/claymore/glowing{
+ desc = "Don't tell anyone you put any points into dex, though.";
+ force = 10;
+ name = "moonlight greatsword"
+ },
+/obj/effect/decal/remains/human,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aXj" = (
/obj/structure/bookcase/random/reference,
/obj/effect/turf_decal/tile/neutral{
@@ -29103,6 +31170,21 @@
},
/turf/open/floor/plasteel/white,
/area/medical/medbay/zone3)
+"aXv" = (
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable/white{
+ icon_state = "1-2"
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aXw" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
@@ -29187,6 +31269,19 @@
},
/turf/open/floor/plasteel/white,
/area/science/research)
+"aXD" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/firealarm{
+ dir = 1;
+ pixel_y = -26
+ },
+/turf/open/floor/plasteel,
+/area/medical/virology)
"aXE" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -29313,53 +31408,21 @@
/turf/open/floor/wood,
/area/library)
"aXN" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/door/airlock/maintenance_hatch{
name = "Maintenance Hatch";
req_access_txt = "12"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
/obj/effect/turf_decal/stripes/line,
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating,
-/area/maintenance/port)
-"aXO" = (
-/obj/structure/table/glass,
-/obj/item/storage/firstaid/toxin{
- pixel_x = 6;
- pixel_y = 6
- },
-/obj/item/storage/firstaid/toxin{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/firstaid/regular,
-/obj/item/storage/firstaid/toxin{
- pixel_x = -3;
- pixel_y = -3
- },
-/obj/machinery/requests_console{
- department = "Medbay";
- departmentType = 1;
- name = "Medbay RC";
- pixel_x = -30
- },
-/obj/machinery/camera{
- c_tag = "Medbay Storage"
- },
-/obj/effect/turf_decal/delivery,
-/obj/structure/window/reinforced{
- dir = 4
- },
-/obj/structure/window/reinforced{
- dir = 1
- },
/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
+/area/maintenance/port/aft)
+"aXO" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"aXP" = (
/obj/structure/extinguisher_cabinet{
pixel_y = 32
@@ -29456,6 +31519,12 @@
},
/turf/open/floor/plasteel,
/area/medical/medbay/zone3)
+"aXY" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 1
+ },
+/turf/closed/wall/r_wall,
+/area/medical/virology)
"aXZ" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/closet/crate/bin,
@@ -29802,85 +31871,77 @@
/turf/open/floor/wood,
/area/library)
"aYz" = (
-/obj/structure/cable/white{
- icon_state = "2-4"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 6
- },
-/turf/open/floor/plating{
- icon_state = "platingdmg3"
- },
-/area/maintenance/port)
-"aYA" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plating{
- icon_state = "platingdmg1"
- },
-/area/maintenance/port)
-"aYC" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"aYE" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "1-8"
+/obj/structure/closet/l3closet/virology,
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 8
},
/obj/effect/turf_decal/stripes/line{
- dir = 1
+ dir = 10
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aYA" = (
+/obj/machinery/atmospherics/pipe/simple/general/visible{
+ dir = 10
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/obj/machinery/airalarm{
+ pixel_y = 23
},
/turf/open/floor/plating,
-/area/maintenance/port)
-"aYF" = (
-/obj/structure/cable/white{
- icon_state = "2-8"
+/area/maintenance/port/aft)
+"aYB" = (
+/obj/machinery/shower{
+ desc = "From what you understand it was put in rather recently, but the design looks right out of the 2510's. Weird.";
+ dir = 1;
+ icon_state = "shower";
+ name = "Emergency Shower"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
+/obj/machinery/camera{
+ c_tag = "Virology Access";
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aYC" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/landmark/event_spawn,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
+"aYD" = (
+/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/effect/turf_decal/stripes/line{
dir = 10
},
/turf/open/floor/plating,
-/area/maintenance/port)
+/area/maintenance/port/aft)
+"aYE" = (
+/obj/machinery/computer/pandemic,
+/obj/effect/turf_decal/tile/green,
+/obj/item/healthanalyzer,
+/obj/machinery/requests_console{
+ department = "Virology";
+ name = "Virology RC";
+ pixel_x = 0;
+ pixel_y = -32;
+ receive_ore_updates = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/virology)
+"aYF" = (
+/obj/structure/chair/comfy/black,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"aYG" = (
-/obj/structure/table/glass,
-/obj/item/storage/firstaid/fire{
- pixel_x = 6;
- pixel_y = 6
- },
-/obj/item/storage/firstaid/fire{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/firstaid/regular,
-/obj/item/storage/firstaid/fire{
- pixel_x = -3;
- pixel_y = -3
- },
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -22
- },
-/obj/effect/turf_decal/delivery,
-/obj/machinery/door/window/eastleft{
- name = "First-Aid Supplies";
- req_access_txt = "5"
- },
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/chair/comfy/black,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"aYH" = (
/obj/effect/landmark/start/medical_doctor,
/obj/effect/turf_decal/tile/blue{
@@ -30089,6 +32150,14 @@
heat_capacity = 1e+006
},
/area/hallway/primary/aft)
+"aYX" = (
+/obj/effect/turf_decal/tile/bar,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
+/obj/structure/window/reinforced/spawner/north,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aYY" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -30188,62 +32257,80 @@
},
/turf/closed/wall/r_wall/rust,
/area/science/robotics/lab)
+"aZn" = (
+/obj/effect/turf_decal/tile/bar,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
+/obj/structure/window/reinforced/spawner/north,
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 1
+ },
+/obj/effect/landmark/xeno_spawn,
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aZo" = (
-/obj/structure/girder,
-/turf/open/floor/plating,
-/area/maintenance/port)
+/obj/effect/turf_decal/tile/bar,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
+/obj/machinery/door/window/northright{
+ name = "Theatre Stage"
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aZp" = (
-/obj/structure/table/wood,
-/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted,
-/turf/open/floor/plating,
-/area/maintenance/port)
+/obj/effect/turf_decal/tile/bar,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aZq" = (
-/obj/structure/table/wood,
-/obj/item/clothing/gloves/color/black,
-/obj/item/taperecorder,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/door/airlock/maintenance_hatch{
+ name = "Maintenance Hatch";
+ req_access_txt = "12"
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
+"aZr" = (
+/obj/effect/turf_decal/tile/bar,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
/obj/machinery/light/small{
dir = 1
},
-/obj/structure/sign/poster/contraband/random{
- pixel_y = 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{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"aZr" = (
-/obj/structure/rack,
-/obj/item/storage/briefcase{
- pixel_x = -3;
- pixel_y = 3
- },
-/obj/item/storage/secure/briefcase,
-/obj/effect/decal/cleanable/cobweb/cobweb2,
-/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/maintenance/port)
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aZs" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/structure/sign/poster/contraband/random,
-/turf/closed/wall,
-/area/maintenance/port)
+/obj/machinery/vending/autodrobe,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aZt" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/table/wood,
+/obj/item/clothing/suit/syndicatefake,
+/obj/item/clothing/head/syndicatefake,
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
"aZu" = (
/obj/machinery/status_display{
pixel_y = -32
@@ -30284,88 +32371,119 @@
},
/turf/open/floor/wood,
/area/library)
-"aZy" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 6
- },
-/turf/closed/wall/rust,
-/area/maintenance/port)
-"aZz" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+"aZx" = (
+/obj/effect/turf_decal/tile/neutral{
dir = 4
},
-/obj/structure/sign/poster/contraband/random,
-/turf/closed/wall,
-/area/maintenance/port)
-"aZA" = (
-/obj/structure/barricade/wooden,
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
+/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"aZB" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 10
- },
-/turf/closed/wall,
-/area/maintenance/port)
-"aZC" = (
-/obj/structure/table/glass,
-/obj/item/storage/firstaid/brute{
- pixel_x = 6;
- pixel_y = 6
- },
-/obj/item/storage/firstaid/brute{
+/obj/machinery/light/small,
+/obj/structure/table/wood,
+/obj/item/lipstick/random{
pixel_x = 3;
pixel_y = 3
},
-/obj/item/storage/firstaid/regular,
-/obj/item/storage/firstaid/brute{
+/obj/item/lipstick/random{
pixel_x = -3;
pixel_y = -3
},
-/obj/machinery/newscaster{
- pixel_x = -32
- },
-/obj/structure/cable/white{
- icon_state = "2-4"
- },
-/obj/effect/turf_decal/delivery,
-/obj/machinery/door/window/eastright{
- name = "First-Aid Supplies";
- req_access_txt = "5"
- },
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
-"aZD" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/obj/effect/turf_decal/loading_area{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/corner,
-/obj/effect/turf_decal/stripes/corner{
- dir = 1
- },
-/obj/effect/turf_decal/tile/blue{
+/obj/item/lipstick/random,
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aZy" = (
+/obj/effect/turf_decal/tile/neutral{
dir = 4
},
-/obj/effect/turf_decal/tile/blue{
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/table/wood,
+/obj/item/clothing/suit/justice,
+/obj/item/clothing/head/helmet/justice/escape{
+ name = "justice helmet"
+ },
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aZz" = (
+/obj/structure/dresser,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/zone3)
+/turf/open/floor/plasteel/dark,
+/area/maintenance/port/aft)
+"aZA" = (
+/obj/structure/table/glass,
+/obj/item/clipboard,
+/obj/machinery/light_switch{
+ pixel_x = 24;
+ pixel_y = -24
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/turf_decal/bot,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/item/folder/white,
+/obj/item/toy/figure/chemist,
+/obj/item/reagent_containers/glass/beaker/large{
+ pixel_x = -3;
+ pixel_y = 6
+ },
+/obj/item/reagent_containers/glass/beaker{
+ pixel_x = 3;
+ pixel_y = 6
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/chemistry)
+"aZB" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/door/airlock/virology/glass{
+ name = "Isolation Room";
+ req_access_txt = "39"
+ },
+/turf/open/floor/plasteel/freezer,
+/area/medical/virology)
+"aZC" = (
+/obj/structure/table/wood,
+/obj/structure/sign/poster/random{
+ pixel_x = 32
+ },
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
+"aZD" = (
+/obj/machinery/atmospherics/components/binary/valve/on{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 9
+ },
+/obj/machinery/light/small{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"aZE" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/atmos/abandoned{
+ name = "Atmospherics Maintenance";
+ req_access_txt = "12;24"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/port/aft)
"aZF" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/medical/glass{
@@ -30426,6 +32544,21 @@
},
/turf/open/floor/plasteel,
/area/medical/medbay/zone3)
+"aZJ" = (
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
+/obj/structure/sign/warning/nosmoking{
+ pixel_y = -32
+ },
+/obj/structure/sign/warning/fire{
+ pixel_x = 32
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"aZK" = (
/obj/machinery/holopad,
/obj/structure/cable/white{
@@ -30774,113 +32907,6 @@
icon_state = "platingdmg1"
},
/area/maintenance/starboard)
-"baj" = (
-/turf/closed/wall,
-/area/maintenance/port)
-"bam" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"bao" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bap" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall,
-/area/maintenance/port)
-"baq" = (
-/obj/structure/table/wood,
-/obj/item/clothing/suit/syndicatefake,
-/obj/item/clothing/head/syndicatefake,
-/obj/effect/decal/cleanable/cobweb,
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"bar" = (
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bas" = (
-/obj/structure/dresser,
-/obj/machinery/light/small{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"bat" = (
-/obj/structure/table/glass,
-/obj/item/storage/firstaid/o2{
- pixel_x = 6;
- pixel_y = 6
- },
-/obj/item/storage/firstaid/o2{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/firstaid/regular,
-/obj/item/storage/firstaid/o2{
- pixel_x = -3;
- pixel_y = -3
- },
-/obj/machinery/power/apc{
- areastring = "/area/medical/medbay/zone3";
- dir = 8;
- name = "Medbay APC";
- pixel_x = -26
- },
-/obj/structure/cable/white,
-/obj/effect/turf_decal/delivery,
-/obj/structure/window/reinforced,
-/obj/structure/window/reinforced{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
-"bau" = (
-/obj/machinery/light,
-/obj/structure/noticeboard{
- dir = 1;
- pixel_y = -32
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/stripes/box,
-/obj/machinery/rnd/production/techfab/department/medical,
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
-"bav" = (
-/obj/machinery/vending/medical,
-/obj/machinery/firealarm{
- dir = 1;
- pixel_y = -24
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/bot,
-/turf/open/floor/plasteel,
-/area/medical/medbay/zone3)
"baw" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/sign/departments/medbay/alt,
@@ -31278,101 +33304,6 @@
},
/turf/open/floor/plasteel/dark,
/area/science/robotics/lab)
-"bbc" = (
-/obj/structure/table/wood,
-/obj/item/flashlight/lamp,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bbe" = (
-/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/maintenance/port)
-"bbf" = (
-/obj/structure/cable/white{
- icon_state = "1-4"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bbg" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bbh" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/effect/landmark/blobstart,
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/maintenance/port)
-"bbj" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bbk" = (
-/obj/structure/cable/white{
- icon_state = "1-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 9
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bbl" = (
-/obj/structure/table/wood,
-/obj/item/clipboard,
-/obj/item/toy/syndicateballoon,
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"bbm" = (
-/obj/effect/turf_decal/tile/bar,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bbn" = (
-/obj/machinery/vending/autodrobe,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
"bbp" = (
/obj/machinery/light{
dir = 8
@@ -31686,92 +33617,6 @@
},
/turf/open/floor/plasteel/dark,
/area/science/robotics/lab)
-"bbQ" = (
-/turf/open/floor/wood{
- icon_state = "wood-broken5"
- },
-/area/maintenance/port)
-"bbR" = (
-/turf/open/floor/wood,
-/area/maintenance/port)
-"bbS" = (
-/turf/open/floor/wood{
- icon_state = "wood-broken6"
- },
-/area/maintenance/port)
-"bbT" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
- },
-/turf/closed/wall,
-/area/maintenance/port)
-"bbV" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/barricade/wooden,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bbW" = (
-/obj/structure/barricade/wooden,
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bbX" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 9
- },
-/turf/closed/wall,
-/area/maintenance/port)
-"bbY" = (
-/obj/machinery/computer/security/telescreen/entertainment,
-/turf/closed/wall,
-/area/maintenance/port)
-"bbZ" = (
-/obj/structure/barricade/wooden,
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bca" = (
-/obj/structure/sign/poster/contraband/random,
-/turf/closed/wall,
-/area/maintenance/port)
-"bcb" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plating{
- icon_state = "platingdmg1"
- },
-/area/maintenance/port)
-"bcc" = (
-/obj/structure/reagent_dispensers/watertank,
-/obj/effect/decal/cleanable/cobweb/cobweb2,
-/obj/effect/turf_decal/stripes/line{
- dir = 9
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"bcd" = (
/obj/item/retractor,
/obj/item/hemostat,
@@ -32096,129 +33941,6 @@
},
/turf/open/floor/plasteel,
/area/science/mixing)
-"bcF" = (
-/obj/machinery/computer/slot_machine,
-/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/maintenance/port)
-"bcG" = (
-/obj/structure/chair/stool/bar,
-/turf/open/floor/wood,
-/area/maintenance/port)
-"bcH" = (
-/obj/effect/decal/cleanable/blood/splatter,
-/turf/open/floor/wood,
-/area/maintenance/port)
-"bcI" = (
-/turf/open/floor/wood{
- icon_state = "wood-broken2"
- },
-/area/maintenance/port)
-"bcJ" = (
-/obj/structure/chair/stool/bar,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bcK" = (
-/obj/machinery/computer/slot_machine,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bcL" = (
-/obj/machinery/vending/cigarette,
-/obj/machinery/newscaster{
- pixel_x = -32
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bcM" = (
-/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/maintenance/port)
-"bcN" = (
-/obj/structure/chair/comfy/black{
- dir = 4
- },
-/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/maintenance/port)
-"bcO" = (
-/obj/structure/window/reinforced{
- dir = 8
- },
-/obj/structure/sign/warning/nosmoking{
- pixel_y = 32
- },
-/obj/effect/turf_decal/tile/bar,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bcR" = (
-/obj/structure/table/wood,
-/obj/item/instrument/guitar,
-/obj/effect/decal/cleanable/cobweb/cobweb2,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bcS" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/structure/cable/white{
- icon_state = "2-4"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/landmark/blobstart,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bcT" = (
-/obj/structure/rack,
-/obj/item/storage/toolbox/mechanical,
-/obj/item/clothing/head/welding,
-/obj/machinery/light/small{
- dir = 4
- },
-/obj/structure/cable/white{
- icon_state = "0-8"
- },
-/obj/machinery/power/apc{
- areastring = "/area/maintenance/port";
- dir = 4;
- name = "Port Maintenance APC";
- pixel_x = 26
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"bcU" = (
/obj/item/circular_saw,
/obj/item/surgicaldrill{
@@ -32670,160 +34392,6 @@
/obj/structure/sign/warning/fire,
/turf/closed/wall,
/area/science/mixing)
-"bdD" = (
-/obj/structure/table/wood,
-/obj/item/storage/briefcase,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bdE" = (
-/obj/structure/chair/stool/bar,
-/turf/open/floor/wood{
- icon_state = "wood-broken"
- },
-/area/maintenance/port)
-"bdF" = (
-/obj/structure/chair/stool/bar,
-/turf/open/floor/wood{
- icon_state = "wood-broken5"
- },
-/area/maintenance/port)
-"bdG" = (
-/obj/structure/chair/stool/bar,
-/turf/open/floor/wood{
- icon_state = "wood-broken2"
- },
-/area/maintenance/port)
-"bdH" = (
-/obj/structure/table/wood,
-/obj/item/toy/cards/deck/syndicate{
- pixel_y = 6
- },
-/obj/machinery/light/small{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bdI" = (
-/obj/structure/table/wood,
-/obj/item/wrench,
-/obj/item/storage/secure/briefcase{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/briefcase,
-/obj/machinery/light/small{
- 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/maintenance/port)
-"bdJ" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/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/maintenance/port)
-"bdK" = (
-/obj/structure/chair/comfy/black{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/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/maintenance/port)
-"bdL" = (
-/obj/structure/window/reinforced{
- dir = 8
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/tile/bar,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bdM" = (
-/obj/effect/landmark/xeno_spawn,
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 8
- },
-/obj/effect/turf_decal/tile/bar,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bdN" = (
-/obj/structure/table/wood,
-/obj/item/clothing/suit/justice,
-/obj/item/clothing/head/helmet/justice/escape{
- name = "justice helmet"
- },
-/obj/machinery/light/small{
- dir = 4
- },
-/obj/structure/sign/poster/contraband/random{
- 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{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"bdO" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bdP" = (
-/obj/structure/reagent_dispensers/fueltank,
-/obj/effect/turf_decal/stripes/line{
- dir = 10
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"bdQ" = (
/obj/structure/closet/secure_closet/medical2,
/obj/machinery/airalarm{
@@ -33234,148 +34802,10 @@
/obj/machinery/door/poddoor/incinerator_toxmix,
/turf/open/floor/engine/vacuum,
/area/science/mixing)
-"beu" = (
-/obj/structure/table/wood,
-/obj/item/storage/pill_bottle,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bev" = (
-/obj/machinery/computer/slot_machine,
-/obj/machinery/light/small,
-/obj/structure/sign/poster/contraband/random{
- pixel_y = -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{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"bew" = (
-/obj/structure/table/wood,
-/obj/item/coin/iron{
- icon_state = "coin_bananium_heads";
- name = "arcade coin";
- pixel_x = 6
- },
-/obj/item/coin/iron{
- icon_state = "coin_bananium_heads";
- name = "arcade coin";
- pixel_x = -6
- },
-/obj/item/coin/iron{
- icon_state = "coin_bananium_heads";
- name = "arcade coin";
- pixel_y = 6
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bex" = (
-/obj/structure/table/wood,
-/obj/item/reagent_containers/blood/random,
-/obj/item/reagent_containers/syringe{
- pixel_y = 5
- },
-/obj/item/reagent_containers/syringe,
-/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/maintenance/port)
-"bey" = (
-/obj/structure/table/wood,
-/obj/item/newspaper,
-/obj/item/clothing/head/bowler,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bez" = (
-/obj/structure/sign/poster/contraband/random{
- pixel_y = -32
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"beA" = (
-/obj/machinery/computer/security/telescreen/entertainment{
- pixel_y = -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{
- dir = 8
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
-"beB" = (
-/obj/machinery/door/window{
- dir = 8;
- name = "Theatre Stage"
- },
-/obj/effect/turf_decal/tile/bar,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"beC" = (
-/obj/structure/table/wood,
-/obj/item/lipstick/random{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/lipstick/random{
- pixel_x = -3;
- pixel_y = -3
- },
-/obj/item/lipstick/random,
-/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/maintenance/port)
"beE" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall,
/area/medical/medbay/zone3)
-"beF" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Medbay Maintenance";
- req_access_txt = "5"
- },
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"beG" = (
/obj/structure/sign/departments/medbay/alt,
/turf/closed/wall,
@@ -33512,93 +34942,6 @@
},
/turf/closed/wall/r_wall,
/area/science/robotics/lab)
-"beR" = (
-/obj/structure/cable/white{
- icon_state = "1-4"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"beS" = (
-/obj/structure/cable/white{
- icon_state = "2-8"
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "2-4"
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/maintenance/port)
-"beV" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "2-4"
- },
-/obj/structure/cable/white{
- icon_state = "2-8"
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"beZ" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bfa" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- icon_state = "1-8"
- },
-/obj/structure/cable/white{
- icon_state = "1-4"
- },
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bfb" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plating{
- icon_state = "platingdmg3"
- },
-/area/maintenance/port)
-"bfd" = (
-/obj/structure/closet/emcloset,
-/obj/effect/turf_decal/stripes/line{
- dir = 10
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"bfe" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/airalarm/unlocked{
@@ -33732,22 +35075,6 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/turf/open/floor/plasteel/white,
/area/chapel/main)
-"bfw" = (
-/obj/structure/bonfire,
-/obj/item/reagent_containers/food/drinks/bottle/orangejuice{
- desc = "For the weary spacemen on their quest to rekindle the first plasma fire.";
- name = "Carton of Estus"
- },
-/obj/item/nullrod/claymore/glowing{
- desc = "Don't tell anyone you put any points into dex, though.";
- force = 10;
- name = "moonlight greatsword"
- },
-/obj/effect/decal/remains/human,
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/chapel/main)
"bfx" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 5
@@ -33760,122 +35087,16 @@
},
/turf/closed/wall,
/area/chapel/main)
-"bfz" = (
-/obj/machinery/door/airlock/grunge{
- name = "Crematorium";
- req_access_txt = "27"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/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/maintenance/port)
"bfA" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/turf/closed/wall,
/area/chapel/main)
-"bfB" = (
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
"bfC" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
/turf/closed/wall/rust,
/area/chapel/main)
-"bfD" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 10
- },
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/stripes/line{
- dir = 5
- },
-/obj/item/storage/backpack,
-/obj/item/crowbar,
-/obj/item/wrench,
-/obj/structure/rack,
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bfE" = (
-/obj/structure/cable/white{
- icon_state = "1-4"
- },
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/landmark/blobstart,
-/turf/open/floor/plating{
- icon_state = "platingdmg1"
- },
-/area/maintenance/port)
-"bfF" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/landmark/event_spawn,
-/obj/item/tank/internals/oxygen/red,
-/obj/item/clothing/mask/gas,
-/turf/open/floor/plating,
-/area/maintenance/port)
-"bfG" = (
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/maintenance/port)
-"bfH" = (
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/structure/cable/white{
- icon_state = "4-8"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/port)
"bfI" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable/white{
@@ -34158,22 +35379,6 @@
},
/turf/open/floor/plasteel/dark,
/area/chapel/main)
-"bgc" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/machinery/portable_atmospherics/canister/oxygen,
-/turf/open/floor/plasteel,
-/area/maintenance/port)
-"bgd" = (
-/obj/structure/closet/firecloset,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"bge" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 8
@@ -34500,21 +35705,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall,
/area/hallway/secondary/entry)
-"bgO" = (
-/obj/machinery/door/airlock/maintenance_hatch{
- name = "Maintenance Hatch";
- req_access_txt = "12"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/effect/turf_decal/stripes/line,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/maintenance/port)
"bgP" = (
/turf/closed/wall,
/area/hallway/secondary/entry)
@@ -37915,14 +39105,6 @@
heat_capacity = 1e+006
},
/area/hallway/primary/port/aft)
-"bxR" = (
-/obj/structure/cable/white{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/plating,
-/area/maintenance/port)
"bxS" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -38346,22 +39528,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
-"dEa" = (
-/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
- },
-/obj/machinery/computer/arcade{
- dir = 4
- },
-/turf/open/floor/plasteel/dark,
-/area/maintenance/port)
"dFV" = (
/obj/machinery/atmospherics/pipe/simple/green/visible{
dir = 4
@@ -40085,9 +41251,6 @@
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/hallway/primary/starboard/fore)
-"nxA" = (
-/turf/closed/wall,
-/area/hallway/primary/port/aft)
"nFG" = (
/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
dir = 8
@@ -41063,12 +42226,6 @@
/obj/structure/sign/warning/vacuum,
/turf/closed/wall/rust,
/area/maintenance/starboard)
-"sCb" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/turf/closed/wall,
-/area/medical/medbay/zone3)
"sCr" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -41902,10 +43059,6 @@
"sJG" = (
/turf/closed/wall/r_wall/rust,
/area/engine/supermatter)
-"sJH" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall/r_wall/rust,
-/area/maintenance/port)
"sJI" = (
/turf/closed/wall/rust,
/area/library)
@@ -41966,9 +43119,6 @@
icon_state = "wood-broken7"
},
/area/library)
-"sJT" = (
-/turf/closed/wall/rust,
-/area/medical/morgue)
"sJV" = (
/turf/closed/wall/r_wall/rust,
/area/tcommsat/server)
@@ -42046,33 +43196,13 @@
"sKp" = (
/turf/closed/wall/rust,
/area/medical/medbay/zone3)
-"sKx" = (
-/turf/closed/wall/r_wall/rust,
-/area/maintenance/port)
"sKB" = (
/turf/closed/wall/rust,
/area/security/checkpoint)
-"sKE" = (
-/turf/closed/wall/rust,
-/area/maintenance/port)
-"sKH" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/turf/closed/wall/rust,
-/area/maintenance/port)
-"sKI" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall/rust,
-/area/maintenance/port)
"sKJ" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall/rust,
/area/science/robotics/lab)
-"sKL" = (
-/obj/structure/sign/poster/contraband/random,
-/turf/closed/wall/rust,
-/area/maintenance/port)
"sKP" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -42085,11 +43215,6 @@
},
/turf/closed/wall/r_wall/rust,
/area/science/robotics/lab)
-"sKW" = (
-/turf/open/floor/plating{
- icon_state = "panelscorched"
- },
-/area/maintenance/port)
"sKZ" = (
/turf/closed/wall/r_wall/rust,
/area/science/xenobiology)
@@ -72661,10 +73786,10 @@ aad
aad
aad
aad
-baj
-aqo
-baj
-baj
+aKm
+aKo
+aKm
+aKm
aaa
aaa
aaa
@@ -72919,9 +74044,9 @@ aMJ
aMJ
sJV
aMJ
-aqx
-awH
-baj
+aKr
+aLz
+aKm
aaa
aaa
aaa
@@ -73176,9 +74301,9 @@ buJ
buO
sKn
aMJ
-atE
-sKx
-baj
+aKB
+aLs
+aKm
aac
aaa
aaa
@@ -73433,8 +74558,8 @@ buK
sKj
buR
aMJ
-avB
-aOH
+aKF
+aqo
aad
aac
aaa
@@ -73690,8 +74815,8 @@ buL
buP
buS
aMJ
-awB
-baj
+aKJ
+aKm
aad
aad
aaa
@@ -73947,8 +75072,8 @@ buK
sKj
buR
aMJ
-awB
-baj
+aKJ
+aKm
aad
aad
aaa
@@ -74204,8 +75329,8 @@ buN
buQ
buU
sJV
-awB
-aOH
+aKJ
+aqo
aad
aaa
aaa
@@ -74461,9 +75586,9 @@ sJV
aMJ
aMJ
sJV
-awB
-aOH
-sKx
+aKJ
+aqo
+aLs
aac
aaa
aaa
@@ -74717,10 +75842,10 @@ bvo
aad
bvo
aad
-baj
-awE
-awL
-baj
+aKm
+aLp
+aLB
+aKm
aac
aac
aac
@@ -74974,10 +76099,10 @@ aUQ
aVK
aUQ
aXc
-baj
-aOH
-axY
-awG
+aKm
+aqo
+aLC
+aLv
aac
aac
aac
@@ -75232,9 +76357,9 @@ aVL
aUR
aUQ
bvo
-sKx
-awB
-baj
+aLs
+aKJ
+aKm
aac
aad
aac
@@ -75489,9 +76614,9 @@ aUU
aWz
aVL
bvo
-aOH
-axh
-baj
+aqo
+aLL
+aKm
aad
aad
aad
@@ -75746,10 +76871,10 @@ aUU
aWz
aUQ
bvg
-baj
-awB
-baj
-baj
+aKm
+aKJ
+aKm
+aKm
aad
aad
aad
@@ -76003,10 +77128,10 @@ aUU
aWz
aVL
bvg
-awG
-awB
-axj
-baj
+aLv
+aKJ
+aME
+aKm
aad
aad
aad
@@ -76260,17 +77385,17 @@ aUU
aUU
aUQ
bvg
-baj
-awB
-axk
-baj
-aad
-aad
-aad
-aad
-aad
-aad
+aKm
+aKJ
+aMF
+aKm
+aac
+aac
aad
+aKm
+aKm
+aKm
+aKm
aad
aad
aaa
@@ -76517,21 +77642,21 @@ aUU
aWz
aVL
bvg
-baj
-awB
-aZo
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aac
-aac
-aaa
+aKm
+aKJ
+aMG
+aKm
+aKm
+aKm
+aKm
+aKm
+aOs
+aSf
+aKV
+aKV
+aKV
+aLw
+aLw
aaa
aaa
aaa
@@ -76774,21 +77899,21 @@ aUU
aWz
aUQ
bvo
-baj
-awE
-awL
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aac
-aac
+aKm
+aLp
+aLB
+aOI
+aPQ
+aPQ
+aPQ
+aPQ
+aPQ
+aVF
+aKV
+aLn
+aRA
+aSp
+aLw
aaa
aaa
aaa
@@ -77031,21 +78156,21 @@ aUU
aWz
aVL
bvo
-aOH
-baj
-axl
-sKE
-baj
-aZo
-aZo
-sKE
-baj
-aad
-aad
-aad
-aad
-aad
-aac
+aqo
+aKm
+aMH
+axU
+aKm
+aMG
+aMG
+aUi
+aKm
+aVG
+aKV
+aSe
+aSJ
+aTm
+aLw
aaa
aaa
aaa
@@ -77288,21 +78413,21 @@ aUU
aWz
aUQ
aad
-sKx
-aZp
-bam
-bbc
-bbQ
-dEa
-bdD
-beu
-sKE
-aad
-aad
-aad
-aad
-aad
-aac
+aLs
+aLX
+aMI
+aOL
+aPR
+aQV
+aSq
+aUk
+aUi
+aVG
+aKV
+aTk
+aSK
+aYE
+aKV
aad
aaa
aaa
@@ -77545,23 +78670,23 @@ aUU
aUU
aVL
aad
-aOH
-aZq
-axn
-axU
-axX
-bcG
-bdE
-bev
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+aqo
+aMv
+aMQ
+aOM
+aPS
+aRc
+aSs
+aUl
+aKm
+aVG
+aKV
+aTl
+aXD
+aKV
+aKV
+aKV
+aKV
aaa
aaa
aaa
@@ -77802,23 +78927,23 @@ bvg
bvg
bvo
bvo
-aOH
-aZr
-bam
-bbe
-bbS
-bcH
-bcG
-bcF
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+aqo
+aMw
+aMI
+aON
+aPT
+aRd
+aRc
+aUm
+aKm
+aVH
+aRe
+aTn
+aWL
+aZB
+aTv
+aTW
+aLw
aac
aaa
aaa
@@ -78048,34 +79173,34 @@ aKH
acB
aEt
aEt
-aOH
-aPO
-sJH
-aQU
-aQU
-sJH
-sJH
-aQU
-aQU
-sJH
-aQU
-aQU
-aZs
-axL
-bap
-bbT
-bcI
-bar
-bew
-aZo
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+aqo
+awH
+axX
+aEg
+aEg
+axX
+axX
+aEg
+aEg
+axX
+aEg
+aEg
+aMD
+aOc
+aOS
+aPU
+aRj
+aSG
+aUo
+aMG
+aSg
+aKV
+aUK
+aXY
+aTo
+aTQ
+aUh
+aKV
aac
aac
aaa
@@ -78305,34 +79430,34 @@ aKI
aLY
aNa
aEt
-aOI
-aPP
-bxR
-aRS
-aTb
-aUb
-aVM
-aVM
-aTb
-aTb
-aTb
-aVM
-aTb
-bao
-bbf
-aZA
-bbR
-bdF
-bcK
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+aqx
+awL
+axY
+aEj
+aFM
+aJN
+aKl
+aKl
+aFM
+aFM
+aFM
+aKl
+aFM
+aOH
+aOT
+aPV
+aRm
+aSI
+aRC
+aKm
+aSr
+aKV
+aWI
+aYz
+aKV
+aZD
+aYD
+aKm
aad
aac
aac
@@ -78562,8 +79687,8 @@ apt
aLZ
aNb
aEt
-bbg
-aPQ
+atE
+axh
aQW
aQW
aQW
@@ -78576,20 +79701,20 @@ sJI
aQW
sJI
aQW
-bbg
-aZz
-bcJ
-bdG
-bev
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+atE
+aQB
+aRn
+aSL
+aUl
+aKm
+aSQ
+aKV
+aWJ
+aYB
+aKV
+aYA
+aZJ
+aKm
aad
aad
aac
@@ -78819,8 +79944,8 @@ aKK
aMa
aNc
aEt
-bbg
-aPR
+atE
+axk
aQW
aRT
aRU
@@ -78833,23 +79958,23 @@ jnK
aYw
aZu
aQW
-aYA
-sKH
-bcK
-bdH
-bex
-sKE
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+awB
+aQF
+aRC
+aTb
+aUp
+aUi
+aTj
+aKV
+aWM
+aKV
+aKV
+aZE
+aKm
+aKm
+aKm
+aKm
+aKm
aad
aad
aad
@@ -79076,8 +80201,8 @@ aKL
aMb
aNd
sHV
-aOL
-aPS
+avB
+axl
sJI
aSc
aTc
@@ -79090,23 +80215,23 @@ aXL
aYx
aZv
aQW
-bbh
-aPV
-baj
-sKL
-baj
-aZo
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+aOV
+axU
+aKm
+aTU
+aKm
+aMG
+aVI
+aWw
+aXd
+aKm
+aRm
+aRm
+aYF
+aYX
+aZp
+aZt
+aKm
aad
aad
aad
@@ -79333,8 +80458,8 @@ aKM
aMa
aNe
aEt
-aYA
-aPT
+awB
+axn
aQW
amH
aTd
@@ -79347,23 +80472,23 @@ aXM
aYy
aZw
aQW
-bbg
-bbV
-bcL
-bdI
-bey
-aZo
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+atE
+aQQ
+aRS
+aTV
+aUq
+aMG
+aVJ
+aWx
+aXe
+aXN
+aXO
+aYC
+aYG
+aZn
+aZp
+aZx
+aKm
aad
aad
aad
@@ -79590,8 +80715,8 @@ aKN
aMc
aNf
aEt
-aOM
-aPU
+awE
+axL
aQW
aRW
aTe
@@ -79604,23 +80729,23 @@ aQW
aQW
aQW
sJI
-bbj
-bbW
-bcM
-bdJ
-bez
-baj
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
-aad
+aPO
+aQU
+aRV
+aUb
+aUu
+aUN
+aVM
+aKm
+aKm
+aKm
+aZC
+aRm
+aRm
+aZo
+aZp
+aZy
+aKm
aad
aad
aac
@@ -79847,37 +80972,37 @@ aKO
aMd
aNg
aEt
-aON
-aPV
+awG
+axU
aQW
aRX
aTf
-sJX
-aUX
+axj
+aCB
+aDm
+aDn
+aDo
+aKn
+aLy
+aFM
+aFM
+aPP
+aQQ
+aSm
+aSm
+aUJ
+aKm
aVR
-aVQ
-aXg
-aQW
-aYz
-aTb
-aTb
-bbk
-bbV
-bcN
-bdK
-beA
-baj
-aad
-aad
-aad
+aKm
+aXi
bfu
bfu
sLf
bfu
bfu
-aad
-aad
-aad
+aZq
+aKm
+aKm
aac
aac
aaa
@@ -80114,16 +81239,16 @@ bxS
aVS
aWE
aXh
-aQW
-bbg
-aZy
-bap
-bap
-bbX
-bcO
-bdL
-beB
-sKE
+ajG
+ajG
+ajG
+ajG
+ajG
+aHK
+aRb
+aRb
+aUL
+sLf
bfu
bfu
sLf
@@ -80132,9 +81257,9 @@ bhZ
biF
bjf
bfu
-aad
-aad
-aac
+aZr
+aZp
+aLv
aac
aaa
aaa
@@ -80370,17 +81495,17 @@ sJX
aUY
aVT
aVQ
-aXi
-aQW
-bbg
-aZz
-baq
-bbl
-bbY
-bbm
-bdM
-bbm
-sKE
+aXg
+ajG
+aGY
+aOl
+aOQ
+aCy
+aPC
+aQh
+aRb
+aKJ
+sLf
bfv
bfS
bgB
@@ -80389,9 +81514,9 @@ bia
biG
bjg
bfu
-aad
-aad
-aac
+aZs
+aZz
+aKm
aaa
aaa
aaa
@@ -80628,16 +81753,16 @@ sKe
aVU
aWE
aXj
-sJI
-aYC
-aZA
-bar
-bbm
-bbZ
-bbm
-bbm
-bbm
-baj
+ajG
+aOb
+aPF
+aRo
+aFZ
+aRp
+aQi
+aRb
+aKJ
+bfu
bfu
bfu
bfu
@@ -80648,7 +81773,7 @@ bjh
bfu
sLf
bfu
-aac
+aKm
aaa
aaa
aaa
@@ -80875,27 +82000,27 @@ aIB
aIB
aIB
aIB
-aOR
+aiQ
aPZ
aQZ
aSb
sJS
-aUh
-aUZ
+aBn
+aDf
aVV
aVQ
aXk
-aQW
-bbg
-aPV
-bas
-bbn
-bca
-bcR
-bdN
-beC
-baj
-bfw
+ajG
+aOZ
+aQe
+aOK
+aCy
+aPE
+aSo
+aRb
+aLp
+aLB
+aVW
bfu
bgC
bhp
@@ -81132,26 +82257,26 @@ aKP
aMe
aNj
aIB
-aOS
+aDk
aQa
aQX
aSc
aTi
-aUi
-aVa
-aVW
-aWF
-aVW
-aXN
-aYE
-aZB
-bap
-bap
-sKI
-bap
-bap
-bap
-bap
+aCx
+aCx
+aVQ
+aWE
+aDq
+ajG
+aOe
+aRl
+aCy
+aCy
+aRw
+aQC
+aHb
+aHb
+aUZ
bfx
bfu
bfu
@@ -81389,7 +82514,7 @@ aKQ
aMf
aNk
aOf
-aOT
+aDp
aQb
aRa
aSd
@@ -81399,16 +82524,16 @@ aVb
aVX
aWG
aXl
-aQW
-aYF
-bxR
-aRS
-aTb
-bcb
-bcS
-aTb
-aVM
-beR
+aSh
+aOg
+aGC
+aGC
+aPA
+aJx
+aQD
+aQI
+aHi
+aVa
bfy
bfT
bgD
@@ -81648,25 +82773,25 @@ aNl
aID
aOU
aQc
-aRb
-aRb
-sJT
-aRb
-aRb
-aRb
-aRb
+ail
+ail
+aFo
+ail
+ail
+ail
+ail
+ail
aSh
-aSh
-aSh
-aSh
-aSh
-sKp
-bcc
-bcT
-bdP
-aZo
-beS
-bfz
+aPg
+aNS
+aPz
+aPB
+aPH
+aQE
+aQL
+aRb
+aVc
+aVY
bfU
bgE
bhr
@@ -81903,26 +83028,26 @@ aKS
aMh
aNm
aIB
-aOV
-aQd
-aRc
-aSe
-aTj
-aUk
-aVc
-aVY
-aWH
-sKp
-aXO
-aYG
-aZC
-bat
+aEh
+aFh
+aGf
+aHG
+aJe
+aJo
+aLo
+aLu
+aMl
+aOW
+aOX
+aGZ
+aOE
+aPv
aSh
aSh
aSh
aSh
aSh
-bbg
+atE
bfA
bfu
bgF
@@ -82160,26 +83285,26 @@ aIB
sIK
aIB
aIB
-aOW
-aPZ
-aRd
-aSf
-aTk
-aSf
-aVd
-aVZ
-aWI
-aSh
+aEi
+aFj
+aGl
+aHJ
+aJf
+aJv
+aLq
+aLx
+aMY
+ail
aXP
aYH
-aZD
-bau
+aFp
+aPD
aSh
bcd
bcU
bdQ
aSh
-bbg
+atE
bfA
bfV
bgG
@@ -82417,27 +83542,27 @@ aKT
aMi
aNn
aHM
-aOX
-aQe
-aRe
-aSg
-aTl
+aEk
+aGd
+aHf
+aHX
+aJg
+aJA
+aLr
+aLA
+aNO
ail
-aVe
-aWa
-aWJ
-aSh
aXQ
aYI
-ajG
-bav
+aOJ
+aHa
aSh
bce
bcV
bdR
sKp
-beV
-bfB
+aVd
+aVZ
bfW
bgH
bht
@@ -82674,16 +83799,16 @@ aKU
aMj
aNt
csX
-aOY
+aEl
aQf
-nxA
-aSh
-aSh
-aSh
-aVf
-sCb
-aSh
-aSh
+ail
+ail
+ail
+ail
+aNp
+aOA
+ail
+ail
aXR
aYJ
aZF
@@ -82693,7 +83818,7 @@ bcf
bcW
blt
ooX
-aOL
+avB
bfA
bfX
bgI
@@ -82931,15 +84056,15 @@ aKX
lyp
bIJ
aOj
-aOZ
+aEm
bxQ
sJJ
-aSh
-aTm
-aUo
-aVg
-aWc
-aWK
+ail
+aGF
+aJO
+aNL
+aNo
+aNP
aXm
aXS
aYK
@@ -82950,7 +84075,7 @@ bcg
bcX
bdS
aSh
-aOL
+avB
bfy
bfY
bgJ
@@ -83191,12 +84316,12 @@ aHM
aPa
aQb
aKg
-aSh
-aTn
-aUp
-aVh
-aWd
-aWL
+ail
+aHc
+aKk
+aNM
+aOB
+aNQ
aXn
bxT
aYL
@@ -83207,7 +84332,7 @@ aUn
aWb
bdT
aSh
-bbg
+atE
bfA
bfZ
bgK
@@ -83448,12 +84573,12 @@ aOh
vsL
aQd
sJK
-aSi
-aTo
-aUq
-aVi
-aWe
-aWM
+aFm
+aHd
+aJd
+aNN
+aOR
+aNR
aXo
aXT
aYM
@@ -83464,7 +84589,7 @@ bch
bcY
bdU
beE
-beZ
+aVe
bfC
bga
bgL
@@ -83720,8 +84845,8 @@ bbq
bbq
bbq
bdV
-beF
-bfa
+aUM
+aVf
bfA
bgb
bgM
@@ -83966,7 +85091,7 @@ aSj
aTq
aUs
aVj
-aWf
+aWg
aTp
aXq
aXV
@@ -83978,7 +85103,7 @@ bci
bcZ
bdW
aSh
-bbg
+atE
bfA
bfu
bfu
@@ -84219,25 +85344,25 @@ aHM
aPd
aQc
aRf
+aiJ
aSk
aTr
-aUt
aVl
-aWg
+aWh
aRf
aXr
aXW
aYP
aZL
baC
-bbs
+aHs
aSi
aWK
aWK
aSh
-bfb
-bfD
-bgc
+aVg
+aWa
+aWy
bgN
bhz
bip
@@ -84478,24 +85603,24 @@ aQg
aRh
aSl
aTs
-aiJ
-aVl
-aWh
+aUt
+aVn
+aWj
aRh
aXs
aXX
aYQ
aZM
baD
-bbr
+bbs
aWK
bda
bdX
aSh
-aYF
-bfE
-bdO
-bgO
+aVh
+aWc
+aWF
+aXv
bhA
biq
biV
@@ -84740,7 +85865,7 @@ aVm
aWi
aWN
aXt
-aiQ
+aOY
aYR
aZN
ajO
@@ -84749,9 +85874,9 @@ bcj
bdb
bdY
aSh
-sKW
-bfF
-aZo
+aVi
+aWd
+aMG
bgP
bhB
bir
@@ -84993,8 +86118,8 @@ aRg
aSn
aTu
aUw
-aVn
-aWj
+aWf
+aZA
aWO
aXu
aXZ
@@ -85006,9 +86131,9 @@ bck
bdc
bdZ
aSh
-bfd
-bfG
-bgd
+aVk
+aWe
+aWH
bgP
bhC
bis
@@ -85263,9 +86388,9 @@ aSh
aWK
bea
beG
-sKE
-bfH
-baj
+aUi
+aWv
+aKm
bgQ
bhD
bit
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index f11815b537..5cb4f044ae 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -334,8 +334,8 @@
/area/crew_quarters/fitness/pool)
"aaM" = (
/turf/open/floor/plasteel/yellowsiding/corner{
- icon_state = "yellowcornersiding";
- dir = 8
+ dir = 8;
+ icon_state = "yellowcornersiding"
},
/area/crew_quarters/fitness/pool)
"aaN" = (
@@ -354,8 +354,8 @@
/area/crew_quarters/fitness/pool)
"aaP" = (
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 8
+ dir = 8;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"aaQ" = (
@@ -433,8 +433,8 @@
/area/crew_quarters/fitness/pool)
"aaW" = (
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 1
+ dir = 1;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"aaX" = (
@@ -550,8 +550,8 @@
"abm" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abn" = (
@@ -580,8 +580,8 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abr" = (
@@ -595,8 +595,8 @@
"abt" = (
/obj/structure/pool/Rboard,
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 8
+ dir = 8;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abu" = (
@@ -659,8 +659,8 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/yellowsiding/corner{
- icon_state = "yellowcornersiding";
- dir = 4
+ dir = 4;
+ icon_state = "yellowcornersiding"
},
/area/crew_quarters/fitness/pool)
"abB" = (
@@ -670,21 +670,21 @@
pixel_y = -27
},
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 1
+ dir = 1;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abC" = (
/obj/machinery/light,
/turf/open/floor/plasteel/yellowsiding{
- icon_state = "yellowsiding";
- dir = 1
+ dir = 1;
+ icon_state = "yellowsiding"
},
/area/crew_quarters/fitness/pool)
"abD" = (
/turf/open/floor/plasteel/yellowsiding/corner{
- icon_state = "yellowcornersiding";
- dir = 1
+ dir = 1;
+ icon_state = "yellowcornersiding"
},
/area/crew_quarters/fitness/pool)
"abE" = (
@@ -6313,27 +6313,7 @@
"aoz" = (
/turf/closed/wall,
/area/maintenance/fore)
-"aoA" = (
-/obj/machinery/gateway{
- dir = 9
- },
-/obj/effect/turf_decal/bot_white/right,
-/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/gateway)
"aoB" = (
-/obj/machinery/gateway{
- dir = 1
- },
/obj/machinery/light{
dir = 1
},
@@ -6350,23 +6330,6 @@
},
/turf/open/floor/plasteel/dark,
/area/gateway)
-"aoC" = (
-/obj/machinery/gateway{
- dir = 5
- },
-/obj/effect/turf_decal/bot_white/left,
-/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/gateway)
"aoH" = (
/obj/structure/lattice,
/obj/structure/grille,
@@ -6692,44 +6655,10 @@
},
/turf/open/space,
/area/space/nearstation)
-"apq" = (
-/obj/machinery/gateway{
- dir = 8
- },
-/obj/effect/turf_decal/bot_white,
-/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/gateway)
"apr" = (
/obj/machinery/gateway/centerstation,
/turf/open/floor/plasteel/dark,
/area/gateway)
-"aps" = (
-/obj/machinery/gateway{
- dir = 4
- },
-/obj/effect/turf_decal/bot_white,
-/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/gateway)
"apt" = (
/obj/structure/chair{
dir = 4
@@ -6916,9 +6845,6 @@
/turf/closed/wall/r_wall,
/area/ai_monitored/nuke_storage)
"apU" = (
-/obj/machinery/gateway{
- dir = 10
- },
/obj/effect/turf_decal/bot_white/left,
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -6933,7 +6859,6 @@
/turf/open/floor/plasteel/dark,
/area/gateway)
"apV" = (
-/obj/machinery/gateway,
/obj/effect/turf_decal/bot_white,
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -6948,9 +6873,6 @@
/turf/open/floor/plasteel/dark,
/area/gateway)
"apW" = (
-/obj/machinery/gateway{
- dir = 6
- },
/obj/effect/turf_decal/bot_white/right,
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -7876,32 +7798,7 @@
/turf/open/floor/plasteel,
/area/gateway)
"arY" = (
-/obj/structure/closet/crate/internals,
-/obj/item/clothing/suit/hazardvest{
- desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
- name = "emergency lifejacket"
- },
-/obj/item/clothing/suit/hazardvest{
- desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
- name = "emergency lifejacket"
- },
-/obj/item/clothing/suit/hazardvest{
- desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
- name = "emergency lifejacket"
- },
-/obj/item/clothing/suit/hazardvest{
- desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
- name = "emergency lifejacket"
- },
-/obj/item/clothing/suit/hazardvest{
- desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
- name = "emergency lifejacket"
- },
-/obj/item/flashlight,
-/obj/item/flashlight,
-/obj/item/flashlight,
-/obj/item/flashlight,
-/obj/item/flashlight,
+/obj/machinery/computer/gateway_control,
/turf/open/floor/plasteel,
/area/gateway)
"arZ" = (
@@ -8904,6 +8801,32 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
},
+/obj/structure/closet/crate/internals,
+/obj/item/clothing/suit/hazardvest{
+ desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
+ name = "emergency lifejacket"
+ },
+/obj/item/clothing/suit/hazardvest{
+ desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
+ name = "emergency lifejacket"
+ },
+/obj/item/clothing/suit/hazardvest{
+ desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
+ name = "emergency lifejacket"
+ },
+/obj/item/clothing/suit/hazardvest{
+ desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
+ name = "emergency lifejacket"
+ },
+/obj/item/clothing/suit/hazardvest{
+ desc = "A high-visibility lifejacket complete with whistle and slot for oxygen tanks.";
+ name = "emergency lifejacket"
+ },
+/obj/item/flashlight,
+/obj/item/flashlight,
+/obj/item/flashlight,
+/obj/item/flashlight,
+/obj/item/flashlight,
/turf/open/floor/plasteel,
/area/gateway)
"auh" = (
@@ -39042,7 +38965,6 @@
/area/chapel/dock)
"bKe" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/obj/structure/closet/emcloset,
/turf/open/floor/plasteel/white{
heat_capacity = 1e+006
},
@@ -40077,12 +39999,6 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 8
},
-/obj/machinery/light/small{
- dir = 4
- },
-/obj/structure/chair{
- dir = 1
- },
/turf/open/floor/plasteel/white{
heat_capacity = 1e+006
},
@@ -47273,7 +47189,7 @@
"ceT" = (
/obj/effect/turf_decal/stripes/line,
/obj/structure/closet/emcloset,
-/turf/open/floor/plating/airless,
+/turf/open/floor/plating,
/area/engine/engineering)
"ceU" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on{
@@ -50404,9 +50320,11 @@
/turf/open/floor/plasteel,
/area/crew_quarters/heads/chief)
"cqW" = (
-/obj/effect/spawner/structure/window/reinforced,
-/turf/closed/mineral,
-/area/chapel/asteroid/monastery)
+/obj/structure/chair,
+/turf/open/floor/plasteel/white{
+ heat_capacity = 1e+006
+ },
+/area/chapel/dock)
"cqX" = (
/obj/structure/disposalpipe/segment,
/obj/structure/lattice,
@@ -52993,7 +52911,7 @@
/turf/open/floor/plasteel/dark,
/area/security/main)
"cCT" = (
-/obj/machinery/rnd/production/protolathe/department/cargo,
+/obj/machinery/rnd/production/techfab/department/cargo,
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"cCU" = (
@@ -55664,11 +55582,11 @@
/turf/open/floor/plating,
/area/crew_quarters/dorms)
"izF" = (
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
+/obj/structure/closet/emcloset,
+/turf/open/floor/plasteel/white{
+ heat_capacity = 1e+006
},
-/area/maintenance/department/science)
+/area/chapel/dock)
"iAx" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -57738,10 +57656,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 6
},
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
- },
+/turf/open/floor/plating,
/area/maintenance/department/science)
"nAs" = (
/obj/machinery/door/airlock/engineering/glass{
@@ -57904,7 +57819,7 @@
/obj/structure/disposalpipe/trunk{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"nOY" = (
/obj/effect/turf_decal/stripes/line{
@@ -58007,10 +57922,7 @@
/obj/structure/table,
/obj/item/paper_bin,
/obj/item/pen,
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
- },
+/turf/open/floor/plating,
/area/maintenance/department/science)
"odM" = (
/obj/effect/landmark/barthpot,
@@ -59532,14 +59444,13 @@
/turf/open/floor/plating/airless,
/area/space/nearstation)
"ros" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/machinery/light/small{
dir = 4
},
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
+/turf/open/floor/plasteel/white{
+ heat_capacity = 1e+006
},
-/area/maintenance/department/science)
+/area/chapel/dock)
"rrb" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -60138,7 +60049,6 @@
/turf/open/floor/plasteel/dark,
/area/chapel/office)
"tap" = (
-/obj/structure/reagent_dispensers/keg/aphro,
/turf/open/floor/wood,
/area/maintenance/department/crew_quarters/dorms)
"taA" = (
@@ -60667,10 +60577,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
},
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
- },
+/turf/open/floor/plating,
/area/maintenance/department/science)
"uos" = (
/obj/machinery/computer/camera_advanced/base_construction,
@@ -61099,13 +61006,6 @@
/obj/structure/lattice,
/turf/open/space/basic,
/area/space/nearstation)
-"vpz" = (
-/obj/structure/girder,
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
- },
-/area/maintenance/department/science)
"vsk" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -61620,12 +61520,6 @@
},
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/bar)
-"wDe" = (
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plasteel/white{
- heat_capacity = 1e+006
- },
-/area/chapel/dock)
"wDl" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/stripes/corner,
@@ -62038,10 +61932,7 @@
/area/maintenance/department/science)
"xsO" = (
/obj/item/ectoplasm,
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01";
- luminosity = 2
- },
+/turf/open/floor/plating,
/area/maintenance/department/science)
"xuv" = (
/obj/item/broken_bottle,
@@ -75866,8 +75757,8 @@ aaa
bGI
bNs
cfN
-cqW
-cqW
+cfN
+cfN
cfN
cfN
bZY
@@ -76379,7 +76270,7 @@ aaa
aaa
bGI
bNs
-cqW
+cfN
bOw
cfN
bOw
@@ -80477,7 +80368,7 @@ aaa
aht
aqG
bGE
-bKf
+cqW
bKf
bMw
bNy
@@ -80734,8 +80625,8 @@ aht
aht
aqG
bGE
-bKf
-bKf
+izF
+ros
bMx
bNz
bHM
@@ -80991,7 +80882,7 @@ aaa
aaa
aqG
bGE
-wDe
+bGE
bHM
bHM
bNA
@@ -97884,8 +97775,8 @@ aaa
aaa
aaa
lcZ
-aoA
-apq
+apW
+apV
apU
aqQ
arX
@@ -98398,8 +98289,8 @@ aiT
aiS
aaa
lcZ
-aoC
-aps
+apU
+apV
apW
aqS
arZ
@@ -107723,7 +107614,7 @@ aht
bwm
ikB
iVJ
-izF
+lWy
typ
bwm
aht
@@ -108233,7 +108124,7 @@ bwm
svN
bIQ
uek
-izF
+lWy
bwm
qnT
lJr
@@ -108488,9 +108379,9 @@ dMO
lWy
rxQ
lWy
-ros
-izF
-izF
+bIQ
+lWy
+lWy
mES
lWy
lWy
@@ -108747,7 +108638,7 @@ bwm
nzD
uoj
bwm
-izF
+lWy
bwm
dMI
lWy
@@ -109001,7 +108892,7 @@ bkF
bwm
bwm
bwm
-ros
+bIQ
bwm
bwm
bwm
@@ -109258,8 +109149,8 @@ bkF
qIO
jXA
bwm
-ros
-vpz
+bIQ
+hXt
bwm
aht
bwm
diff --git a/_maps/map_files/Snaxi/Snaxi.dmm b/_maps/map_files/Snaxi/Snaxi.dmm
index c8b76b4922..43e7915ca4 100644
--- a/_maps/map_files/Snaxi/Snaxi.dmm
+++ b/_maps/map_files/Snaxi/Snaxi.dmm
@@ -1,4 +1,309 @@
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"aaa" = (
+/obj/effect/landmark/event_spawn,
+/mob/living/simple_animal/hostile/retaliate/goat{
+ name = "Pete"
+ },
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/kitchen)
+"aab" = (
+/obj/structure/curtain,
+/obj/machinery/shower{
+ pixel_y = 20
+ },
+/turf/open/floor/plasteel/white,
+/area/crew_quarters/dorms)
+"aac" = (
+/obj/machinery/shower{
+ pixel_y = 20
+ },
+/obj/structure/curtain,
+/turf/open/floor/plasteel/white,
+/area/crew_quarters/dorms)
+"aad" = (
+/obj/item/radio/intercom{
+ name = "Station Intercom (General)";
+ pixel_x = 30
+ },
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/dorms)
+"aae" = (
+/obj/machinery/button/door{
+ id = "Bath1";
+ name = "Door Bolt Control";
+ normaldoorcontrol = 1;
+ pixel_x = 24;
+ pixel_y = -5;
+ specialfunctions = 4
+ },
+/obj/machinery/light/small{
+ dir = 8
+ },
+/obj/structure/toilet/secret/low_loot{
+ pixel_y = 14
+ },
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/dorms)
+"aaf" = (
+/obj/machinery/light,
+/obj/structure/urinal{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/dorms)
+"aag" = (
+/obj/structure/table/reinforced,
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
+ },
+/mob/living/carbon/monkey/punpun,
+/turf/open/floor/plasteel/grimy,
+/area/crew_quarters/bar)
+"aah" = (
+/obj/structure/table/reinforced,
+/obj/item/clothing/glasses/meson{
+ pixel_y = 4
+ },
+/obj/item/cartridge/atmos,
+/obj/item/cartridge/engineering{
+ pixel_x = -3;
+ pixel_y = 2
+ },
+/obj/item/cartridge/engineering{
+ pixel_x = -3;
+ pixel_y = 2
+ },
+/obj/item/cartridge/engineering{
+ pixel_x = -3;
+ pixel_y = 2
+ },
+/obj/item/radio/intercom{
+ dir = 4;
+ name = "Station Intercom (General)";
+ pixel_x = 27
+ },
+/obj/machinery/keycard_auth{
+ pixel_y = -28
+ },
+/mob/living/simple_animal/parrot/Poly,
+/turf/open/floor/plasteel,
+/area/crew_quarters/heads/chief)
+"aai" = (
+/obj/effect/turf_decal/bot,
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/mob/living/simple_animal/sloth/paperwork,
+/turf/open/floor/plasteel,
+/area/quartermaster/storage)
+"aaj" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/effect/turf_decal/bot,
+/obj/machinery/navbeacon{
+ codes_txt = "delivery;dir=8";
+ dir = 8;
+ freq = 1400;
+ location = "QM #1"
+ },
+/obj/machinery/power/apc{
+ areastring = "/area/maintenance/starboard";
+ dir = 4;
+ name = "Starboard Maintenance APC";
+ pixel_x = 26
+ },
+/mob/living/simple_animal/bot/mulebot{
+ beacon_freq = 1400;
+ home_destination = "QM #1";
+ suffix = "#1"
+ },
+/turf/open/floor/pod/dark,
+/area/maintenance/starboard)
+"aak" = (
+/obj/effect/turf_decal/bot,
+/obj/machinery/navbeacon{
+ codes_txt = "delivery;dir=8";
+ dir = 8;
+ freq = 1400;
+ location = "QM #2"
+ },
+/obj/machinery/camera{
+ c_tag = "Cargo Garage";
+ dir = 8
+ },
+/mob/living/simple_animal/bot/mulebot{
+ home_destination = "QM #2";
+ suffix = "#2"
+ },
+/turf/open/floor/pod/dark,
+/area/maintenance/starboard)
+"aal" = (
+/obj/structure/chair{
+ dir = 8
+ },
+/obj/item/radio/intercom{
+ pixel_x = 28
+ },
+/obj/machinery/light_switch{
+ pixel_y = 26
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/camera{
+ c_tag = "Chief Medical Office";
+ dir = 8;
+ network = list("ss13","medbay");
+ pixel_y = -22
+ },
+/mob/living/simple_animal/pet/cat/Runtime,
+/turf/open/floor/plasteel/white,
+/area/crew_quarters/heads/cmo)
+"aam" = (
+/obj/structure/chair/comfy/brown{
+ color = "#596479";
+ dir = 1
+ },
+/mob/living/simple_animal/mouse/brown/Tom,
+/turf/open/floor/plasteel/dark,
+/area/security/prison)
+"aan" = (
+/obj/machinery/camera{
+ c_tag = "Head of Security's Office";
+ dir = 8
+ },
+/obj/structure/bed/dogbed{
+ desc = "A comfy-looking pet bed. You can even strap your pet in, in case the gravity turns off.";
+ name = "pet bed"
+ },
+/obj/item/storage/secure/safe/HoS{
+ pixel_x = 35
+ },
+/mob/living/simple_animal/hostile/retaliate/bat/secbat{
+ desc = "An adorable fruit bat with a cute little hat, may or may not have a reputation for biting out eyeballs, or at least that's what the HoS'd tell you.";
+ name = "Colonel Chomps"
+ },
+/turf/open/floor/carpet,
+/area/crew_quarters/heads/hos)
+"aao" = (
+/obj/structure/closet/emcloset/anchored,
+/obj/structure/sign/directions/medical{
+ dir = 8;
+ icon_state = "direction_med";
+ pixel_y = 36
+ },
+/obj/structure/sign/directions/science{
+ dir = 8;
+ icon_state = "direction_sci";
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/aft)
+"aap" = (
+/obj/machinery/quantumpad{
+ map_pad_id = "5";
+ map_pad_link_id = "6"
+ },
+/obj/structure/sign/directions/evac{
+ pixel_y = 40
+ },
+/obj/structure/sign/directions/security{
+ pixel_y = 32
+ },
+/obj/structure/sign/directions/command{
+ pixel_y = 24
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/aft)
+"aaq" = (
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 6
+ },
+/obj/structure/sign/directions/supply{
+ pixel_x = 32;
+ pixel_y = -36
+ },
+/obj/structure/sign/directions/engineering{
+ dir = 4;
+ icon_state = "direction_eng";
+ pixel_x = 32;
+ pixel_y = -28
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/aft)
+"aar" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/sign/departments/botany,
+/turf/open/floor/plating,
+/area/hydroponics)
+"aas" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/sign/departments/engineering,
+/turf/open/floor/plating,
+/area/engine/engineering)
+"aat" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/structure/cable{
+ icon_state = "0-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/power/apc{
+ areastring = "/area/hallway/primary/fore";
+ dir = 1;
+ name = "Fore Primary Hallway APC";
+ pixel_y = 24
+ },
+/obj/structure/sign/directions/engineering{
+ dir = 4;
+ icon_state = "direction_eng";
+ pixel_x = 0;
+ pixel_y = 40
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/fore)
+"aau" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/sign/departments/custodian{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness)
+"aav" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/structure/disposalpipe/trunk{
+ dir = 1
+ },
+/obj/machinery/disposal/bin,
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness)
"aaw" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -11,10 +316,198 @@
},
/turf/open/floor/plasteel/white,
/area/science/misc_lab)
+"aax" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/sign/departments/cargo,
+/turf/open/floor/plating,
+/area/quartermaster/storage)
+"aay" = (
+/obj/structure/disposalpipe/junction/yjunction{
+ dir = 1
+ },
+/obj/structure/sign/departments/cargo{
+ pixel_x = -32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/fore)
+"aaz" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/structure/disposalpipe/segment,
+/obj/structure/sign/directions/engineering{
+ dir = 1;
+ icon_state = "direction_eng";
+ pixel_x = 32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/fore)
+"aaA" = (
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/structure/sign/warning/pods{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/white/corner{
+ dir = 4
+ },
+/area/hallway/primary/port)
+"aaB" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/structure/sign/departments/chemistry{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"aaC" = (
+/obj/structure/sign/directions/medical{
+ dir = 8;
+ icon_state = "direction_med";
+ pixel_y = 36
+ },
+/obj/structure/sign/directions/science{
+ dir = 8;
+ icon_state = "direction_sci";
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"aaD" = (
+/obj/structure/sign/directions/engineering{
+ dir = 4;
+ icon_state = "direction_eng";
+ pixel_y = 36
+ },
+/obj/structure/sign/directions/supply{
+ dir = 4;
+ icon_state = "direction_supply";
+ pixel_x = 0;
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"aaE" = (
+/obj/structure/sign/directions/evac{
+ pixel_x = -32;
+ pixel_y = -24
+ },
+/obj/structure/sign/directions/security{
+ pixel_x = -32;
+ pixel_y = -32
+ },
+/obj/structure/sign/directions/command{
+ pixel_x = -32;
+ pixel_y = -40
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"aaF" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/obj/structure/sign/departments/science{
+ pixel_x = -32;
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"aaG" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
+ dir = 4
+ },
+/obj/structure/sign/directions/medical{
+ dir = 8;
+ icon_state = "direction_med";
+ pixel_y = 40
+ },
+/obj/structure/sign/directions/science{
+ dir = 8;
+ icon_state = "direction_sci";
+ pixel_y = 32
+ },
+/obj/structure/sign/directions/security{
+ pixel_y = 24
+ },
+/turf/open/floor/plating/snowed/smoothed/icemoon,
+/area/icemoon/surface/outdoors)
"aaH" = (
/obj/machinery/smartfridge/chemistry/preloaded,
/turf/closed/wall,
/area/medical/chemistry)
+"aaI" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
+ dir = 4
+ },
+/obj/structure/sign/directions/engineering{
+ dir = 4;
+ icon_state = "direction_eng";
+ pixel_y = 40
+ },
+/obj/structure/sign/directions/supply{
+ dir = 4;
+ icon_state = "direction_supply";
+ pixel_x = 0;
+ pixel_y = 32
+ },
+/obj/structure/sign/directions/evac{
+ pixel_y = 24
+ },
+/turf/open/floor/plating/snowed/smoothed/icemoon,
+/area/icemoon/surface/outdoors)
+"aaJ" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/sign/departments/evac,
+/turf/open/floor/plating,
+/area/hallway/secondary/exit/departure_lounge)
+"aaK" = (
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/item/radio/intercom{
+ pixel_y = 25
+ },
+/obj/structure/sign/directions/evac{
+ dir = 4;
+ pixel_x = 0;
+ pixel_y = 40
+ },
+/turf/open/floor/plasteel/white/corner{
+ dir = 4
+ },
+/area/hallway/secondary/exit/departure_lounge)
+"aaL" = (
+/obj/structure/sign/departments/restroom{
+ pixel_x = 32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/grimy,
+/area/crew_quarters/fitness/recreation)
"aaM" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
/obj/machinery/atmospherics/components/binary/valve{
@@ -22,6 +515,24 @@
},
/turf/open/floor/plating/asteroid/snow/icemoon,
/area/icemoon/surface/outdoors)
+"aaN" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/obj/machinery/quantumpad{
+ map_pad_id = "1";
+ map_pad_link_id = "2"
+ },
+/obj/structure/sign/directions/medical{
+ dir = 8;
+ icon_state = "direction_med";
+ pixel_y = 36
+ },
+/obj/structure/sign/directions/science{
+ dir = 8;
+ icon_state = "direction_sci";
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel,
+/area/quartermaster/miningdock)
"aaO" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 9
@@ -36,13 +547,155 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
+"aaQ" = (
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
+/obj/machinery/computer/shuttle/snow_taxi,
+/obj/structure/sign/directions/supply{
+ dir = 4;
+ icon_state = "direction_supply";
+ pixel_x = 0;
+ pixel_y = 36
+ },
+/obj/structure/sign/directions/engineering{
+ dir = 4;
+ icon_state = "direction_eng";
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel,
+/area/quartermaster/miningdock)
+"aaR" = (
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
"aaS" = (
/turf/closed/wall/r_wall,
/area/medical/surgery)
+"aaT" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"aaU" = (
+/obj/structure/sign/departments/restroom{
+ pixel_x = 32
+ },
+/turf/open/floor/carpet,
+/area/crew_quarters/dorms)
+"aaV" = (
+/obj/structure/sign/directions/evac{
+ dir = 1;
+ icon_state = "direction_evac";
+ pixel_y = 8
+ },
+/obj/structure/sign/directions/security{
+ dir = 8;
+ icon_state = "direction_sec";
+ pixel_x = 0;
+ pixel_y = 0
+ },
+/obj/structure/sign/directions/command{
+ dir = 8;
+ icon_state = "direction_bridge";
+ pixel_y = -8
+ },
+/turf/closed/wall/r_wall,
+/area/hallway/primary/central)
+"aaW" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/sign/departments/security,
+/turf/open/floor/plating,
+/area/hallway/primary/central)
+"aaX" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"aaY" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"aaZ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/sign/mining{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
"aba" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/medical/surgery)
+"abb" = (
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abc" = (
+/obj/structure/sign/directions/command{
+ pixel_x = 32;
+ pixel_y = -40
+ },
+/obj/structure/sign/directions/supply{
+ dir = 4;
+ icon_state = "direction_supply";
+ pixel_x = 32;
+ pixel_y = -24
+ },
+/obj/structure/sign/directions/science{
+ dir = 4;
+ pixel_x = 32;
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abd" = (
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
"abe" = (
/obj/structure/table/wood,
/obj/machinery/computer/security/wooden_tv,
@@ -52,14 +705,308 @@
},
/turf/open/floor/wood,
/area/maintenance/bar)
+"abf" = (
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abg" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abh" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/structure/reagent_dispensers/watertank,
+/obj/item/radio/intercom{
+ pixel_y = -26
+ },
+/obj/structure/sign/departments/xenobio{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel/white,
+/area/science/misc_lab)
+"abi" = (
+/obj/machinery/airalarm{
+ dir = 8;
+ pixel_x = 24
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abj" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/structure/sign/departments/holy{
+ pixel_x = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
"abk" = (
/obj/machinery/light,
/turf/open/floor/plasteel/dark,
/area/ai_monitored/security/armory)
+"abl" = (
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/sign/departments/holy{
+ pixel_x = -32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abm" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/structure/sign/directions/evac{
+ dir = 8;
+ icon_state = "direction_evac";
+ pixel_x = 32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abn" = (
+/obj/structure/sign/poster/official/ian,
+/turf/closed/wall,
+/area/crew_quarters/heads/hop)
+"abo" = (
+/obj/effect/landmark/start/assistant,
+/obj/structure/sign/poster/official/build{
+ pixel_x = -32;
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/storage/primary)
+"abp" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/effect/turf_decal/tile/brown,
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/filingcabinet,
+/turf/open/floor/plasteel,
+/area/quartermaster/storage)
+"abq" = (
+/obj/structure/toilet{
+ contents = newlist(/obj/item/toy/snappop/phoenix);
+ dir = 4
+ },
+/obj/machinery/light/small{
+ dir = 1;
+ light_color = "#ffc1c1"
+ },
+/turf/open/floor/plasteel/freezer,
+/area/hallway/primary/port)
+"abr" = (
+/obj/structure/sink/kitchen{
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel/freezer,
+/area/hallway/primary/port)
"abs" = (
/obj/structure/table/optable,
/turf/open/floor/plasteel/freezer,
/area/medical/surgery)
+"abt" = (
+/obj/machinery/door/airlock{
+ name = "Unisex Restroom"
+ },
+/turf/open/floor/plasteel/freezer,
+/area/hallway/primary/port)
+"abu" = (
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/structure/sign/departments/restroom{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"abv" = (
+/obj/effect/turf_decal/tile/green{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/green{
+ dir = 8
+ },
+/obj/machinery/camera{
+ c_tag = "Hydroponics North"
+ },
+/obj/structure/disposalpipe/trunk{
+ dir = 8
+ },
+/obj/machinery/disposal/bin,
+/obj/structure/sign/poster/official/hydro_ad{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/dark,
+/area/hydroponics)
+"abw" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/bar,
+/obj/structure/disposalpipe/segment,
+/obj/structure/sign/poster/official/high_class_martini{
+ pixel_x = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/aft)
+"abx" = (
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/structure/table/wood,
+/obj/structure/sign/poster/official/soft_cap_pop_art{
+ pixel_x = -32
+ },
+/turf/open/floor/wood,
+/area/crew_quarters/bar)
+"aby" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/machinery/computer/arcade/minesweeper{
+ dir = 8
+ },
+/obj/structure/sign/poster/official/nanomichi_ad{
+ pixel_x = 32
+ },
+/turf/open/floor/wood,
+/area/crew_quarters/bar)
+"abz" = (
+/obj/structure/chair/sofa/right{
+ dir = 1
+ },
+/obj/structure/sign/poster/official/fruit_bowl{
+ pixel_y = -32
+ },
+/turf/open/floor/wood,
+/area/crew_quarters/bar)
+"abA" = (
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 9
+ },
+/obj/structure/sign/poster/official/fashion{
+ pixel_y = -32
+ },
+/turf/open/floor/carpet,
+/area/crew_quarters/dorms)
+"abB" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/structure/sign/poster/official/report_crimes{
+ pixel_x = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/fore)
+"abC" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/machinery/door/airlock/external{
+ req_one_access_txt = "13,8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper,
+/turf/open/floor/plating,
+/area/maintenance/port/fore)
+"abD" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/machinery/door/airlock/external{
+ req_one_access_txt = "13,8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/fore)
+"abE" = (
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/camera{
+ c_tag = "Medbay Cryogenics";
+ network = list("ss13","medbay")
+ },
+/obj/structure/sign/poster/official/help_others{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/central)
+"abF" = (
+/obj/effect/turf_decal/tile/red,
+/obj/effect/turf_decal/tile/red{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
+/obj/structure/closet/secure_closet/security/engine,
+/obj/item/radio/intercom{
+ pixel_y = -26
+ },
+/obj/machinery/camera{
+ c_tag = "Security Post - Cargo";
+ dir = 1
+ },
+/obj/structure/sign/poster/official/do_not_question{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel,
+/area/security/checkpoint/supply)
"abG" = (
/obj/effect/turf_decal/stripes/corner{
dir = 4
@@ -67,11 +1014,160 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/turf/open/floor/plasteel,
/area/engine/atmospherics_engine)
+"abH" = (
+/obj/structure/table,
+/obj/item/storage/firstaid/brute,
+/obj/item/storage/firstaid/brute{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/structure/sign/poster/official/medical_green_cross{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/central)
+"abI" = (
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/yellow,
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/sign/poster/official/safety_eye_protection{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/chemistry)
+"abJ" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/structure/sign/poster/official/walk{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"abK" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/structure/sign/poster/official/build{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/port)
+"abL" = (
+/obj/structure/table,
+/obj/item/mmi,
+/obj/item/mmi,
+/obj/item/mmi,
+/obj/structure/sign/poster/official/state_laws{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/white,
+/area/science/robotics/lab)
+"abM" = (
+/obj/structure/closet/secure_closet/security/med,
+/obj/effect/turf_decal/tile/red,
+/obj/effect/turf_decal/tile/red{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 8
+ },
+/obj/machinery/camera{
+ c_tag = "Security Post - Medbay";
+ dir = 1
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/structure/sign/poster/official/here_for_your_safety{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/security/checkpoint/medical)
+"abN" = (
+/obj/machinery/light,
+/obj/machinery/camera{
+ c_tag = "Escape Arm Southwest";
+ dir = 1
+ },
+/obj/structure/closet/crate/bin,
+/obj/structure/sign/directions/security{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/secondary/exit/departure_lounge)
+"abO" = (
+/obj/machinery/light,
+/obj/structure/closet/crate/bin,
+/obj/structure/sign/directions/command{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/secondary/exit/departure_lounge)
+"abP" = (
+/obj/structure/chair{
+ dir = 1
+ },
+/obj/structure/sign/poster/official/cohiba_robusto_ad{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/secondary/exit/departure_lounge)
"abQ" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/effect/landmark/event_spawn,
/turf/open/floor/wood,
/area/crew_quarters/theatre)
+"abR" = (
+/obj/structure/chair/stool,
+/obj/structure/sign/poster/official/foam_force_ad{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel/grimy,
+/area/crew_quarters/fitness/recreation)
+"abS" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
+ },
+/obj/structure/sign/poster/official/no_erp{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel,
+/area/quartermaster/miningoffice)
+"abT" = (
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
+/obj/structure/disposalpipe/segment,
+/obj/structure/sign/directions/evac{
+ dir = 8;
+ icon_state = "direction_evac";
+ pixel_x = 32;
+ pixel_y = 40
+ },
+/obj/structure/sign/directions/engineering{
+ dir = 4;
+ icon_state = "direction_eng";
+ pixel_x = 32;
+ pixel_y = 24
+ },
+/obj/structure/sign/directions/medical{
+ dir = 4;
+ pixel_x = 32;
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
"abU" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -81,6 +1177,25 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
+"abV" = (
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/structure/sign/poster/official/obey{
+ pixel_x = -32
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/central)
+"abW" = (
+/obj/structure/tank_dispenser/oxygen,
+/obj/machinery/camera/motion{
+ c_tag = "Armory Motion Sensor North"
+ },
+/obj/structure/sign/poster/official/ion_rifle{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/dark,
+/area/ai_monitored/security/armory)
"abX" = (
/obj/machinery/airalarm{
pixel_y = 28
@@ -98,6 +1213,15 @@
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
+"abY" = (
+/obj/machinery/computer/camera_advanced/xenobio{
+ dir = 1
+ },
+/obj/structure/sign/poster/official/anniversary_vintage_reprint{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/white,
+/area/science/xenobiology)
"abZ" = (
/obj/effect/landmark/start/medical_doctor,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
@@ -105,6 +1229,38 @@
},
/turf/open/floor/plasteel/freezer,
/area/medical/surgery)
+"aca" = (
+/obj/structure/cable{
+ icon_state = "0-4"
+ },
+/obj/machinery/camera{
+ c_tag = "Brig Evidence Storage"
+ },
+/obj/structure/sign/poster/official/space_cops{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/dark,
+/area/security/main)
+"acb" = (
+/obj/structure/sign/poster/official/science{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/white,
+/area/science/mixing)
+"acc" = (
+/obj/structure/sign/poster/contraband/lusty_xenomorph{
+ pixel_x = -32;
+ pixel_y = -32
+ },
+/turf/open/floor/plating,
+/area/maintenance/aft/secondary)
+"acd" = (
+/obj/structure/reagent_dispensers/watertank,
+/obj/structure/sign/poster/contraband/bountyhunters{
+ pixel_x = 32
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"ace" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -114,6 +1270,19 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
+"acf" = (
+/obj/structure/chair/stool,
+/obj/structure/sign/poster/official/bless_this_spess{
+ pixel_x = -32
+ },
+/turf/open/floor/carpet,
+/area/chapel/main)
+"acg" = (
+/obj/structure/sign/poster/official/wtf_is_co2{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel,
+/area/science/storage)
"acj" = (
/obj/effect/landmark/blobstart,
/turf/open/floor/plating,
@@ -772,16 +1941,6 @@
},
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
-"aon" = (
-/obj/effect/turf_decal/tile/yellow{
- dir = 8
- },
-/obj/effect/turf_decal/tile/yellow,
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/open/floor/plasteel/white,
-/area/medical/chemistry)
"aoo" = (
/obj/structure/table/glass,
/obj/machinery/reagentgrinder{
@@ -915,9 +2074,6 @@
},
/turf/open/floor/plasteel/dark,
/area/tcommsat/computer)
-"arG" = (
-/turf/open/floor/plating,
-/area/medical/medbay/central)
"arH" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -1548,7 +2704,7 @@
/turf/open/floor/plasteel/white,
/area/science/lab)
"ayu" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-16"
},
/obj/effect/turf_decal/tile/purple{
@@ -2950,24 +4106,6 @@
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/engine/engineering)
-"aOl" = (
-/obj/structure/closet/secure_closet/security/med,
-/obj/effect/turf_decal/tile/red,
-/obj/effect/turf_decal/tile/red{
- dir = 4
- },
-/obj/effect/turf_decal/tile/red{
- dir = 8
- },
-/obj/machinery/camera{
- c_tag = "Security Post - Medbay";
- dir = 1
- },
-/obj/machinery/light{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/security/checkpoint/medical)
"aOm" = (
/obj/effect/turf_decal/tile/red,
/obj/effect/turf_decal/tile/red{
@@ -3023,7 +4161,7 @@
/area/engine/supermatter)
"aOP" = (
/obj/structure/table/wood,
-/obj/item/storage/pill_bottle/dice,
+/obj/item/storage/box/dice,
/turf/open/floor/plasteel/dark,
/area/security/prison)
"aPw" = (
@@ -4937,13 +6075,6 @@
},
/turf/open/floor/carpet,
/area/hallway/primary/central)
-"bBB" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"bBH" = (
/obj/structure/cable{
icon_state = "0-4"
@@ -6489,10 +7620,6 @@
/obj/machinery/holopad,
/turf/open/floor/carpet,
/area/hallway/secondary/exit/departure_lounge)
-"bQf" = (
-/obj/structure/closet/emcloset/anchored,
-/turf/open/floor/plasteel,
-/area/hallway/primary/aft)
"bQg" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -7161,15 +8288,6 @@
/obj/structure/closet/crate/coffin,
/turf/open/floor/wood,
/area/chapel/office)
-"cbz" = (
-/obj/structure/cable{
- icon_state = "0-4"
- },
-/obj/machinery/camera{
- c_tag = "Brig Evidence Storage"
- },
-/turf/open/floor/plasteel/dark,
-/area/security/main)
"cbL" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -7757,7 +8875,7 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/carpet,
@@ -8466,15 +9584,6 @@
},
/turf/open/floor/plasteel,
/area/storage/primary)
-"cGQ" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/machinery/light{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"cGZ" = (
/obj/machinery/light{
dir = 8
@@ -8829,18 +9938,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
-"cSv" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/structure/disposalpipe/trunk{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/crew_quarters/fitness)
"cSC" = (
/obj/effect/landmark/event_spawn,
/turf/open/floor/plasteel/white,
@@ -9031,7 +10128,7 @@
/obj/structure/cable{
icon_state = "2-8"
},
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/plasteel/dark,
@@ -9409,7 +10506,7 @@
/turf/open/floor/plasteel,
/area/hallway/primary/fore)
"dij" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/carpet,
@@ -9806,14 +10903,6 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
-"dvh" = (
-/obj/structure/table/reinforced,
-/mob/living/carbon/monkey/punpun,
-/obj/machinery/door/firedoor/border_only{
- name = "south facing firelock"
- },
-/turf/open/floor/plasteel/grimy,
-/area/crew_quarters/bar)
"dvs" = (
/obj/machinery/door/airlock/public/glass{
name = "Snow Airlock"
@@ -10028,19 +11117,6 @@
/obj/machinery/rnd/production/techfab/department/cargo,
/turf/open/floor/plasteel,
/area/quartermaster/storage)
-"dDf" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/fore)
"dDC" = (
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
@@ -10876,15 +11952,6 @@
},
/turf/open/floor/plasteel,
/area/science/robotics/lab)
-"eeh" = (
-/obj/machinery/light,
-/obj/machinery/camera{
- c_tag = "Escape Arm Southwest";
- dir = 1
- },
-/obj/structure/closet/crate/bin,
-/turf/open/floor/plasteel,
-/area/hallway/secondary/exit/departure_lounge)
"eex" = (
/obj/machinery/atmospherics/pipe/simple/general/visible,
/obj/machinery/meter,
@@ -11361,7 +12428,7 @@
/turf/open/floor/plasteel,
/area/janitor)
"eue" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-04"
},
/obj/effect/turf_decal/tile/blue{
@@ -11404,13 +12471,6 @@
dir = 8
},
/area/hallway/primary/fore)
-"evr" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/door/firedoor/border_only{
- name = "south facing firelock"
- },
-/turf/open/floor/plasteel,
-/area/quartermaster/miningoffice)
"evI" = (
/obj/machinery/atmospherics/components/trinary/filter/atmos/n2{
dir = 1
@@ -11633,10 +12693,6 @@
},
/turf/open/floor/plating,
/area/engine/storage)
-"eEa" = (
-/obj/machinery/light,
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/dorms)
"eEy" = (
/obj/machinery/doorButtons/access_button{
idDoor = "virology_airlock_interior";
@@ -11671,15 +12727,6 @@
},
/turf/open/floor/plasteel/dark,
/area/teleporter)
-"eFy" = (
-/obj/machinery/light{
- dir = 4
- },
-/obj/machinery/computer/arcade/minesweeper{
- dir = 8
- },
-/turf/open/floor/wood,
-/area/crew_quarters/bar)
"eFB" = (
/obj/structure/table/wood,
/obj/item/reagent_containers/rag,
@@ -12087,19 +13134,6 @@
},
/turf/open/floor/wood,
/area/crew_quarters/bar)
-"eOK" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/hallway/primary/central)
"eOO" = (
/obj/structure/weightmachine/weightlifter,
/turf/open/floor/plasteel,
@@ -12380,13 +13414,6 @@
/obj/structure/table,
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
-"eZn" = (
-/obj/structure/tank_dispenser/oxygen,
-/obj/machinery/camera/motion{
- c_tag = "Armory Motion Sensor North"
- },
-/turf/open/floor/plasteel/dark,
-/area/ai_monitored/security/armory)
"eZA" = (
/obj/structure/cable{
icon_state = "0-4"
@@ -12857,14 +13884,6 @@
},
/turf/open/floor/engine/co2,
/area/engine/atmos)
-"fnu" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/obj/machinery/quantumpad{
- map_pad_id = "1";
- map_pad_link_id = "2"
- },
-/turf/open/floor/plasteel,
-/area/quartermaster/miningdock)
"fnx" = (
/obj/machinery/light{
dir = 1
@@ -12948,24 +13967,6 @@
},
/turf/open/floor/plasteel/white,
/area/science/robotics/lab)
-"fpW" = (
-/obj/effect/turf_decal/bot,
-/mob/living/simple_animal/bot/mulebot{
- home_destination = "QM #2";
- suffix = "#2"
- },
-/obj/machinery/navbeacon{
- codes_txt = "delivery;dir=8";
- dir = 8;
- freq = 1400;
- location = "QM #2"
- },
-/obj/machinery/camera{
- c_tag = "Cargo Garage";
- dir = 8
- },
-/turf/open/floor/pod/dark,
-/area/maintenance/starboard)
"fqj" = (
/obj/machinery/field/generator,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
@@ -13098,11 +14099,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall,
/area/storage/eva)
-"fuy" = (
-/obj/machinery/light,
-/obj/structure/closet/crate/bin,
-/turf/open/floor/plasteel,
-/area/hallway/secondary/exit/departure_lounge)
"fuB" = (
/obj/machinery/camera{
c_tag = "Auxiliary Bridge North";
@@ -13699,13 +14695,6 @@
},
/turf/open/floor/plating,
/area/storage/atmos)
-"fNd" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/engine/engineering)
"fNh" = (
/obj/structure/cable,
/turf/open/floor/plating/snowed/smoothed/icemoon,
@@ -15081,18 +16070,6 @@
/obj/machinery/power/port_gen/pacman,
/turf/open/floor/plating,
/area/engine/storage)
-"gEz" = (
-/obj/structure/cable{
- icon_state = "1-4"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/structure/disposalpipe/segment{
- dir = 9
- },
-/turf/open/floor/carpet,
-/area/crew_quarters/dorms)
"gFb" = (
/obj/machinery/vending/wardrobe/law_wardrobe,
/obj/item/radio/intercom{
@@ -15277,19 +16254,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
-"gKB" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/machinery/light{
- dir = 4
- },
-/obj/structure/reagent_dispensers/watertank,
-/obj/item/radio/intercom{
- pixel_y = -26
- },
-/turf/open/floor/plasteel/white,
-/area/science/misc_lab)
"gKR" = (
/obj/machinery/mineral/equipment_vendor,
/obj/structure/disposalpipe/segment{
@@ -15589,13 +16553,6 @@
},
/turf/open/floor/plating,
/area/maintenance/solars/port/aft)
-"gRS" = (
-/obj/machinery/light{
- dir = 8
- },
-/obj/structure/table/wood,
-/turf/open/floor/wood,
-/area/crew_quarters/bar)
"gSh" = (
/obj/structure/cable{
icon_state = "1-8"
@@ -16190,31 +17147,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/port)
-"hnB" = (
-/obj/structure/chair{
- dir = 8
- },
-/obj/item/radio/intercom{
- pixel_x = 28
- },
-/obj/machinery/light_switch{
- pixel_y = 26
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/mob/living/simple_animal/pet/cat/Runtime,
-/obj/machinery/camera{
- c_tag = "Chief Medical Office";
- dir = 8;
- network = list("ss13","medbay");
- pixel_y = -22
- },
-/turf/open/floor/plasteel/white,
-/area/crew_quarters/heads/cmo)
"hnO" = (
/obj/machinery/atmospherics/components/unary/cryo_cell,
/turf/open/floor/plasteel/white,
@@ -16876,12 +17808,6 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
-"hGM" = (
-/obj/structure/urinal{
- pixel_y = 32
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/dorms)
"hGU" = (
/obj/structure/closet/secure_closet/personal/cabinet{
pixel_x = -8
@@ -17394,7 +18320,7 @@
/obj/machinery/light{
dir = 4
},
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/wood,
@@ -17876,14 +18802,6 @@
/obj/structure/closet/crate/coffin,
/turf/open/floor/wood,
/area/chapel/office)
-"ifQ" = (
-/mob/living/simple_animal/mouse/brown/Tom,
-/obj/structure/chair/comfy/brown{
- color = "#596479";
- dir = 1
- },
-/turf/open/floor/plasteel/dark,
-/area/security/prison)
"ifT" = (
/obj/structure/cable{
icon_state = "0-4"
@@ -19714,19 +20632,6 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
-"jiV" = (
-/obj/structure/table,
-/obj/item/storage/firstaid/brute,
-/obj/item/storage/firstaid/brute{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/obj/effect/turf_decal/tile/blue,
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/central)
"jiY" = (
/obj/effect/turf_decal/tile/brown{
dir = 1
@@ -20465,10 +21370,6 @@
"jJu" = (
/turf/closed/wall/r_wall,
/area/medical/medbay/zone3)
-"jKb" = (
-/obj/effect/landmark/start/assistant,
-/turf/open/floor/plasteel,
-/area/storage/primary)
"jKF" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -22194,19 +23095,6 @@
},
/turf/open/floor/engine,
/area/engine/atmospherics_engine)
-"kPj" = (
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"kPn" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
@@ -22642,7 +23530,7 @@
/turf/open/floor/engine,
/area/engine/engineering)
"lfs" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-08"
},
/turf/open/floor/plasteel,
@@ -24381,24 +25269,6 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
-"mkm" = (
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/machinery/power/apc{
- areastring = "/area/hallway/primary/fore";
- dir = 1;
- name = "Fore Primary Hallway APC";
- pixel_y = 24
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/fore)
"mkr" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -24799,13 +25669,6 @@
/obj/machinery/telecomms/processor/preset_four,
/turf/open/floor/plasteel/dark/telecomms,
/area/tcommsat/server)
-"mzB" = (
-/obj/structure/table,
-/obj/item/mmi,
-/obj/item/mmi,
-/obj/item/mmi,
-/turf/open/floor/plasteel/white,
-/area/science/robotics/lab)
"mAk" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 10
@@ -25362,22 +26225,6 @@
},
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/dorms)
-"mQo" = (
-/obj/effect/turf_decal/tile/green{
- dir = 1
- },
-/obj/effect/turf_decal/tile/green{
- dir = 8
- },
-/obj/machinery/camera{
- c_tag = "Hydroponics North"
- },
-/obj/structure/disposalpipe/trunk{
- dir = 8
- },
-/obj/machinery/disposal/bin,
-/turf/open/floor/plasteel/dark,
-/area/hydroponics)
"mQC" = (
/obj/machinery/airalarm{
dir = 1;
@@ -26124,12 +26971,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/medical/genetics)
-"nmY" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"nnj" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -26162,14 +27003,6 @@
},
/turf/open/floor/plasteel,
/area/hydroponics)
-"noB" = (
-/obj/effect/turf_decal/bot,
-/mob/living/simple_animal/sloth/paperwork,
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/quartermaster/storage)
"noQ" = (
/obj/effect/spawner/structure/window/plasma/reinforced,
/turf/open/floor/plating,
@@ -26788,34 +27621,6 @@
},
/turf/open/floor/plasteel,
/area/engine/atmos)
-"nGa" = (
-/obj/structure/cable,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/machinery/light{
- dir = 4
- },
-/obj/effect/turf_decal/bot,
-/mob/living/simple_animal/bot/mulebot{
- beacon_freq = 1400;
- home_destination = "QM #1";
- suffix = "#1"
- },
-/obj/machinery/navbeacon{
- codes_txt = "delivery;dir=8";
- dir = 8;
- freq = 1400;
- location = "QM #1"
- },
-/obj/machinery/power/apc{
- areastring = "/area/maintenance/starboard";
- dir = 4;
- name = "Starboard Maintenance APC";
- pixel_x = 26
- },
-/turf/open/floor/pod/dark,
-/area/maintenance/starboard)
"nGd" = (
/obj/effect/turf_decal/delivery,
/obj/machinery/portable_atmospherics/canister/toxins,
@@ -26886,7 +27691,7 @@
"nIM" = (
/obj/structure/table/wood/poker,
/obj/item/toy/cards/deck,
-/obj/item/storage/pill_bottle/dice{
+/obj/item/storage/box/dice{
pixel_x = 8
},
/obj/structure/sign/poster/contraband/random{
@@ -27753,9 +28558,6 @@
},
/turf/open/floor/plating/asteroid/snow/icemoon,
/area/engine/atmospherics_engine)
-"oiX" = (
-/turf/closed/wall,
-/area/crew_quarters/heads/hop)
"oje" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -27858,7 +28660,7 @@
/turf/open/floor/carpet,
/area/quartermaster/miningoffice)
"old" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "applebush"
},
/turf/open/floor/wood,
@@ -28531,7 +29333,7 @@
/turf/open/floor/carpet,
/area/crew_quarters/heads/hop)
"oGU" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/wood,
@@ -28735,23 +29537,6 @@
/obj/effect/landmark/event_spawn,
/turf/open/floor/plasteel/dark,
/area/ai_monitored/turret_protected/ai_upload_foyer)
-"oLT" = (
-/obj/effect/turf_decal/tile/red{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/machinery/light{
- dir = 1
- },
-/obj/item/radio/intercom{
- pixel_y = 25
- },
-/turf/open/floor/plasteel/white/corner{
- dir = 4
- },
-/area/hallway/secondary/exit/departure_lounge)
"oME" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -29572,13 +30357,6 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
-"pkh" = (
-/mob/living/simple_animal/hostile/retaliate/goat{
- name = "Pete"
- },
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/kitchen)
"pkJ" = (
/turf/open/floor/wood{
icon_state = "wood-broken6"
@@ -29602,7 +30380,7 @@
c_tag = "Courtroom East";
dir = 8
},
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "applebush"
},
/turf/open/floor/wood,
@@ -30303,20 +31081,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
/area/hallway/primary/central)
-"pCj" = (
-/obj/structure/sink{
- dir = 8;
- pixel_x = -12;
- pixel_y = 2
- },
-/obj/structure/mirror{
- pixel_x = -28
- },
-/obj/structure/urinal{
- pixel_y = 32
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/dorms)
"pCo" = (
/obj/machinery/atmospherics/pipe/simple/orange/visible{
dir = 9
@@ -30909,12 +31673,6 @@
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
-"pUz" = (
-/obj/structure/disposalpipe/junction/yjunction{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/fore)
"pUP" = (
/obj/machinery/door/airlock/public/glass{
name = "Chapel"
@@ -31083,15 +31841,6 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
-"qbh" = (
-/obj/structure/cable{
- icon_state = "2-4"
- },
-/obj/machinery/light{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
"qbr" = (
/obj/effect/turf_decal/tile/red{
dir = 4
@@ -31877,13 +32626,6 @@
},
/turf/open/floor/plating/asteroid/snow/icemoon,
/area/icemoon/surface/outdoors)
-"qAq" = (
-/obj/machinery/quantumpad{
- map_pad_id = "5";
- map_pad_link_id = "6"
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/aft)
"qAx" = (
/obj/structure/disposalpipe/segment{
dir = 9
@@ -32153,7 +32895,7 @@
/turf/open/floor/carpet,
/area/crew_quarters/dorms)
"qHO" = (
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21"
},
/turf/open/floor/plasteel,
@@ -32343,7 +33085,7 @@
/area/bridge)
"qMN" = (
/obj/structure/table,
-/obj/item/storage/pill_bottle/dice,
+/obj/item/storage/box/dice,
/turf/open/floor/plasteel/grimy,
/area/crew_quarters/fitness/recreation)
"qNB" = (
@@ -32961,7 +33703,7 @@
dir = 4
},
/obj/effect/turf_decal/tile/neutral,
-/obj//obj/item/kirbyplants,
+/obj/item/kirbyplants,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness)
"rhX" = (
@@ -33777,35 +34519,6 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
-"rFQ" = (
-/obj/structure/table/reinforced,
-/mob/living/simple_animal/parrot/Poly,
-/obj/item/clothing/glasses/meson{
- pixel_y = 4
- },
-/obj/item/cartridge/atmos,
-/obj/item/cartridge/engineering{
- pixel_x = -3;
- pixel_y = 2
- },
-/obj/item/cartridge/engineering{
- pixel_x = -3;
- pixel_y = 2
- },
-/obj/item/cartridge/engineering{
- pixel_x = -3;
- pixel_y = 2
- },
-/obj/item/radio/intercom{
- dir = 4;
- name = "Station Intercom (General)";
- pixel_x = 27
- },
-/obj/machinery/keycard_auth{
- pixel_y = -28
- },
-/turf/open/floor/plasteel,
-/area/crew_quarters/heads/chief)
"rGc" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 6
@@ -34298,10 +35011,6 @@
},
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
-"rYN" = (
-/obj/structure/chair/stool,
-/turf/open/floor/carpet,
-/area/chapel/main)
"rYQ" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 10
@@ -34346,7 +35055,7 @@
/area/engine/engineering)
"saN" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/plasteel,
@@ -34519,16 +35228,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness)
-"seR" = (
-/obj/machinery/airalarm{
- dir = 8;
- pixel_x = 24
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"seZ" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
@@ -34785,15 +35484,6 @@
/obj/machinery/computer/card,
/turf/open/floor/wood,
/area/crew_quarters/heads/captain)
-"soN" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 1
- },
-/obj/effect/turf_decal/tile/yellow{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/port)
"spa" = (
/obj/structure/disposalpipe/segment{
dir = 10
@@ -34837,7 +35527,7 @@
dir = 8
},
/obj/effect/turf_decal/tile/blue,
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/plasteel/dark,
@@ -35302,16 +35992,6 @@
/obj/effect/turf_decal/stripes/corner,
/turf/open/floor/engine,
/area/engine/engineering)
-"sIn" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/obj/machinery/door/airlock/external{
- req_one_access_txt = "13,8"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plating,
-/area/maintenance/port/fore)
"sIT" = (
/obj/structure/reagent_dispensers/fueltank,
/turf/open/floor/pod/dark,
@@ -36237,7 +36917,7 @@
/obj/effect/turf_decal/tile/red{
dir = 4
},
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/plasteel/dark,
@@ -37160,18 +37840,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/carpet,
/area/hallway/secondary/exit/departure_lounge)
-"tJL" = (
-/obj/structure/cable{
- icon_state = "2-4"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 6
- },
-/obj/structure/disposalpipe/segment{
- dir = 6
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/aft)
"tKa" = (
/obj/machinery/door/airlock/security/glass{
id_tag = "innerbrig";
@@ -37430,24 +38098,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/exit/departure_lounge)
-"tQd" = (
-/obj/effect/turf_decal/tile/red,
-/obj/effect/turf_decal/tile/red{
- dir = 4
- },
-/obj/effect/turf_decal/tile/red{
- dir = 8
- },
-/obj/structure/closet/secure_closet/security/engine,
-/obj/item/radio/intercom{
- pixel_y = -26
- },
-/obj/machinery/camera{
- c_tag = "Security Post - Cargo";
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/security/checkpoint/supply)
"tQv" = (
/obj/effect/turf_decal/tile/purple,
/obj/effect/turf_decal/tile/purple{
@@ -37694,11 +38344,6 @@
},
/turf/open/floor/plasteel,
/area/science/robotics/mechbay)
-"tWx" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
-/obj/structure/disposalpipe/segment,
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"tXn" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -38012,23 +38657,6 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/carpet,
/area/crew_quarters/dorms)
-"ugr" = (
-/obj/machinery/button/door{
- id = "Bath1";
- name = "Door Bolt Control";
- normaldoorcontrol = 1;
- pixel_x = 24;
- pixel_y = -5;
- specialfunctions = 4
- },
-/obj/machinery/shower{
- pixel_y = 20
- },
-/obj/machinery/light/small{
- dir = 8
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/dorms)
"uha" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -39813,16 +40441,6 @@
/obj/machinery/meter,
/turf/open/floor/engine,
/area/engine/engineering)
-"vlz" = (
-/obj/structure/urinal{
- pixel_y = 32
- },
-/obj/item/radio/intercom{
- name = "Station Intercom (General)";
- pixel_x = 30
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/dorms)
"vlC" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
@@ -42975,24 +43593,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
/area/hallway/primary/central)
-"xdr" = (
-/obj/machinery/camera{
- c_tag = "Head of Security's Office";
- dir = 8
- },
-/obj/structure/bed/dogbed{
- desc = "A comfy-looking pet bed. You can even strap your pet in, in case the gravity turns off.";
- name = "pet bed"
- },
-/mob/living/simple_animal/hostile/retaliate/bat/secbat{
- desc = "An adorable fruit bat with a cute little hat, may or may not have a reputation for biting out eyeballs, or at least that's what the HoS'd tell you.";
- name = "Colonel Chomps"
- },
-/obj/item/storage/secure/safe/HoS{
- pixel_x = 35
- },
-/turf/open/floor/carpet,
-/area/crew_quarters/heads/hos)
"xdD" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{
dir = 4
@@ -43119,9 +43719,6 @@
},
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
-"xhH" = (
-/turf/closed/wall/r_wall,
-/area/hallway/primary/central)
"xhV" = (
/obj/effect/turf_decal/bot_white,
/obj/structure/window/reinforced{
@@ -43182,7 +43779,7 @@
/obj/structure/cable{
icon_state = "0-4"
},
-/obj//obj/item/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/obj/machinery/power/apc{
@@ -43201,20 +43798,6 @@
/obj/machinery/vending/snack/random,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness)
-"xlg" = (
-/obj/machinery/atmospherics/components/unary/thermomachine/freezer,
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/machinery/camera{
- c_tag = "Medbay Cryogenics";
- network = list("ss13","medbay")
- },
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/central)
"xlm" = (
/obj/machinery/vending/wardrobe/atmos_wardrobe,
/turf/open/floor/plasteel,
@@ -43318,11 +43901,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel/grimy,
/area/crew_quarters/bar)
-"xou" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
-/obj/machinery/computer/shuttle/snow_taxi,
-/turf/open/floor/plasteel,
-/area/quartermaster/miningdock)
"xow" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/door/airlock/security/glass{
@@ -43496,18 +44074,6 @@
/obj/machinery/atmospherics/pipe/simple/supply/visible,
/turf/open/floor/plating,
/area/maintenance/department/electrical)
-"xve" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/obj/effect/turf_decal/tile/bar,
-/obj/structure/disposalpipe/segment,
-/turf/open/floor/plasteel,
-/area/hallway/primary/aft)
"xvj" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -43681,10 +44247,6 @@
},
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
-"xCr" = (
-/obj/effect/landmark/blobstart,
-/turf/open/floor/plating,
-/area/medical/medbay/central)
"xCC" = (
/obj/effect/turf_decal/tile/red{
dir = 1
@@ -44311,10 +44873,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
-"xXX" = (
-/obj/structure/reagent_dispensers/watertank,
-/turf/open/floor/plating,
-/area/maintenance/central)
"xYD" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
/turf/open/floor/carpet,
@@ -44369,10 +44927,6 @@
},
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/surface/outdoors)
-"yae" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"ybp" = (
/obj/structure/chair{
dir = 8
@@ -58951,8 +59505,8 @@ ash
ash
nQr
ash
-ash
-ash
+tmO
+tmO
wje
ahC
nOK
@@ -59208,9 +59762,9 @@ rbW
aoR
apO
ash
-arG
-ash
-qbh
+abq
+tmO
+abu
auY
hEf
eGO
@@ -59465,8 +60019,8 @@ rRV
aoT
pWz
ash
-xCr
-ash
+abr
+abt
lxF
rbo
ioG
@@ -59719,11 +60273,11 @@ tUi
ash
tVS
anm
-jiV
-ash
-ash
+abH
ash
ash
+tmO
+tmO
dXR
hOA
irg
@@ -59983,7 +60537,7 @@ arI
syN
atr
rbo
-jwo
+aaF
azq
azq
azq
@@ -60222,7 +60776,7 @@ ash
cxX
sXJ
sXJ
-hnB
+aal
qhU
vCE
gIm
@@ -61282,7 +61836,7 @@ aPB
oqL
aLG
aNk
-aOl
+abM
aPA
avT
avT
@@ -62536,7 +63090,7 @@ vvH
vvH
fsA
gZX
-xlg
+abE
jUu
xGP
anm
@@ -63319,7 +63873,7 @@ mAx
ndm
rQN
aoX
-soN
+aaB
ojv
oTu
oTu
@@ -64602,7 +65156,7 @@ aoX
ali
yds
yds
-aon
+abI
aoX
rJw
tkr
@@ -64837,10 +65391,10 @@ avT
avT
xUL
rTG
-sIn
+abC
kxU
sdH
-sIn
+abD
kxU
pyw
nYZ
@@ -65118,7 +65672,7 @@ yds
yds
qWL
aoX
-gsM
+abJ
tkr
iPX
rQJ
@@ -65643,7 +66197,7 @@ ayA
sNK
xmo
rqW
-mzB
+abL
rQJ
szG
aHG
@@ -66390,7 +66944,7 @@ xUL
xUL
xUL
tmO
-fYx
+aaA
oDm
tmO
rhX
@@ -66660,7 +67214,7 @@ nrJ
iAR
rik
xWq
-aAL
+abK
gxi
wEP
wJH
@@ -67689,7 +68243,7 @@ xWq
xWq
xWq
tmO
-wje
+aaC
wje
tmO
ydp
@@ -68203,7 +68757,7 @@ xUL
xUL
xUL
tmO
-wje
+aaD
iPX
tmO
tmO
@@ -68461,7 +69015,7 @@ xUL
xUL
usE
buO
-wje
+aaE
cpC
tmO
ydp
@@ -71329,7 +71883,7 @@ avT
kfv
kfv
ilb
-ifQ
+aam
rlG
wSb
wav
@@ -72111,7 +72665,7 @@ wDk
pmK
dbB
nxv
-eZn
+abW
xBv
nQM
lZi
@@ -74684,7 +75238,7 @@ oJF
piv
nre
bWR
-xdr
+aan
uKb
fKC
rVN
@@ -75204,7 +75758,7 @@ cBD
bQj
gCG
sdN
-xXX
+acd
ubL
diH
uPJ
@@ -75454,7 +76008,7 @@ bDr
alG
fmt
cBD
-cbz
+aca
jae
bNS
pST
@@ -75719,7 +76273,7 @@ giT
bZF
xkT
bVR
-rYN
+acf
qOb
bSd
bXO
@@ -77234,7 +77788,7 @@ xZg
xZg
xZg
uBa
-eeh
+abN
grV
cTD
cTD
@@ -77244,7 +77798,7 @@ cTD
grV
lbp
knn
-eOK
+aaW
bBz
lbp
cBD
@@ -77464,7 +78018,7 @@ gky
ptY
cgH
ktw
-xZL
+aaG
lzB
avT
avT
@@ -77499,30 +78053,30 @@ vPQ
vPQ
vPQ
bwu
+aaR
+aaT
+aaX
+aaY
+abb
lhQ
-yae
-kPj
-bBB
-lhQ
-lhQ
-vPQ
-cGQ
-vPQ
-vPQ
+abV
+abf
+abb
+abb
bNn
vPQ
qQt
vPQ
bJF
bVX
-cGQ
+abj
hhz
vPQ
vPQ
vPQ
haj
pjn
-tNf
+abl
sAw
vPQ
mdG
@@ -78235,7 +78789,7 @@ cPI
kxP
vAs
ktw
-xZL
+aaI
lzB
avT
avT
@@ -78250,7 +78804,7 @@ wxT
bUP
fLK
rmN
-oLT
+aaK
ljL
uBa
uBa
@@ -78271,19 +78825,19 @@ fXU
ffm
jBl
fmw
-tWx
+abT
pBU
reS
+abc
lhQ
-lhQ
-ceA
-vun
-ceA
-ceA
-ceA
-seR
-ceA
-ceA
+abd
+abg
+abd
+abd
+abd
+abi
+abd
+abd
bmP
bQs
vun
@@ -78295,7 +78849,7 @@ ceA
vun
lhQ
lhQ
-ceA
+abm
bPc
ceA
bUL
@@ -78519,7 +79073,7 @@ piX
hJw
kop
uBa
-fuy
+abO
bwx
bwx
bwx
@@ -79033,7 +79587,7 @@ fWE
wbE
wbE
uBa
-rcH
+abP
bwx
iSo
bpM
@@ -80579,8 +81133,8 @@ tHU
bBL
guv
bpO
-bDR
-gfF
+aaL
+abR
bDR
jOl
bBL
@@ -80818,13 +81372,13 @@ iaO
dnm
hHC
dnm
-unA
+aaJ
unA
unA
unA
unA
dnm
-unA
+aaJ
dnm
unA
unA
@@ -80841,7 +81395,7 @@ bsx
bLT
bLT
bLT
-xhH
+aaV
rle
cSG
bCQ
@@ -81096,7 +81650,7 @@ vAs
vAs
vAs
bLT
-fnu
+aaN
bxR
mPM
ohK
@@ -81116,7 +81670,7 @@ bQC
gsK
wuB
pyI
-bXW
+acg
eqZ
wpN
vOV
@@ -81274,7 +81828,7 @@ dvs
mtP
naE
mtP
-mtP
+aaU
nOY
mtP
naE
@@ -81353,7 +81907,7 @@ vAs
vAs
vAs
bLT
-xou
+aaQ
jkL
fcJ
cqd
@@ -81526,7 +82080,7 @@ ydp
avT
avT
iHM
-iHM
+pgp
pgp
pgp
pgp
@@ -81781,11 +82335,11 @@ xUL
ydp
ydp
ydp
-avT
bmX
avT
pgp
-pCj
+aab
+dZV
dZV
gLk
pgp
@@ -81871,7 +82425,7 @@ bEi
bEi
lbp
bAs
-nmY
+aaZ
bCL
bDW
gpp
@@ -82040,9 +82594,9 @@ ydp
ydp
ydp
avT
-avT
pgp
-hGM
+aac
+gLk
gLk
gLk
pgp
@@ -82296,10 +82850,10 @@ ydp
ydp
ydp
ydp
-ydp
avT
pgp
-vlz
+aab
+aad
gLk
fBs
pgp
@@ -82390,11 +82944,11 @@ aGl
bEa
pHl
aaw
-gKB
+abh
qJV
fjU
fjU
-fjU
+acb
qJV
fuG
qJV
@@ -82554,7 +83108,7 @@ ydp
ydp
ydp
avT
-avT
+pgp
pgp
pgp
pgp
@@ -82813,7 +83367,7 @@ ydp
avT
ydp
pgp
-ugr
+aae
pBh
gLk
pgp
@@ -83072,7 +83626,7 @@ ydp
pgp
pgp
pgp
-eEa
+aaf
pgp
pgp
pgp
@@ -83345,8 +83899,8 @@ skZ
mSt
geO
cQv
-nGa
-fpW
+aaj
+aak
oyf
dzS
dSQ
@@ -83593,7 +84147,7 @@ mWy
pgp
uEG
dKn
-gEz
+abA
pax
sdq
iux
@@ -83677,13 +84231,13 @@ dFp
wTK
tDY
oXn
-cSg
+abY
tRe
egg
cbQ
iXG
bWf
-bVa
+acc
bVa
bWf
ftV
@@ -84178,7 +84732,7 @@ bvq
oCZ
lxV
dGP
-evr
+abS
lxV
hJE
cmC
@@ -84622,7 +85176,7 @@ iML
kFr
vuO
vaj
-rTv
+aau
mSt
dWt
fyr
@@ -85373,7 +85927,7 @@ xUL
xUL
xUL
kVO
-bQf
+aao
qgm
qgm
qgm
@@ -85390,7 +85944,7 @@ xJB
hyK
vVN
qeL
-oiX
+abn
trU
knI
oIb
@@ -85632,7 +86186,7 @@ xUL
qaO
gct
sGE
-tJL
+aaq
ixf
ixf
giv
@@ -86165,7 +86719,7 @@ iqZ
seG
tYT
qKA
-cSv
+aav
pJS
pJS
tQG
@@ -86415,7 +86969,7 @@ mKv
sAh
sAh
sAh
-urI
+aar
uEz
uEz
hrS
@@ -86658,7 +87212,7 @@ xUL
xUL
xUL
kVO
-qAq
+aap
acq
fJc
lfy
@@ -87179,7 +87733,7 @@ wAx
wuQ
vnM
wAx
-mQo
+abv
mbE
qss
sYv
@@ -87456,7 +88010,7 @@ mhq
bNF
wIA
hTO
-noB
+aai
wIA
kti
nrg
@@ -88462,7 +89016,7 @@ hAw
skK
vKa
gdg
-pkh
+aaa
loM
vKa
nsv
@@ -88483,7 +89037,7 @@ pJS
leq
qxT
wIA
-iCO
+abp
pJS
pJS
pJS
@@ -88987,12 +89541,12 @@ fTy
jvb
xZp
dVr
-gRS
+abx
msK
cKk
dNB
rmV
-dDf
+abB
gaf
pMD
shN
@@ -89245,7 +89799,7 @@ stW
iKV
hFj
oNv
-guV
+abz
cKk
meG
mcU
@@ -90278,7 +90832,7 @@ jHT
rkd
mcU
rNS
-vyf
+aax
vyf
hLQ
nsf
@@ -90295,7 +90849,7 @@ gwY
pdD
hMM
qKP
-tQd
+abF
jIt
avT
avT
@@ -90541,7 +91095,7 @@ vkk
qSi
vkk
vkk
-pUz
+aay
pqj
mcU
pqj
@@ -91034,7 +91588,7 @@ pCU
ixf
kcn
llu
-xve
+abw
gJP
eGi
mIe
@@ -91312,7 +91866,7 @@ uqy
yes
iqH
iqH
-iqH
+aaz
iqH
yes
iqH
@@ -92068,10 +92622,10 @@ gcY
xop
fbq
lFv
-dvh
+aag
gkl
eOt
-eFy
+aby
rYc
hbb
rkd
@@ -92331,7 +92885,7 @@ cKk
cKk
cKk
cKk
-mkm
+aat
lpl
xcA
srk
@@ -93875,7 +94429,7 @@ fPd
eYu
xOj
jKF
-jKb
+abo
wdR
sda
pAC
@@ -94900,7 +95454,7 @@ wTe
sPt
iBL
bnU
-fNd
+aas
bDg
fKE
bnU
@@ -96953,7 +97507,7 @@ ulr
jJb
xfH
puE
-rFQ
+aah
iiY
piR
tty
diff --git a/_maps/map_files/generic/City_of_Cogs.dmm b/_maps/map_files/generic/City_of_Cogs.dmm
index 1195ad62c5..9ef765aa28 100644
--- a/_maps/map_files/generic/City_of_Cogs.dmm
+++ b/_maps/map_files/generic/City_of_Cogs.dmm
@@ -10,20 +10,10 @@
/obj/structure/grille/ratvar,
/turf/open/indestructible/reebe_void,
/area/reebe)
-"ad" = (
-/obj/structure/lattice/clockwork,
-/obj/item/clockwork/component/belligerent_eye/blind_eye,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
"ae" = (
/obj/structure/lattice/clockwork,
/turf/open/indestructible/reebe_void,
/area/reebe)
-"af" = (
-/obj/structure/lattice/clockwork,
-/obj/item/clockwork/component/geis_capacitor/antennae,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
"ag" = (
/obj/structure/lattice/catwalk/clockwork,
/turf/open/indestructible/reebe_void,
@@ -39,14 +29,6 @@
"aj" = (
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"ak" = (
-/obj/structure/destructible/clockwork/massive/celestial_gateway,
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
-"al" = (
-/obj/machinery/sleeper/clockwork,
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
"an" = (
/obj/structure/noticeboard,
/obj/item/paper/fluff/ruins/djstation{
@@ -64,10 +46,6 @@
},
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"aq" = (
-/obj/machinery/computer/camera_advanced/ratvar,
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
"ar" = (
/obj/structure/closet/wardrobe/mixed,
/turf/open/floor/clockwork/reebe,
@@ -96,12 +74,6 @@
},
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"ax" = (
-/obj/structure/chair/brass{
- dir = 1
- },
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
"ay" = (
/obj/machinery/door/airlock/clockwork/brass{
name = "Dressing Room"
@@ -109,7 +81,7 @@
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
"az" = (
-/obj/structure/destructible/clockwork/heralds_beacon,
+/obj/structure/destructible/clockwork/eminence_spire,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
"aA" = (
@@ -118,17 +90,6 @@
},
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"aB" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/construct_chassis/cogscarab,
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
-"aC" = (
-/obj/machinery/sleeper/clockwork{
- dir = 1
- },
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
"aD" = (
/obj/machinery/door/airlock/clockwork/brass{
name = "Listening Station"
@@ -149,15 +110,6 @@
opacity = 0
},
/area/reebe/city_of_cogs)
-"aH" = (
-/obj/effect/landmark/servant_of_ratvar,
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
-"aI" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/slab,
-/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
"aJ" = (
/obj/structure/table/reinforced/brass,
/obj/item/screwdriver/brass,
@@ -182,162 +134,22 @@
/obj/item/weldingtool/experimental/brass,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"aO" = (
-/obj/structure/lattice/catwalk/clockwork,
-/obj/item/clockwork/component/belligerent_eye/lens_gem,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
-"aP" = (
-/obj/structure/lattice/catwalk/clockwork,
-/obj/item/clockwork/component/hierophant_ansible/obelisk,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
-"aQ" = (
-/obj/structure/lattice/clockwork,
-/obj/item/clockwork/alloy_shards/clockgolem_remains,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
-"aR" = (
-/obj/effect/landmark/city_of_cogs,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
"aS" = (
-/obj/effect/clockwork/servant_blocker{
- dir = 1
- },
-/obj/structure/lattice/catwalk/clockwork,
-/turf/open/indestructible/reebe_void,
-/area/reebe/city_of_cogs)
-"aT" = (
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"aU" = (
-/obj/structure/grille/ratvar,
-/obj/structure/window/reinforced/clockwork/fulltile,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"aV" = (
-/obj/machinery/door/airlock/clockwork/brass,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"aW" = (
-/obj/item/clockwork/component/replicant_alloy/replication_plate,
-/turf/open/indestructible/reebe_void/spawning/lattices,
-/area/reebe)
-"aX" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/belligerent_eye,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"aY" = (
-/obj/effect/clockwork/servant_blocker{
- dir = 1
- },
-/obj/structure/lattice/clockwork,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
-"aZ" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/belligerent_eye/blind_eye,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"ba" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/belligerent_eye/lens_gem,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bb" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/geis_capacitor,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bc" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/geis_capacitor/antennae,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bd" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/geis_capacitor/fallen_armor,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"be" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/hierophant_ansible,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bf" = (
-/obj/structure/table/reinforced/brass,
/obj/item/clockwork/component/hierophant_ansible/obelisk,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bg" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/replicant_alloy,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bh" = (
-/obj/structure/lattice/catwalk/clockwork,
-/obj/item/clockwork/integration_cog,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
-"bi" = (
-/obj/structure/lattice/catwalk/clockwork,
-/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism,
-/turf/open/indestructible/reebe_void,
-/area/reebe)
-"bj" = (
-/obj/structure/destructible/clockwork/eminence_spire,
/turf/open/floor/clockwork/reebe,
-/area/reebe/city_of_cogs)
-"bk" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/replicant_alloy/replication_plate,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bl" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bm" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/vanguard_cogwheel,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bn" = (
-/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bo" = (
-/obj/structure/window/reinforced/clockwork/fulltile,
-/obj/structure/grille/ratvar,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bp" = (
-/obj/structure/window/reinforced/clockwork/fulltile,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
+/area/reebe)
+"aT" = (
+/obj/item/clockwork/component/geis_capacitor/antennae,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
"bt" = (
/obj/structure/table/bronze,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"bu" = (
-/obj/structure/table/reinforced/brass,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bw" = (
-/obj/structure/chair/brass{
- dir = 8
- },
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"bx" = (
-/obj/structure/chair/brass{
- dir = 4
- },
-/turf/open/indestructible/clock_spawn_room,
+"bC" = (
+/obj/structure/table/bronze,
+/obj/item/storage/belt/utility/servant,
+/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
"bE" = (
/obj/structure/table/reinforced/brass,
@@ -348,53 +160,114 @@
/obj/item/healthanalyzer/advanced,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"eV" = (
-/obj/structure/chair/stool/bar/brass,
-/turf/open/indestructible/clock_spawn_room,
+"dl" = (
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"dx" = (
+/obj/structure/destructible/clockwork/powered/clockwork_obelisk,
+/obj/effect/clockwork/sigil/transmission,
+/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"nj" = (
-/obj/structure/table/bronze,
-/turf/open/indestructible/clock_spawn_room,
+"ew" = (
+/obj/structure/table/reinforced/brass,
+/obj/item/clockwork/construct_chassis/cogscarab{
+ pixel_y = 20
+ },
+/obj/item/clockwork/construct_chassis/cogscarab{
+ pixel_x = -7;
+ pixel_y = 6
+ },
+/obj/item/clockwork/construct_chassis/cogscarab{
+ pixel_x = 7;
+ pixel_y = 6
+ },
+/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"ww" = (
-/obj/structure/table/bronze,
-/obj/item/camera_film,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"xH" = (
-/obj/structure/chair/stool/brass,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"ym" = (
-/obj/structure/table/bronze,
+"hY" = (
+/obj/item/clockwork/alloy_shards/pinion_lock,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"nX" = (
+/obj/item/clockwork/alloy_shards/clockgolem_remains,
+/obj/item/clockwork/weapon/ratvarian_spear,
+/obj/item/clockwork/alloy_shards/pinion_lock,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"om" = (
+/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment,
+/obj/item/clockwork/component/geis_capacitor/fallen_armor,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"sW" = (
+/obj/structure/table/reinforced/brass,
+/obj/item/storage/belt/utility/servant,
+/obj/item/storage/belt/utility/servant,
+/obj/item/storage/belt/utility/servant,
+/obj/item/storage/belt/utility/servant,
/obj/item/storage/belt/utility/servant,
/obj/item/storage/belt/utility/servant,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
+"vx" = (
+/obj/effect/clockwork/sigil/transmission,
+/turf/open/floor/clockwork/reebe,
+/area/reebe/city_of_cogs)
+"wV" = (
+/obj/item/clockwork/alloy_shards/large,
+/turf/open/indestructible/reebe_void/spawning/lattices,
+/area/reebe)
+"xR" = (
+/obj/item/clockwork/alloy_shards/medium,
+/turf/open/indestructible/reebe_void/spawning/lattices,
+/area/reebe)
+"yY" = (
+/obj/item/clockwork/alloy_shards/small,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
"zb" = (
/turf/open/space/basic,
/area/space)
-"EE" = (
-/obj/structure/table/bronze,
-/obj/item/camera,
-/turf/open/indestructible/clock_spawn_room,
+"Fd" = (
+/obj/item/clockwork/alloy_shards/clockgolem_remains,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"Fj" = (
+/obj/machinery/sleeper/syndie/fullupgrade{
+ desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch.";
+ enter_message = "You hear the gentle hum and click of machinery, and are lulled into a sense of peace.";
+ icon_state = "sleeper_clockwork";
+ name = "soothing sleeper"
+ },
+/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
-"NH" = (
-/obj/structure/table/bronze,
-/obj/item/taperecorder,
-/turf/open/indestructible/clock_spawn_room,
-/area/reebe/city_of_cogs)
-"VP" = (
+"Ia" = (
+/obj/item/clockwork/alloy_shards/small,
+/turf/open/indestructible/reebe_void/spawning/lattices,
+/area/reebe)
+"OB" = (
+/obj/item/clockwork/component/geis_capacitor/fallen_armor,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"Rw" = (
/obj/structure/table/reinforced/brass,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
-/obj/item/clockwork/slab,
+/obj/item/clockwork/replica_fabricator,
+/obj/item/clockwork/replica_fabricator,
+/turf/open/floor/clockwork/reebe,
+/area/reebe/city_of_cogs)
+"Sr" = (
+/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"TH" = (
+/obj/structure/lattice/catwalk/clockwork,
+/turf/open/indestructible/reebe_void/spawning/lattices,
+/area/reebe/city_of_cogs)
+"Wv" = (
+/obj/item/clockwork/component/belligerent_eye/blind_eye,
+/turf/open/floor/clockwork/reebe,
+/area/reebe)
+"WA" = (
+/obj/effect/clockwork/sigil/vitality,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
"WT" = (
@@ -24671,7 +24544,7 @@ aa
aa
aa
aa
-ab
+aa
aa
aa
aa
@@ -24908,58 +24781,58 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -25155,76 +25028,76 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -25411,78 +25284,78 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -25668,79 +25541,79 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -25925,80 +25798,80 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ac
-ae
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-aW
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -26182,81 +26055,81 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ae
-af
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ab
-aP
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -26439,82 +26312,82 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ac
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -26696,83 +26569,83 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -26953,84 +26826,84 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ae
-ae
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -27210,85 +27083,85 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ag
-ag
-ag
-ae
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aG
-aY
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ah
-ah
-bo
-bo
-bo
-bo
-bo
-bo
-bo
-ah
-ah
-ae
-ae
-ae
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -27467,85 +27340,85 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ag
-ag
-ag
-ae
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aG
-aS
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-nj
-nj
-ah
-ah
-ah
-ae
-ae
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -27724,6 +27597,31 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -27733,76 +27631,51 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ah
-ah
-ai
-ah
-ah
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aj
-aS
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-aU
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-EE
-bo
-aX
-bo
-ag
+ae
+ae
ae
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aF
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -27974,6 +27847,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -27982,84 +27887,52 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-ar
-aj
-bt
-ah
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-bw
-bw
-bw
-bw
-bw
-bw
-bw
-bw
-bw
-bw
-bw
-bw
-aU
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-NH
-bo
-aZ
-bo
+ae
+ag
+ag
ag
ae
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -28231,6 +28104,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -28239,84 +28144,52 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-as
-aj
-aj
-ay
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bo
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-nj
-bo
-ba
-bo
+ae
+ag
+ag
ag
ae
-bi
-ab
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
ab
ab
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -28488,17 +28361,38 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -28508,72 +28402,51 @@ ab
ab
ab
ah
-VP
-aj
-ym
ah
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aV
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-bb
-bo
-ag
-ae
+ai
+ah
+ah
+aG
+aG
+aG
+aG
+aG
+aG
+aG
+aF
ab
-ae
-ac
ab
+ab
+ab
+ab
+ab
+aa
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -28745,17 +28618,38 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -28765,9 +28659,9 @@ ab
ab
ab
ah
-ah
-ay
-ah
+ar
+aj
+bt
ah
aj
aj
@@ -28775,62 +28669,41 @@ aj
aj
aj
aj
+TH
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bo
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-ww
-bo
-bc
-bo
-ag
-ae
+aa
+dl
+ab
+aa
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -29002,6 +28875,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -29010,84 +28915,52 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-an
-au
-aj
-au
ah
+as
+aj
+aj
+ay
aj
aj
aj
aj
aj
aj
+TH
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-bd
-bo
-ag
-ae
+aa
+dl
+aa
+aa
+ab
+dl
+ab
+dl
+dl
+dl
+ab
+ab
+dl
ab
ab
ab
ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -29259,16 +29132,38 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -29278,10 +29173,9 @@ ab
ab
ab
ah
-ah
-av
+aL
aj
-av
+bC
ah
aj
aj
@@ -29289,62 +29183,41 @@ aj
aj
aj
aj
+TH
+ab
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-nj
-bo
-be
-bo
-ag
-ae
+aa
+dl
+aa
+Wv
+ab
+Fd
+yY
+yY
+dl
+dl
+dl
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -29516,6 +29389,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -29524,84 +29429,52 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ai
-ao
-aj
-aj
-aj
-aD
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bp
-bp
-ah
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-EE
-nj
ah
ah
+ay
ah
-ae
-ae
+ah
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aa
+dl
+ab
+aa
+Fd
+ab
+hY
+Sr
+dl
+ab
+ab
+dl
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -29773,6 +29646,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -29781,23 +29686,11 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
+an
+au
+aj
+au
ah
-ah
-aw
-aj
-aw
-ai
-aH
aj
aj
aj
@@ -29806,59 +29699,39 @@ aj
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bp
-bg
-ah
-ah
-bo
-bo
-bo
-bo
-bo
-bo
-bo
-ah
-ah
-ae
-ae
-ae
+aa
+dl
+aa
+ab
+ab
+OB
+ab
+yY
+dl
ab
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -30030,6 +29903,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -30037,85 +29942,53 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ae
-ag
-ag
-an
-au
-aj
-au
-ai
-aI
-aK
-aH
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bp
-bp
-ah
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-ww
-nj
ah
ah
+av
+aj
+av
ah
-ae
-ae
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aa
+dl
+dl
+aa
+aa
+om
+Fd
ab
ab
ab
ab
+dl
+dl
+dl
+dl
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -30287,92 +30160,92 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-ah
-ah
-ai
-ah
-ah
-ah
-ai
-ap
-ai
-ah
-aJ
-aH
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-nj
-bo
-bf
-bo
-ag
ae
+ai
+ao
+aj
+aj
+aj
+aD
+aj
+aj
+aj
+aj
+aj
+aj
+TH
+aa
+aa
+aa
+aT
+Wv
ab
ab
ab
ab
+ab
+ab
+ab
+dl
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -30544,92 +30417,92 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ac
-ah
-aj
-aj
-aj
-aj
-aj
-ai
-aj
-aj
-aj
-ai
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-bg
-bo
-ag
ae
+ah
+ah
+aw
+aj
+aw
+ai
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aa
+ab
+ab
+ab
+Ia
+ab
+yY
+ab
+ab
+dl
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -30801,92 +30674,92 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
ae
-ah
-aj
-aj
-aj
-aj
-aj
-ai
-aj
-az
-aj
-ai
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-ai
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-EE
-bo
-bk
-bo
+ae
ag
-ae
+ag
+an
+au
+aj
+au
+ai
+aL
+aK
+aj
+aj
+aj
+aj
+aj
+ab
+ab
+aa
+Fd
+ab
+Ia
+ab
+ab
+ab
+Wv
ab
ab
ab
ab
+dl
+ab
+dl
+ab
+dl
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -31058,30 +30931,52 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ag
+ah
+ah
+ah
+ai
+ah
+ah
+ah
ai
-aj
-aj
-ak
-aj
-aj
-ap
-aj
-aj
-aj
ap
+ai
+ah
+aJ
aj
aj
aj
@@ -31090,60 +30985,38 @@ aj
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aV
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-bl
-bo
-ag
-ae
+aa
+ab
+ab
+ab
+Ia
ab
ab
ab
ab
+ab
+ab
+ab
+dl
+ab
+dl
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -31317,17 +31190,38 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
+ac
ah
aj
aj
@@ -31336,7 +31230,7 @@ aj
aj
ai
aj
-bj
+aj
aj
ai
aj
@@ -31345,62 +31239,41 @@ aj
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-ai
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-nj
-bo
-bm
-bo
-ag
-ae
+TH
+aa
+aa
+ab
+ab
+Sr
+ab
+ab
+Ia
+ab
+ab
+dl
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -31574,15 +31447,36 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ae
ah
@@ -31598,66 +31492,45 @@ aj
ai
aj
aj
-aH
-aH
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
aj
aj
aj
aj
aj
aj
+aa
aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-bn
-bo
-ag
-ae
+ab
+aa
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -31831,90 +31704,90 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-ah
-ah
-ai
-ah
-ah
-ah
-ai
-ap
-ai
-ah
-aj
-aH
-aL
-aN
-aH
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-nj
-bo
-aX
-bo
-ag
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ae
+ag
+ai
+aj
+aj
+dx
+aj
+aj
+ap
+aj
+aj
+aj
+ap
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+ab
+aa
+ab
+aa
+xR
+nX
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -32088,33 +31961,49 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ae
-ae
-ag
ah
-aq
-ax
+aj
+aj
+aj
aj
aj
ai
aj
-aH
-aM
-aL
-aH
+aj
+aj
+ai
aj
aj
aj
@@ -32124,54 +32013,38 @@ aj
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bp
-bp
-ah
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-NH
-EE
-ah
-ah
-ah
-ae
-ae
+aa
+ab
+aa
+ab
+ab
+ab
+wV
ab
ab
ab
ab
+ab
+ab
+dl
+dl
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -32345,32 +32218,49 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ae
-ai
-aq
-ax
+ah
+aj
+aj
+aj
aj
aj
ai
aj
aj
-aH
-aH
+aj
+ai
aj
aj
aj
@@ -32378,50 +32268,11 @@ aj
aj
aj
aj
+ab
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bp
-bk
-ah
-ah
-bo
-bo
-bo
-bo
-bo
-bo
-bo
-ah
-ah
-ae
+ab
+aa
+xR
ab
ab
ab
@@ -32429,6 +32280,28 @@ ab
ab
ab
ab
+ab
+ab
+dl
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -32602,90 +32475,90 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
+ah
+ah
+ah
ai
-aq
-ax
-aj
-aj
-aE
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bp
-bp
-ah
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-nj
-nj
ah
ah
ah
-ae
-ae
+ai
+ap
+ai
+ah
+aj
+aj
+aL
+aN
+aj
+aj
+aj
+ab
+aa
+dl
+aa
+ab
+OB
ab
ab
ab
ab
+ab
+dl
+ab
+dl
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -32859,90 +32732,90 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
-ab
-ad
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ai
-aq
-ax
-aj
-aB
-ah
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-EE
-bo
-aZ
-bo
-ag
ae
+ae
+ag
+ah
+ew
+aj
+aj
+aj
+ai
+aj
+aj
+aM
+aL
+aj
+aj
+aj
+aa
+aa
+aa
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+dl
+ab
+ab
+dl
+ab
+dl
+ab
+ab
+ab
+dl
+dl
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -33116,90 +32989,90 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-aq
-ax
-aj
-aB
-ah
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aU
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-ba
-bo
-ag
ae
+ai
+aj
+aj
+aj
+aj
+ai
+aj
+aj
+aj
+aj
+aj
+aj
+TH
+aa
+dl
+hY
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+dl
+ab
+ab
+ab
+ab
+dl
+ab
+dl
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -33373,90 +33246,90 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-ah
-ah
-ah
-aA
-ah
-ah
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bo
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-NH
-bo
-bb
-bo
-ag
ae
+ai
+az
+vx
+aj
+aj
+aE
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+aa
+aa
+ab
+ab
+ab
+aT
+Wv
+ab
+ab
+ab
+dl
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -33630,6 +33503,36 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -33637,20 +33540,11 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ah
-al
+ai
aj
aj
aj
-aC
+sW
ah
aj
aj
@@ -33661,59 +33555,38 @@ aj
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
+aa
aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aV
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-nj
-bo
-bc
-bo
-ag
-ae
ab
ab
ab
ab
+ab
+dl
+ab
+ab
+dl
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -33887,6 +33760,68 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ah
+aj
+aj
+aj
+Rw
+ah
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+ab
+ab
+aa
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+dl
ab
ab
ab
@@ -33897,80 +33832,18 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ai
-bE
-aj
-aj
-aj
-aj
-aA
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aS
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-bo
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-ww
-bo
-bd
-bo
-ag
-ae
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -34144,15 +34017,36 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -34160,11 +34054,11 @@ ab
ab
ab
ah
-al
-aj
-aj
-aj
-aC
+ah
+ah
+ah
+aA
+ah
ah
aj
aj
@@ -34175,59 +34069,38 @@ aj
aj
aj
aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aj
-aG
-aS
-bx
-bx
-bx
-bx
-bx
-bx
-bx
-bx
-bx
-bx
-bx
-bx
-aU
-aT
-aT
-aR
-aT
-aR
-aT
-aR
-eV
-EE
-bo
-be
-bo
-ag
-ae
+aa
+hY
+ab
+ab
+dl
+ab
+dl
ab
ab
ab
ab
+ab
+dl
+ab
+ab
+dl
+dl
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -34401,15 +34274,36 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -34417,74 +34311,53 @@ ab
ab
ab
ah
+Fj
+aj
+aj
+aj
+WA
ah
-ah
-ai
-ah
-ah
-ah
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aG
-aS
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-bu
-aU
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-xH
-nj
-bo
-bf
-bo
-ag
-ae
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+ab
+ab
+aa
+aa
ab
ab
ab
ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -34658,6 +34531,62 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+ab
+ab
+ai
+bE
+aj
+aj
+aj
+aj
+aA
+aj
+aj
+aj
+aj
+aj
+aj
+TH
+aj
+aj
+aj
+ab
+aa
+Fd
ab
ab
ab
@@ -34669,79 +34598,23 @@ ab
ab
ab
ab
+dl
ab
ab
+dl
ab
-ab
-ab
-ab
-ae
-ae
-ag
-ae
-ae
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-aF
-ab
-aS
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-ah
-aT
-aT
-aT
-aT
-aT
-aT
-aT
-nj
-nj
-ah
-ah
-ah
-ae
-ae
-ab
-ab
-ab
-ab
+dl
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -34915,11 +34788,61 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
ab
ab
+ab
+ah
+Fj
+aj
+aj
+aj
+WA
+ah
+aj
+aj
+aj
+aj
+aj
+aj
+aj
+ab
+ab
+ab
+dl
+ab
aa
ab
ab
@@ -34937,68 +34860,18 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aY
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ah
-ah
-bo
-bo
-bo
-bo
-bo
-bo
-bo
-ah
-ah
-ae
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -35178,6 +35051,50 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+ab
+ab
+ah
+ah
+ah
+ai
+ah
+ah
+ah
+aG
+aG
+aG
+aG
+aG
+aG
+aG
ab
ab
ab
@@ -35200,61 +35117,17 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ae
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -35435,6 +35308,30 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -35443,74 +35340,50 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+ae
+ae
+ag
+ae
+ae
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
aF
ab
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
+aF
ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -35692,6 +35565,30 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -35735,38 +35632,14 @@ ab
ab
ab
ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -35949,6 +35822,30 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -35969,37 +35866,6 @@ ab
ab
ab
ab
-aO
-ac
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aQ
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
ab
ab
ab
@@ -36041,6 +35907,13 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
WT
zb
zb
@@ -36206,10 +36079,30 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
ab
ab
ab
@@ -36253,32 +36146,12 @@ ab
ab
ab
aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -36463,78 +36336,78 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ac
-bh
-ae
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -36720,77 +36593,77 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -36977,76 +36850,76 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
@@ -37244,58 +37117,58 @@ aa
aa
aa
aa
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
aa
-aF
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
-ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
aa
aa
aa
diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm
index 0404cede34..3ac1d18ac4 100644
--- a/_maps/shuttles/whiteship_box.dmm
+++ b/_maps/shuttles/whiteship_box.dmm
@@ -2690,7 +2690,7 @@
/obj/structure/rack,
/obj/item/storage/box/zipties,
/obj/item/assembly/flash/handheld,
-/obj/item/melee/classic_baton/telescopic,
+/obj/item/melee/classic_baton,
/obj/machinery/light/small/built{
dir = 8
},
diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 2af331b777..035563627f 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -142,6 +142,11 @@
#define CUSTOM_SKINTONE 24 //adds a "_g" suffix to bodypart overlays icon states if a custom skintone is used.
#define HORNCOLOR 25
#define WINGCOLOR 26
+#define CAN_SCAR 27 // If this species can be scarred (fleshy)
+
+/// Used for determining which wounds are applicable to this species.
+#define HAS_FLESH 28 /// if we have flesh (can suffer slash/piercing/burn wounds, requires they don't have NOBLOOD)
+#define HAS_BONE 29 /// if we have bones (can suffer bone wounds)
//organ slots
#define ORGAN_SLOT_BRAIN "brain"
diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm
index 3a31eebb19..0734feaa42 100644
--- a/code/__DEFINES/_flags/_flags.dm
+++ b/code/__DEFINES/_flags/_flags.dm
@@ -138,14 +138,6 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_PICKUP | MOBILITY_USE | MOBILITY_UI | MOBILITY_STORAGE | MOBILITY_PULL | MOBILITY_RESIST)
#define MOBILITY_FLAGS_ANY_INTERACTION (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_UI | MOBILITY_STORAGE)
-// melee_attack_chain() attackchain_flags
-/// The attack is from a parry counterattack.
-#define ATTACKCHAIN_PARRY_COUNTERATTACK (1<<0)
-
-// UnarmedAttack() flags
-/// Attack is from a parry counterattack
-#define UNARMED_ATTACK_PARRY (1<<0)
-
/// If the thing can reflect light (lasers/energy)
#define RICOCHET_SHINY (1<<0)
/// If the thing can reflect matter (bullets/bomb shrapnel)
diff --git a/code/__DEFINES/_flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm
index b3b65bcf59..26e764c45b 100644
--- a/code/__DEFINES/_flags/item_flags.dm
+++ b/code/__DEFINES/_flags/item_flags.dm
@@ -52,4 +52,4 @@
#define ORGAN_VITAL (1<<4) //Currently only the brain
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
-#define ORGAN_EDIBLE (1<<5) //is a snack? :D
\ No newline at end of file
+#define ORGAN_EDIBLE (1<<7) //is a snack? :D
diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm
index ebb9b4bda0..a936a5cef5 100644
--- a/code/__DEFINES/_flags/obj_flags.dm
+++ b/code/__DEFINES/_flags/obj_flags.dm
@@ -12,4 +12,9 @@
#define SHOVABLE_ONTO (1<<9) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
#define BLOCK_Z_FALL (1<<10)
+/// Integrity defines for clothing (not flags but close enough)
+#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
+#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart and can be equipped
+#define CLOTHING_SHREDDED 2 // The clothing is useless and cannot be equipped unless repaired first
+
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
diff --git a/code/__DEFINES/_flags/return_values.dm b/code/__DEFINES/_flags/return_values.dm
new file mode 100644
index 0000000000..28606265b3
--- /dev/null
+++ b/code/__DEFINES/_flags/return_values.dm
@@ -0,0 +1,22 @@
+/////////// ATTACKCHAIN_FLAGS ////////////
+// melee_attack_chain(), attackby(), pre_attack(), afterattack(), and tool_act(), attack() and **anything that is called by ClickOn()** return values.
+// These are all passed down through the attack chain and are binary OR'd into each other!
+/// Stop the attack chain if still in melee_attack_chain()
+#define STOP_ATTACK_PROC_CHAIN (1<<0)
+/// This attack should discard last_action instead of flushing (storing) it). You should probably know what you're doing if you use this considering this is how clickdelay is enforced.
+#define DISCARD_LAST_ACTION (1<<1)
+/// There are a number of "safety nets" intended to default-handle clickdelay. Return this flag to bypass ALL of them. Be sure
+/// you know EXACTLY what you are doing!
+#define NO_AUTO_CLICKDELAY_HANDLING (1<<2)
+/// Only used with UnarmedAttack(). Interrupts unarmed attack from progressing.
+#define INTERRUPT_UNARMED_ATTACK (1<<3)
+/// Attack should not set next action even if the atom wants it to be an action
+#define ATTACK_IGNORE_ACTION (1<<4)
+/// Attack should not at all check last_action/attack_hand_speed even if the atom wants to
+#define ATTACK_IGNORE_CLICKDELAY (1<<5)
+/// This attack is from a parry counterattack
+#define ATTACK_IS_PARRY_COUNTERATTACK (1<<6)
+
+// obj/item/dropped()
+/// dropped() relocated this item, return FALSE for doUnEquip.
+#define ITEM_RELOCATED_BY_DROPPED "relocated_by_dropped"
diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 6a0cd3b8ee..97f07acc05 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -74,8 +74,13 @@
#define ADMIN_PUNISHMENT_MAZING "Puzzle"
#define ADMIN_PUNISHMENT_PIE "Cream Pie"
#define ADMIN_PUNISHMENT_CUSTOM_PIE "Custom Cream Pie"
+#define ADMIN_PUNISHMENT_SHOES "Knot Shoes"
+#define ADMIN_PUNISHMENT_CRACK ":B:oneless"
+#define ADMIN_PUNISHMENT_BLEED ":B:loodless"
+#define ADMIN_PUNISHMENT_SCARIFY "Scarify"
#define ADMIN_PUNISHMENT_PICKLE "Pickle-ify"
#define ADMIN_PUNISHMENT_FRY "Fry"
+#define ADMIN_PUNISHMENT_PERFORATE ":B:erforate"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
diff --git a/code/__DEFINES/admin/keybindings.dm b/code/__DEFINES/admin/keybindings.dm
index 3efc26c7d5..fcfe7c5e58 100644
--- a/code/__DEFINES/admin/keybindings.dm
+++ b/code/__DEFINES/admin/keybindings.dm
@@ -1,6 +1,6 @@
// 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
+#define MAX_KEYPRESS_COMMANDLENGTH 32
/// Maximum keys that can be bound to one button
#define MAX_COMMANDS_PER_KEY 5
/// Maximum keys per keybind
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 07f24fd8a3..585e8da7d7 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -98,6 +98,7 @@
#define NO_APHRO (1<<9)
#define NO_ASS_SLAP (1<<10)
#define BIMBOFICATION (1<<11)
+#define NO_AUTO_WAG (1<<12)
#define TOGGLES_CITADEL 0
diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm
index 2f2f94413b..5f4317060d 100644
--- a/code/__DEFINES/clockcult.dm
+++ b/code/__DEFINES/clockcult.dm
@@ -8,6 +8,7 @@
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
+GLOBAL_LIST_EMPTY(active_daemons) //A list of all active tinkerer's daemons
GLOBAL_VAR_INIT(neovgre_exists, 0) //Does neovgre exist?
GLOBAL_LIST_EMPTY(all_clockwork_objects) //All clockwork items, structures, and effects in existence
@@ -19,21 +20,23 @@ GLOBAL_VAR_INIT(ark_of_the_clockwork_justiciar, FALSE) //The Ark on the Reebe z-
GLOBAL_VAR_INIT(clockwork_gateway_activated, FALSE) //if a gateway to the celestial derelict has ever been successfully activated
GLOBAL_VAR_INIT(script_scripture_unlocked, FALSE) //If script scripture is available, through converting at least one crewmember
-GLOBAL_VAR_INIT(application_scripture_unlocked, FALSE) //If script scripture is available
+GLOBAL_VAR_INIT(application_scripture_unlocked, FALSE) //If application scripture is available
+GLOBAL_VAR_INIT(judgement_scripture_unlocked, FALSE) //If judgement scripture is available
GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not used to track existing scripture
+GLOBAL_LIST_EMPTY(all_clockwork_rites) //a list containing all clockwork rites. Filled the first time any cultist interacts with a sigil of rites.
//Scripture tiers and requirements; peripherals should never be used
#define SCRIPTURE_PERIPHERAL "Peripheral"
#define SCRIPTURE_DRIVER "Driver"
#define SCRIPTURE_SCRIPT "Script"
#define SCRIPTURE_APPLICATION "Application"
+#define SCRIPTURE_JUDGEMENT "Judgement"
//Various costs related to power.
#define MAX_CLOCKWORK_POWER 80000 //The max power in W that the cult can stockpile
#define SCRIPT_UNLOCK_THRESHOLD 35000 //Scripts will unlock if the total power reaches this amount
-#define APPLICATION_UNLOCK_THRESHOLD 50000 //Applications will unlock if the total powre reaches this amount
-
-#define ABSCOND_ABDUCTION_COST 95
+#define APPLICATION_UNLOCK_THRESHOLD 50000 //Applications will unlock if the total power reaches this amount
+#define JUDGEMENT_UNLOCK_THRESHOLD 80000 //might as well have this unlock at a power amount like the other scriptures, Judgement unlocks at this amount.
//clockcult power defines
#define MIN_CLOCKCULT_POWER 25 //the minimum amount of power clockcult machines will handle gracefully
@@ -59,11 +62,11 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
//Ark defines
#define GATEWAY_SUMMON_RATE 1 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 1 per tick
-#define GATEWAY_REEBE_FOUND 240 //when progress is at or above this, the gateway finds reebe and begins drawing power
+#define GATEWAY_REEBE_FOUND 120 //when progress is at or above this, the gateway finds reebe and begins drawing power
-#define GATEWAY_RATVAR_COMING 480 //when progress is at or above this, ratvar has entered and is coming through the gateway
+#define GATEWAY_RATVAR_COMING 240 //when progress is at or above this, ratvar has entered and is coming through the gateway
-#define GATEWAY_RATVAR_ARRIVAL 600 //when progress is at or above this, game over ratvar's here everybody go home
+#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
//Objective text define
#define CLOCKCULT_OBJECTIVE "Construct the Ark of the Clockwork Justicar and free Ratvar."
@@ -81,7 +84,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define CLOCKWORK_ARMOR_COOLDOWN 1800 //The cooldown period between summoning suits of clockwork armor
-#define RATVARIAN_SPEAR_COOLDOWN 300 //The cooldown period between summoning another Ratvarian spear
+#define RATVARIAN_WEAPON_COOLDOWN 300 //The cooldown period between summoning another Ratvarian spear
#define MARAUDER_SCRIPTURE_SCALING_THRESHOLD 600 //The amount of deciseconds that must pass before marauder scripture will not gain a recital penalty
@@ -89,4 +92,8 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define MARAUDER_SCRIPTURE_SCALING_MAX 300 //The maximum extra time applied to the marauder scripture
-#define ARK_SCREAM_COOLDOWN 600 //This much time has to pass between instances of the Ark taking damage before it will "scream" again
+#define GUARDIAN_EMERGE_THRESHOLD 65 //guardian cannot emerge unless host is at this% or less health
+
+#define ARK_SCREAM_COOLDOWN 300 //This much time has to pass between instances of the Ark taking damage before it will "scream" again
+
+#define PRISM_DELAY_DURATION 1200 //how long prolonging prisms delay the shuttle for; defaults to 2 minutes
\ No newline at end of file
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index dff52f4748..14d62f7978 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -108,7 +108,6 @@
#define CLICK_CD_RANGE 4
#define CLICK_CD_RAPID 2
#define CLICK_CD_CLICK_ABILITY 6
-#define CLICK_CD_BREAKOUT 100
#define CLICK_CD_HANDCUFFED 10
#define CLICK_CD_RESIST 20
#define CLICK_CD_GRABBING 10
@@ -155,9 +154,10 @@
#define SHOVE_KNOCKDOWN_HUMAN 30
#define SHOVE_KNOCKDOWN_TABLE 30
#define SHOVE_KNOCKDOWN_COLLATERAL 10
-//for the shove slowdown, see __DEFINES/movespeed_modification.dm
-#define SHOVE_SLOWDOWN_LENGTH 30
-#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier
+/// how long they're staggered for
+#define SHOVE_STAGGER_DURATION 35
+/// how long they're off balance for
+#define SHOVE_OFFBALANCE_DURATION 30
//Shove disarming item list
GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/obj/item/gun)))
@@ -209,9 +209,9 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define GUN_AIMING_TIME (2 SECONDS)
//Object/Item sharpness
-#define IS_BLUNT 0
-#define IS_SHARP 1
-#define IS_SHARP_ACCURATE 2
+#define SHARP_NONE 0
+#define SHARP_EDGED 1
+#define SHARP_POINTY 2
//His Grace.
#define HIS_GRACE_SATIATED 0 //He hungers not. If bloodthirst is set to this, His Grace is asleep.
@@ -281,7 +281,7 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/// changeNext_move penalty multiplier of the above.
#define STAM_CRIT_ITEM_ATTACK_DELAY 1.75
/// Damage penalty when fighting prone.
-#define LYING_DAMAGE_PENALTY 0.5
+#define LYING_DAMAGE_PENALTY 0.7
/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise.
#define STAM_CRIT_GUN_DELAY 2.75
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index cfd1906e82..5cc7f8767b 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -209,6 +209,8 @@
#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands" //from base of mob/swap_hand(): (obj/item)
#define COMPONENT_BLOCK_SWAP 1
+#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge"
+
// /client signals
#define COMSIG_MOB_CLIENT_LOGIN "mob_client_login" //sent when a mob/login() finishes: (client)
#define COMSIG_MOB_CLIENT_LOGOUT "mob_client_logout" //sent when a mob/logout() starts: (client)
@@ -252,7 +254,14 @@
#define COMPONENT_INTERRUPT_LIFE_BIOLOGICAL 1 // interrupt biological processes
#define COMPONENT_INTERRUPT_LIFE_PHYSICAL 2 // interrupt physical handling
-// /mob/living/carbon signals
+// /mob/living/carbon physiology signals
+#define COMSIG_CARBON_GAIN_WOUND "carbon_gain_wound" //from /datum/wound/proc/apply_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
+#define COMSIG_CARBON_LOSE_WOUND "carbon_lose_wound" //from /datum/wound/proc/remove_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
+///from base of /obj/item/bodypart/proc/attach_limb(): (new_limb, special) allows you to fail limb attachment
+#define COMSIG_CARBON_ATTACH_LIMB "carbon_attach_limb"
+ #define COMPONENT_NO_ATTACH (1<<0)
+#define COMSIG_CARBON_REMOVE_LIMB "carbon_remove_limb" //from base of /obj/item/bodypart/proc/drop_limb(special, dismembered)
+
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
#define COMSIG_CARBON_IDENTITY_TRANSFERRED_TO "carbon_id_transferred_to" //from datum/dna/transfer_identity(): (datum/dna, transfer_SE)
#define COMSIG_CARBON_TACKLED "carbon_tackled" //sends from tackle.dm on tackle completion
@@ -350,10 +359,10 @@
#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
// /obj/item/projectile signals (sent to the firer)
-#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
-#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
+#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" ///from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle, hit_limb)
+#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle, hit_limb)
#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" // from base of /obj/item/projectile/proc/fire(): (obj/item/projectile, atom/original_target)
-#define COMSIG_PROJECTILE_FIRE "projectile_fire" ///from the base of /obj/projectile/proc/fire(): ()
+#define COMSIG_PROJECTILE_FIRE "projectile_fire" ///from the base of /obj/item/projectile/proc/fire(): ()
#define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out" // sent to targets during the process_hit proc of projectiles
#define COMSIG_EMBED_TRY_FORCE "item_try_embed" // sent when trying to force an embed (mainly for projectiles, only used in the embed element)
#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" ///sent to targets during the process_hit proc of projectiles
@@ -363,6 +372,7 @@
// /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
+#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
#define COMSIG_HUMAN_PREFS_COPIED_TO "human_prefs_copied_to" //from datum/preferences/copy_to(): (datum/preferences, icon_updates, roundstart_checks)
#define COMSIG_HUMAN_HARDSET_DNA "human_hardset_dna" //from mob/living/carbon/human/hardset_dna(): (ui, list/mutation_index, newreal_name, newblood_type, datum/species, newfeatures)
@@ -445,6 +455,9 @@
#define COMPONENT_TWOHANDED_BLOCK_WIELD 1
#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield" //from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
+// /datum/component/squeak signals
+#define COMSIG_CROSS_SQUEAKED "cross_squeaked" // sent when a squeak component squeaks from crossing something, to delay anything else crossing that might squeak to prevent ear hurt.
+
// /datum/action signals
#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
#define COMPONENT_ACTION_BLOCK_TRIGGER 1
diff --git a/code/__DEFINES/exosuit_fabs.dm b/code/__DEFINES/exosuit_fabs.dm
new file mode 100644
index 0000000000..d951a7bc28
--- /dev/null
+++ b/code/__DEFINES/exosuit_fabs.dm
@@ -0,0 +1,35 @@
+/// Module is compatible with Security Cyborg models
+#define BORG_MODULE_SECURITY (1<<0)
+/// Module is compatible with Miner Cyborg models
+#define BORG_MODULE_MINER (1<<1)
+/// Module is compatible with Janitor Cyborg models
+#define BORG_MODULE_JANITOR (1<<2)
+/// Module is compatible with Medical Cyborg models
+#define BORG_MODULE_MEDICAL (1<<3)
+/// Module is compatible with Engineering Cyborg models
+#define BORG_MODULE_ENGINEERING (1<<4)
+
+/// Module is compatible with Ripley Exosuit models
+#define EXOSUIT_MODULE_RIPLEY (1<<0)
+/// Module is compatible with Odyseeus Exosuit models
+#define EXOSUIT_MODULE_ODYSSEUS (1<<1)
+/// Module is compatible with Clarke Exosuit models. Rebranded to firefighter because tg nerfed it to this.
+#define EXOSUIT_MODULE_FIREFIGHTER (1<<2)
+// #define EXOSUIT_MODULE_CLARKE (1<<2)
+/// Module is compatible with Gygax Exosuit models
+#define EXOSUIT_MODULE_GYGAX (1<<3)
+/// Module is compatible with Durand Exosuit models
+#define EXOSUIT_MODULE_DURAND (1<<4)
+/// Module is compatible with H.O.N.K Exosuit models
+#define EXOSUIT_MODULE_HONK (1<<5)
+/// Module is compatible with Phazon Exosuit models
+#define EXOSUIT_MODULE_PHAZON (1<<6)
+/// Module is compatable with N models
+#define EXOSUIT_MODULE_GYGAX_MED (1<<7)
+
+/// Module is compatible with "Working" Exosuit models - Ripley and Clarke
+#define EXOSUIT_MODULE_WORKING EXOSUIT_MODULE_RIPLEY | EXOSUIT_MODULE_FIREFIGHTER // | EXOSUIT_MODULE_CLARKE
+/// Module is compatible with "Combat" Exosuit models - Gygax, H.O.N.K, Durand and Phazon
+#define EXOSUIT_MODULE_COMBAT EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON
+/// Module is compatible with "Medical" Exosuit modelsm - Odysseus
+#define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS | EXOSUIT_MODULE_GYGAX_MED
diff --git a/code/__DEFINES/integrated_electronics.dm b/code/__DEFINES/integrated_electronics.dm
index 727314abc6..71bdfb37ea 100644
--- a/code/__DEFINES/integrated_electronics.dm
+++ b/code/__DEFINES/integrated_electronics.dm
@@ -7,10 +7,10 @@
#define PULSE_CHANNEL "pulse channel"
// Methods of obtaining a circuit.
-#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and able to be printed in the IC printer.
+#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and is able to be printed in the IC printer.
#define IC_SPAWN_RESEARCH 2 // If the circuit design will be available in the IC printer after upgrading it.
-// Categories that help differentiate circuits that can do different tipes of actions
+// Categories that help differentiate circuits that can do different types of actions
#define IC_ACTION_MOVEMENT (1<<0) // If the circuit can move the assembly
#define IC_ACTION_COMBAT (1<<1) // If the circuit can cause harm
#define IC_ACTION_LONG_RANGE (1<<2) // If the circuit communicate with something outside of the assembly
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index a9d9bda00c..d66521d945 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -65,9 +65,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isslimeperson(A) (is_species(A, /datum/species/jelly/slime))
#define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent))
#define iszombie(A) (is_species(A, /datum/species/zombie))
-#define ismoth(A) (is_species(A, /datum/species/insect))
#define ishumanbasic(A) (is_species(A, /datum/species/human))
-#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
+#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid))
#define isdwarf(A) (is_species(A, /datum/species/dwarf))
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
#define isangel(A) (is_species(A, /datum/species/angel))
@@ -75,13 +74,12 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define ismush(A) (is_species(A, /datum/species/mush))
#define isshadow(A) (is_species(A, /datum/species/shadow))
#define isskeleton(A) (is_species(A, /datum/species/skeleton))
+#define isethereal(A) (is_species(A, /datum/species/ethereal))
// Citadel specific species
#define isipcperson(A) (is_species(A, /datum/species/ipc))
#define issynthliz(A) (is_species(A, /datum/species/synthliz))
#define ismammal(A) (is_species(A, /datum/species/mammal))
-#define isavian(A) (is_species(A, /datum/species/avian))
-#define isaquatic(A) (is_species(A, /datum/species/aquatic))
#define isinsect(A) (is_species(A, /datum/species/insect))
#define isxenoperson(A) (is_species(A, /datum/species/xeno))
#define isstartjelly(A) (is_species(A, /datum/species/jelly/roundstartslime))
@@ -202,14 +200,6 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isclothing(A) (istype(A, /obj/item/clothing))
-GLOBAL_LIST_INIT(pointed_types, typecacheof(list(
- /obj/item/pen,
- /obj/item/screwdriver,
- /obj/item/reagent_containers/syringe,
- /obj/item/kitchen/fork)))
-
-#define is_pointed(W) (is_type_in_typecache(W, GLOB.pointed_types))
-
#define isbodypart(A) (istype(A, /obj/item/bodypart))
#define isprojectile(A) (istype(A, /obj/item/projectile))
diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm
index 6f33bb1a0e..9188efacfd 100644
--- a/code/__DEFINES/layers_planes.dm
+++ b/code/__DEFINES/layers_planes.dm
@@ -131,6 +131,8 @@
#define LIGHTING_LAYER 15
#define LIGHTING_RENDER_TARGET "LIGHT_PLANE"
+#define RAD_TEXT_LAYER 15.1
+
#define ABOVE_LIGHTING_PLANE 16
#define ABOVE_LIGHTING_LAYER 16
#define ABOVE_LIGHTING_RENDER_TARGET "ABOVE_LIGHTING_PLANE"
diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm
new file mode 100644
index 0000000000..94059c0880
--- /dev/null
+++ b/code/__DEFINES/loadout.dm
@@ -0,0 +1,56 @@
+//defines for loadout categories
+//no category defines
+#define LOADOUT_CATEGORY_NONE "ERROR"
+#define LOADOUT_SUBCATEGORY_NONE "Miscellaneous"
+#define LOADOUT_SUBCATEGORIES_NONE list("Miscellaneous")
+
+//backpack
+#define LOADOUT_CATEGORY_BACKPACK "In backpack"
+#define LOADOUT_SUBCATEGORY_BACKPACK_GENERAL "General" //basically anything that there's not enough of to have its own subcategory
+#define LOADOUT_SUBCATEGORY_BACKPACK_TOYS "Toys"
+//neck
+#define LOADOUT_CATEGORY_NECK "Neck"
+#define LOADOUT_SUBCATEGORY_NECK_GENERAL "General"
+#define LOADOUT_SUBCATEGORY_NECK_TIE "Ties"
+#define LOADOUT_SUBCATEGORY_NECK_SCARVES "Scarves"
+
+//mask
+#define LOADOUT_CATEGORY_MASK "Mask"
+
+//hands
+#define LOADOUT_CATEGORY_HANDS "Hands"
+
+//uniform
+#define LOADOUT_CATEGORY_UNIFORM "Uniform" //there's so many types of uniform it's best to have lots of categories
+#define LOADOUT_SUBCATEGORY_UNIFORM_GENERAL "General"
+#define LOADOUT_SUBCATEGORY_UNIFORM_JOBS "Jobs"
+#define LOADOUT_SUBCATEGORY_UNIFORM_SUITS "Suits"
+#define LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS "Skirts"
+#define LOADOUT_SUBCATEGORY_UNIFORM_DRESSES "Dresses"
+#define LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS "Sweaters"
+#define LOADOUT_SUBCATEGORY_UNIFORM_PANTS "Pants"
+#define LOADOUT_SUBCATEGORY_UNIFORM_SHORTS "Shorts"
+
+//suit
+#define LOADOUT_CATEGORY_SUIT "Suit"
+#define LOADOUT_SUBCATEGORY_SUIT_GENERAL "General"
+#define LOADOUT_SUBCATEGORY_SUIT_COATS "Coats"
+#define LOADOUT_SUBCATEGORY_SUIT_JACKETS "Jackets"
+#define LOADOUT_SUBCATEGORY_SUIT_JOBS "Jobs"
+
+//head
+#define LOADOUT_CATEGORY_HEAD "Head"
+#define LOADOUT_SUBCATEGORY_HEAD_GENERAL "General"
+#define LOADOUT_SUBCATEGORY_HEAD_JOBS "Jobs"
+
+//shoes
+#define LOADOUT_CATEGORY_SHOES "Shoes"
+
+//gloves
+#define LOADOUT_CATEGORY_GLOVES "Gloves"
+
+//glasses
+#define LOADOUT_CATEGORY_GLASSES "Glasses"
+
+//donator items
+#define LOADOUT_CATEGORY_DONATOR "Donator"
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 071dab20b1..927b661898 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -341,10 +341,11 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are.
//Endgame Results
-#define NUKE_MISS_STATION 1
-#define NUKE_SYNDICATE_BASE 2
-#define STATION_DESTROYED_NUKE 3
-#define STATION_EVACUATED 4
+#define NUKE_NEAR_MISS 1
+#define NUKE_MISS_STATION 2
+#define NUKE_SYNDICATE_BASE 3
+#define STATION_DESTROYED_NUKE 4
+#define STATION_EVACUATED 5
#define BLOB_WIN 8
#define BLOB_NUKE 9
#define BLOB_DESTROYED 10
@@ -434,6 +435,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define ION_FILE "ion_laws.json"
#define REDPILL_FILE "redpill.json"
#define PIRATE_NAMES_FILE "pirates.json"
+#define FLESH_SCAR_FILE "wounds/flesh_scar_desc.json"
+#define BONE_SCAR_FILE "wounds/bone_scar_desc.json"
+#define SCAR_LOC_FILE "wounds/scar_loc.json"
//Fullscreen overlay resolution in tiles.
@@ -535,4 +539,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile.
#define LOOT_RESTRICTION_CKEY_PILE 4 //Idem
+//stages of shoe tying-ness
+#define SHOES_UNTIED 0
+#define SHOES_TIED 1
+#define SHOES_KNOTTED 2
+
#define WANTED_FILE "wanted_message.json"
diff --git a/code/__DEFINES/misc/return_values.dm b/code/__DEFINES/misc/return_values.dm
deleted file mode 100644
index d55f603de9..0000000000
--- a/code/__DEFINES/misc/return_values.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-// obj/item/dropped
-/// dropped() relocated this item, return FALSE for doUnEquip.
-#define ITEM_RELOCATED_BY_DROPPED "relocated_by_dropped"
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 42139cdeda..782095f883 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -12,6 +12,8 @@
#define MOVE_INTENT_RUN "run"
//Blood levels
+#define BLOOD_VOLUME_MAX_LETHAL 2150
+#define BLOOD_VOLUME_EXCESS 2100
#define BLOOD_VOLUME_MAXIMUM 2000
#define BLOOD_VOLUME_SLIME_SPLIT 1120
#define BLOOD_VOLUME_NORMAL 560
@@ -57,6 +59,7 @@
#define BODYPART_NOT_DISABLED 0
#define BODYPART_DISABLED_DAMAGE 1
#define BODYPART_DISABLED_PARALYSIS 2
+#define BODYPART_DISABLED_WOUND 3
#define DEFAULT_BODYPART_ICON 'icons/mob/human_parts.dmi'
#define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi'
@@ -103,12 +106,14 @@
#define TRAUMA_RESILIENCE_BASIC 1 //Curable with chems
#define TRAUMA_RESILIENCE_SURGERY 2 //Curable with brain surgery
#define TRAUMA_RESILIENCE_LOBOTOMY 3 //Curable with lobotomy
-#define TRAUMA_RESILIENCE_MAGIC 4 //Curable only with magic
-#define TRAUMA_RESILIENCE_ABSOLUTE 5 //This is here to stay
+#define TRAUMA_RESILIENCE_WOUND 4 //Curable by healing the head wound
+#define TRAUMA_RESILIENCE_MAGIC 5 //Curable only with magic
+#define TRAUMA_RESILIENCE_ABSOLUTE 6 //This is here to stay
//Limit of traumas for each resilience tier
#define TRAUMA_LIMIT_BASIC 3
#define TRAUMA_LIMIT_SURGERY 2
+#define TRAUMA_LIMIT_WOUND 2
#define TRAUMA_LIMIT_LOBOTOMY 3
#define TRAUMA_LIMIT_MAGIC 3
#define TRAUMA_LIMIT_ABSOLUTE INFINITY
@@ -171,6 +176,15 @@
#define DISGUST_LEVEL_VERYGROSS 50
#define DISGUST_LEVEL_GROSS 25
+//Charge levels for Ethereals
+#define ETHEREAL_CHARGE_NONE 0
+#define ETHEREAL_CHARGE_LOWPOWER 20
+#define ETHEREAL_CHARGE_NORMAL 50
+#define ETHEREAL_CHARGE_ALMOSTFULL 75
+#define ETHEREAL_CHARGE_FULL 100
+#define ETHEREAL_CHARGE_OVERLOAD 125
+#define ETHEREAL_CHARGE_DANGEROUS 150
+
//Slime evolution threshold. Controls how fast slimes can split/grow
#define SLIME_EVOLUTION_THRESHOLD 10
@@ -279,6 +293,7 @@
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases
+#define ETHEREAL_CHARGE_FACTOR 0.08 //factor at which ethereal's charge decreases
#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
#define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism
@@ -305,6 +320,7 @@
#define GRAB_PIXEL_SHIFT_NECK 16
#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;
+#define INTERACTING_WITH(X, Y) (Y in X.do_afters)
/// Field of vision defines.
#define FOV_90_DEGREES 90
@@ -315,4 +331,4 @@
#define EYE_CONTACT_RANGE 5
/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
-#define EXAMINE_MORE_TIME 1 SECONDS
\ No newline at end of file
+#define EXAMINE_MORE_TIME 1 SECONDS
diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm
index 699f39e79f..5e7d0a2cca 100644
--- a/code/__DEFINES/movespeed_modification.dm
+++ b/code/__DEFINES/movespeed_modification.dm
@@ -63,7 +63,6 @@
#define MOVESPEED_ID_TASED_STATUS "TASED"
#define MOVESPEED_ID_ELECTROSTAFF "ELECTROSTAFF"
-#define MOVESPEED_ID_SHOVE "SHOVE"
#define MOVESPEED_ID_FAT "FAT"
#define MOVESPEED_ID_COLD "COLD"
#define MOVESPEED_ID_HUNGRY "HUNGRY"
diff --git a/code/__DEFINES/pool.dm b/code/__DEFINES/pool.dm
index 1e66109dc7..64bbd20b19 100644
--- a/code/__DEFINES/pool.dm
+++ b/code/__DEFINES/pool.dm
@@ -8,6 +8,5 @@
GLOBAL_LIST_INIT(blacklisted_pool_reagents, list(
/datum/reagent/toxin/plasma, /datum/reagent/oxygen, /datum/reagent/nitrous_oxide, /datum/reagent/nitrogen, //gases
/datum/reagent/fermi, //blanket fermichem ban sorry. this also covers mkultra, genital enlargers, etc etc.
- /datum/reagent/drug/aphrodisiac, /datum/reagent/drug/anaphrodisiac, /datum/reagent/drug/aphrodisiacplus, /datum/reagent/drug/anaphrodisiacplus, //literally asking for prefbreaks
/datum/reagent/consumable/femcum, /datum/reagent/consumable/semen //NO.
))
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 4225581018..9a3b5d55f4 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -36,6 +36,8 @@
#define STATUS_EFFECT_REGENERATIVE_CORE /datum/status_effect/regenerative_core //removes damage slowdown while giving a slow regenerating effect
+#define STATUS_EFFECT_DETERMINED /datum/status_effect/determined //currently in a combat high from being seriously wounded
+
/////////////
// DEBUFFS //
/////////////
@@ -107,6 +109,11 @@
#define STATUS_EFFECT_ELECTROSTAFF /datum/status_effect/electrostaff //slows down victim
+#define STATUS_EFFECT_LIMP /datum/status_effect/limp //For when you have a busted leg (or two!) and want additional slowdown when walking on that leg
+
+/// shoves inflict this to indicate the next shove while this is in effect should disarm guns
+#define STATUS_EFFECT_OFF_BALANCE /datum/status_effect/off_balance
+
/////////////
// NEUTRAL //
/////////////
diff --git a/code/__DEFINES/storage/_storage.dm b/code/__DEFINES/storage/_storage.dm
index 3a05293d2d..6eb613b423 100644
--- a/code/__DEFINES/storage/_storage.dm
+++ b/code/__DEFINES/storage/_storage.dm
@@ -19,7 +19,7 @@
/// Size of EACH left/right border icon for volumetric boxes
#define VOLUMETRIC_STORAGE_BOX_BORDER_SIZE 1
/// Minimum pixels an item must have in volumetric scaled storage UI
-#define MINIMUM_PIXELS_PER_ITEM 8
+#define MINIMUM_PIXELS_PER_ITEM 16
/// Maximum number of objects that will be allowed to be displayed using the volumetric display system. Arbitrary number to prevent server lockups.
#define MAXIMUM_VOLUMETRIC_ITEMS 256
/// How much padding to give between items
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index bf76f8a523..7a188281d0 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -107,6 +107,7 @@
#define FIRE_PRIORITY_INSTRUMENTS 30
#define FIRE_PRIORITY_FIELDS 30
#define FIRE_PRIOTITY_SMOOTHING 35
+#define FIRE_PRIORITY_HUDS 40
#define FIRE_PRIORITY_NETWORKS 40
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_ACID 40
@@ -152,14 +153,17 @@
var/list/po = A.priority_overlays;\
if(LAZYLEN(rm)){\
A.overlays -= rm;\
- rm.Cut();\
+ A.remove_overlays = null;\
}\
if(LAZYLEN(ad)){\
A.overlays |= ad;\
- ad.Cut();\
+ A.add_overlays = null;\
}\
if(LAZYLEN(po)){\
A.overlays |= po;\
}\
+ else{\
+ A.priority_overlays = null;\
+ }\
A.flags_1 &= ~OVERLAY_QUEUED_1;\
}
diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm
index 5ba0096d1b..f5adeadade 100644
--- a/code/__DEFINES/tgui.dm
+++ b/code/__DEFINES/tgui.dm
@@ -1,4 +1,28 @@
-#define UI_INTERACTIVE 2 // Green/Interactive
-#define UI_UPDATE 1 // Orange/Updates Only
-#define UI_DISABLED 0 // Red/Disabled
-#define UI_CLOSE -1 // Closed
\ No newline at end of file
+/// Green eye; fully interactive
+#define UI_INTERACTIVE 2
+/// Orange eye; updates but is not interactive
+#define UI_UPDATE 1
+/// Red eye; disabled, does not update
+#define UI_DISABLED 0
+/// UI Should close
+#define UI_CLOSE -1
+
+/// Maximum number of windows that can be suspended/reused
+#define TGUI_WINDOW_SOFT_LIMIT 5
+/// Maximum number of open windows
+#define TGUI_WINDOW_HARD_LIMIT 9
+
+/// Maximum ping timeout allowed to detect zombie windows
+#define TGUI_PING_TIMEOUT 4 SECONDS
+
+/// Window does not exist
+#define TGUI_WINDOW_CLOSED 0
+/// Window was just opened, but is still not ready to be sent data
+#define TGUI_WINDOW_LOADING 1
+/// Window is free and ready to receive data
+#define TGUI_WINDOW_READY 2
+
+/// Get a window id based on the provided pool index
+#define TGUI_WINDOW_ID(index) "tgui-window-[index]"
+/// Get a pool index of the provided window id
+#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13))
diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm
index 7e391caaed..a472e83795 100644
--- a/code/__DEFINES/tools.dm
+++ b/code/__DEFINES/tools.dm
@@ -17,6 +17,7 @@
//Glasswork Tools
#define TOOL_BLOW "blowing_rod"
#define TOOL_GLASS_CUT "glasskit"
+#define TOOL_BONESET "bonesetter"
// If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY,
// tool sound is only played when op is started. If not, it's played twice.
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index eb86c52301..3e5b27d376 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -228,7 +228,7 @@
#define TRAIT_SPRINT_LOCKED "sprint_locked"
//non-mob traits
-#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
+#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
#define VEHICLE_TRAIT "vehicle" // inherited from riding vehicles
#define INNATE_TRAIT "innate"
diff --git a/code/__DEFINES/wounds.dm b/code/__DEFINES/wounds.dm
new file mode 100644
index 0000000000..73ada71423
--- /dev/null
+++ b/code/__DEFINES/wounds.dm
@@ -0,0 +1,119 @@
+
+#define WOUND_DAMAGE_EXPONENT 1.225
+
+/// an attack must do this much damage after armor in order to roll for being a wound (incremental pressure damage need not apply)
+#define WOUND_MINIMUM_DAMAGE 5
+/// an attack must do this much damage after armor in order to be eliigible to dismember a suitably mushed bodypart
+#define DISMEMBER_MINIMUM_DAMAGE 10
+/// any damage dealt over this is ignored for damage rolls unless the target has the frail quirk (35^1.4=145)
+#define WOUND_MAX_CONSIDERED_DAMAGE 35
+
+
+#define WOUND_SEVERITY_TRIVIAL 0 // for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds
+#define WOUND_SEVERITY_MODERATE 1
+#define WOUND_SEVERITY_SEVERE 2
+#define WOUND_SEVERITY_CRITICAL 3
+#define WOUND_SEVERITY_LOSS 4 // theoretical total limb loss, like dismemberment for cuts
+
+/// any brute weapon/attack that doesn't have sharpness. rolls for blunt bone wounds
+#define WOUND_BLUNT 1
+/// any brute weapon/attack with sharpness = SHARP_EDGED. rolls for slash wounds
+#define WOUND_SLASH 2
+/// any brute weapon/attack with sharpness = SHARP_POINTY. rolls for piercing wounds
+#define WOUND_PIERCE 3
+/// any concentrated burn attack (lasers really). rolls for burning wounds
+#define WOUND_BURN 4
+
+// How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind()]
+#define WOUND_DETERMINATION_MODERATE 1
+#define WOUND_DETERMINATION_SEVERE 2.5
+#define WOUND_DETERMINATION_CRITICAL 5
+#define WOUND_DETERMINATION_LOSS 7.5
+
+/// the max amount of determination you can have
+#define WOUND_DETERMINATION_MAX 10
+
+/// set wound_bonus on an item or attack to this to disable checking wounding for the attack
+#define CANT_WOUND -100
+
+// list in order of highest severity to lowest
+GLOBAL_LIST_INIT(global_wound_types, list(WOUND_BLUNT = list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate),
+ WOUND_SLASH = list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate),
+ WOUND_PIERCE = list(/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate),
+ WOUND_BURN = list(/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate)
+ ))
+
+GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate,
+ /datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate,
+ /datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate,
+ /datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate))
+
+// Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse
+/// below this has no ill effects from infection
+#define WOUND_INFECTION_MODERATE 4
+/// then below here, you ooze some pus and suffer minor tox damage, but nothing serious
+#define WOUND_INFECTION_SEVERE 8
+/// then below here, your limb occasionally locks up from damage and infection and briefly becomes disabled. Things are getting really bad
+#define WOUND_INFECTION_CRITICAL 12
+/// below here, your skin is almost entirely falling off and your limb locks up more frequently. You are within a stone's throw of septic paralysis and losing the limb
+#define WOUND_INFECTION_SEPTIC 20
+// above WOUND_INFECTION_SEPTIC, your limb is completely putrid and you start rolling to lose the entire limb by way of paralyzation. After 3 failed rolls (~4-5% each probably), the limb is paralyzed
+
+
+/// how quickly sanitization removes infestation and decays per tick
+#define WOUND_BURN_SANITIZATION_RATE 0.15
+/// how much blood you can lose per tick per slash max. 8 is a LOT of blood for one cut so don't worry about hitting it easily
+#define WOUND_SLASH_MAX_BLOODFLOW 8
+/// dead people don't bleed, but they can clot! this is the minimum amount of clotting per tick on dead people, so even critical cuts will slowly clot in dead people
+#define WOUND_SLASH_DEAD_CLOT_MIN 0.05
+/// if we suffer a bone wound to the head that creates brain traumas, the timer for the trauma cycle is +/- by this percent (0-100)
+#define WOUND_BONE_HEAD_TIME_VARIANCE 20
+
+// The following are for persistent scar save formats
+/// The version number of the scar we're saving
+#define SCAR_SAVE_VERS 1
+/// The body_zone we're applying to on granting
+#define SCAR_SAVE_ZONE 2
+/// The description we're loading
+#define SCAR_SAVE_DESC 3
+/// The precise location we're loading
+#define SCAR_SAVE_PRECISE_LOCATION 4
+/// The severity the scar had
+#define SCAR_SAVE_SEVERITY 5
+///how many fields there are above (NOT INCLUDING THIS OBVIOUSLY)
+#define SCAR_SAVE_LENGTH 5
+
+// increment this number when you update the persistent scarring format in a way that invalidates previous saved scars (new fields, reordering, etc)
+/// saved scars with a version lower than this will be discarded
+#define SCAR_CURRENT_VERSION 1
+
+
+// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (bone only creatures just need the second):
+// 1. Skin is mangled: A critical slash or pierce wound on that limb
+// 2. Bone is mangled: At least a severe bone wound on that limb
+// see [/obj/item/bodypart/proc/get_mangled_state] for more information
+#define BODYPART_MANGLED_NONE 0
+#define BODYPART_MANGLED_BONE 1
+#define BODYPART_MANGLED_FLESH 2
+#define BODYPART_MANGLED_BOTH 3
+
+// What kind of biology we have, and what wounds we can suffer, mostly relies on the HAS_FLESH and HAS_BONE species traits on human species
+/// golems and androids, cannot suffer any wounds
+#define BIO_INORGANIC 0
+/// skeletons and plasmemes, can only suffer bone wounds, only needs mangled bone to be able to dismember
+#define BIO_JUST_BONE 1
+/// nothing right now, maybe slimepeople in the future, can only suffer slashing, piercing, and burn wounds
+#define BIO_JUST_FLESH 2
+/// standard humanoids, can suffer all wounds, needs mangled bone and flesh to dismember
+#define BIO_FLESH_BONE 3
+
+/// If this wound requires having the HAS_FLESH flag for humanoids
+#define FLESH_WOUND (1<<0)
+/// If this wound requires having the HAS_BONE flag for humanaoids
+#define BONE_WOUND (1<<1)
+/// If having this wound counts as mangled flesh for dismemberment
+#define MANGLES_FLESH (1<<2)
+/// If having this wound counts as mangled bone for dismemberment
+#define MANGLES_BONE (1<<3)
+/// If this wound marks the limb as being allowed to have gauze applied
+#define ACCEPTS_GAUZE (1<<4)
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 84709a78b1..62e6c4daf9 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -81,6 +81,10 @@
if (CONFIG_GET(flag/log_attack))
WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]")
+/proc/log_wounded(text)
+ if (CONFIG_GET(flag/log_attack))
+ WRITE_LOG(GLOB.world_attack_log, "WOUND: [text]")
+
/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE)
if (CONFIG_GET(flag/log_manifest))
WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]")
@@ -197,9 +201,18 @@
WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------")
/* ui logging */
-
-/proc/log_tgui(text)
- WRITE_LOG(GLOB.tgui_log, text)
+/proc/log_tgui(user_or_client, text)
+ var/entry = ""
+ if(!user_or_client)
+ entry += "no user"
+ else if(istype(user_or_client, /mob))
+ var/mob/user = user_or_client
+ entry += "[user.ckey] (as [user])"
+ else if(istype(user_or_client, /client))
+ var/client/client = user_or_client
+ entry += "[client.ckey]"
+ entry += ":\n[text]"
+ WRITE_LOG(GLOB.tgui_log, entry)
/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
/proc/shutdown_logging()
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index 0825e51ae4..a688d20451 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -85,9 +85,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B)
return A.totalResistance() - B.totalResistance()
-/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
- return A.display_order - B.display_order
-
/proc/cmp_uplink_items_dsc(datum/uplink_item/A, datum/uplink_item/B)
return sorttext(initial(B.name), initial(A.name))
@@ -97,9 +94,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_numbered_displays_name_dsc(datum/numbered_display/A, datum/numbered_display/B)
return sorttext(B.sample_object.name, A.sample_object.name)
-/proc/cmp_reagents_asc(datum/reagent/a, datum/reagent/b)
- return sorttext(initial(b.name),initial(a.name))
-
/proc/cmp_quirk_asc(datum/quirk/A, datum/quirk/B)
var/a_sign = num2sign(initial(A.value) * -1)
var/b_sign = num2sign(initial(B.value) * -1)
@@ -133,3 +127,12 @@ GLOBAL_VAR_INIT(cmp_field, "name")
return A.required_temp - B.required_temp //return coldest
else
return B.required_temp - A.required_temp //return hottest
+
+/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
+ return A.display_order - B.display_order
+
+/proc/cmp_reagents_asc(datum/reagent/a, datum/reagent/b)
+ return sorttext(initial(b.name),initial(a.name))
+
+/proc/cmp_typepaths_asc(A, B)
+ return sorttext("[B]","[A]")
\ No newline at end of file
diff --git a/code/__HELPERS/do_after.dm b/code/__HELPERS/do_after.dm
index f1f483c345..30d40f3867 100644
--- a/code/__HELPERS/do_after.dm
+++ b/code/__HELPERS/do_after.dm
@@ -166,6 +166,9 @@
var/target_loc = target.loc
+ LAZYADD(user.do_afters, target)
+ LAZYADD(target.targeted_by, user)
+
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
if (progress)
@@ -183,6 +186,13 @@
break
if(uninterruptible)
continue
+ if(!(target in user.do_afters))
+ . = FALSE
+ break
+
+ if(!(target in user.do_afters))
+ . = FALSE
+ break
if(drifting && !user.inertia_dir)
drifting = 0
@@ -191,13 +201,16 @@
if((!drifting && user.loc != user_loc) || target.loc != target_loc || (!ignorehelditem && user.get_active_held_item() != holding) || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke()))
. = 0
break
- if (progress)
+ if(progress)
qdel(progbar)
+ if(!QDELETED(target))
+ LAZYREMOVE(user.do_afters, target)
+ LAZYREMOVE(target.targeted_by, user)
//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
- if(check_clicks && next_move > world.time)
+ if(check_clicks && !CheckActionCooldown())
return FALSE
return TRUE
@@ -216,6 +229,10 @@
if(target && !isturf(target))
Tloc = target.loc
+ if(target)
+ LAZYADD(user.do_afters, target)
+ LAZYADD(target.targeted_by, user)
+
var/atom/Uloc = user.loc
var/drifting = 0
@@ -260,6 +277,10 @@
. = 0
break
+ if(target && !(target in user.do_afters))
+ . = FALSE
+ break
+
if(needhand)
//This might seem like an odd check, but you can still need a hand even when it's empty
//i.e the hand is used to pull some item/tool out of the construction
@@ -270,8 +291,14 @@
if(user.get_active_held_item() != holding)
. = 0
break
- if (progress)
+ if(progress)
qdel(progbar)
+ if(!QDELETED(target))
+ LAZYREMOVE(user.do_afters, target)
+
+ if(!QDELETED(target))
+ LAZYREMOVE(user.do_afters, target)
+ LAZYREMOVE(target.targeted_by, user)
/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
. = 1
@@ -291,6 +318,8 @@
var/list/originalloc = list()
for(var/atom/target in targets)
originalloc[target] = target.loc
+ LAZYADD(user.do_afters, target)
+ LAZYADD(target.targeted_by, user)
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
@@ -321,3 +350,8 @@
break mainloop
if(progbar)
qdel(progbar)
+ for(var/thing in targets)
+ var/atom/target = thing
+ if(!QDELETED(target))
+ LAZYREMOVE(user.do_afters, target)
+ LAZYREMOVE(target.targeted_by, user)
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index f8f6bca31a..c4964022e5 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -145,9 +145,9 @@
continue
if(!S.ckeys_allowed)
snowflake_ipc_antenna_list[S.name] = mspath
- var/color1 = random_short_color()
- var/color2 = random_short_color()
- var/color3 = random_short_color()
+ var/color1 = random_color()
+ var/color2 = random_color()
+ var/color3 = random_color()
var/body_model = MALE
switch(intended_gender)
@@ -264,6 +264,13 @@
if(!findname(.))
break
+/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10)
+ for(var/i in 1 to attempts_to_find_unique_name)
+ . = capitalize(ethereal_name())
+
+ if(!findname(.))
+ break
+
/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
for(var/i in 1 to attempts_to_find_unique_name)
. = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last))
diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm
index 8b699e3eee..e1848b21a2 100644
--- a/code/__HELPERS/names.dm
+++ b/code/__HELPERS/names.dm
@@ -4,6 +4,12 @@
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
+/proc/ethereal_name()
+ var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
+ if(prob(65))
+ tempname += random_capital_letter()
+ return tempname
+
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm
index cbe1817233..0441e0bcb7 100644
--- a/code/__HELPERS/sanitize_values.dm
+++ b/code/__HELPERS/sanitize_values.dm
@@ -51,40 +51,111 @@
return default
return default
-/proc/sanitize_hexcolor(color, desired_format=3, include_crunch=0, default)
+#define RGB_FORMAT_INVALID 0
+#define RGB_FORMAT_SHORT 1
+#define RGB_FORMAT_LONG 2
+
+/**
+ * Sanitizes a hexadecimal color. Always outputs lowercase.
+ *
+ * @params
+ * * color - input color, 3 or 6 characters without the #.
+ * * desired_format - 3 or 6 characters without the potential #. can only put in 3 or 6 here.
+ * * include_crunch - do we put a # at the start
+ * * default - default color. must be 3 or 6 characters with or without #.
+ * * default_replacement - what we replace broken letters with.
+ */
+/proc/sanitize_hexcolor(color, desired_format = 3, include_crunch = 0, default = rgb(218, 72, 255), default_replacement = "f")
+ if(!istext(default) || (length(default) < 3))
+ CRASH("Default should be a text string of RGB format, with or without the crunch, 3 or 6 characters. Default was instead [default]")
+ if(!istext(default_replacement) || (length(default_replacement) != 1))
+ CRASH("Invalid default_replacement: [default_replacement]")
+ default_replacement = lowertext(default_replacement)
+ switch(text2ascii(default_replacement))
+ if(48 to 57)
+ if(97 to 102)
+ if(65 to 70)
+ else // yeah yeah i know 3 empty if's..
+ CRASH("Invalid default_replacement: [default_replacement]")
var/crunch = include_crunch ? "#" : ""
if(!istext(color))
- color = ""
+ color = default
- var/start = 1 + (text2ascii(color, 1) == 35)
var/len = length(color)
- var/char = ""
- // RRGGBB -> RGB but awful
- var/convert_to_shorthand = desired_format == 3 && length_char(color) > 3
+ // get rid of crunch
+ if(len && color[1] == "#")
+ if(len >= 2)
+ color = copytext(color, 2)
+ else
+ color = ""
+ len = length(color)
- . = ""
- var/i = start
- while(i <= len)
+ switch(desired_format)
+ if(3)
+ desired_format = RGB_FORMAT_SHORT
+ if(6)
+ desired_format = RGB_FORMAT_LONG
+ else
+ CRASH("Invalid desired_format: [desired_format]. Must be 3 or 6.")
+ var/current_format = RGB_FORMAT_INVALID
+ switch(length(color))
+ if(3)
+ current_format = RGB_FORMAT_SHORT
+ if(6)
+ current_format = RGB_FORMAT_LONG
+ else
+ current_format = RGB_FORMAT_INVALID
+
+ if(current_format == RGB_FORMAT_INVALID) // nah
+ color = default // process default
+ if(color[1] == "#") // we checked default was at least 3 chars long earlier
+ color = copytext(color, 2)
+ len = length(color)
+ switch(len)
+ if(3)
+ current_format = RGB_FORMAT_SHORT
+ if(6)
+ current_format = RGB_FORMAT_LONG
+ else
+ CRASH("Default was not 3 or 6 RGB hexadecimal characters: [default]")
+
+ var/sanitized = ""
+ var/char = ""
+ // first, sanitize hex
+ for(var/i in 1 to len)
char = color[i]
switch(text2ascii(char))
- if(48 to 57) //numbers 0 to 9
- . += char
- if(97 to 102) //letters a to f
- . += char
- if(65 to 70) //letters A to F
- . += lowertext(char)
+ if(48 to 57) // 0 to 9
+ sanitized += char
+ if(97 to 102) // a to f
+ sanitized += char
+ if(65 to 70) // A to F (capitalized!)
+ sanitized += lowertext(char)
else
- break
- i += length(char)
- if(convert_to_shorthand && i <= len) //skip next one
- i += length(color[i])
+ sanitized += default_replacement
+ // do we need to convert?
+ if(desired_format == current_format)
+ return crunch + sanitized // no
+ // yes
+ if((desired_format == RGB_FORMAT_SHORT) && (current_format == RGB_FORMAT_LONG)) // downconvert
+ var/temp = ""
+ // we could do some math but we're lazy and in practice floor()ing this.
+ for(var/i in 1 to 6 step 2)
+ temp += sanitized[i]
+ sanitized = temp
+ else if((desired_format == RGB_FORMAT_LONG) && (current_format == RGB_FORMAT_SHORT)) // upconvert
+ var/temp = ""
+ for(var/i in 1 to 3)
+ temp += sanitized[i]
+ temp += sanitized[i]
+ sanitized = temp
+ else
+ CRASH("Invalid desired_format and current_format pair: [desired_format], [current_format]. Could not determine which way to convert.")
+ return crunch + sanitized
- if(length_char(.) != desired_format)
- if(default)
- return default
- return crunch + repeat_string(desired_format, "0")
-
- return crunch + .
+#undef RGB_FORMAT_INVALID
+#undef RGB_FORMAT_SHORT
+#undef RGB_FORMAT_LONG
/proc/sanitize_ooccolor(color)
if(length(color) != length_char(color))
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index 9c71cfeb69..7c251edd88 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -113,6 +113,22 @@
else
return trim(html_encode(name), max_length)
+/**
+ * stripped_multiline_input but reflects to the user instead if it's too big and returns null.
+ */
+/proc/stripped_multiline_input_or_reflect(mob/user, message = "", title = "", default = "", max_length=MAX_MESSAGE_LEN, no_trim=FALSE)
+ var/name = input(user, message, title, default) as message|null
+ if(isnull(name)) // Return null if canceled.
+ return null
+ if(length(name) > max_length)
+ to_chat(user, name)
+ to_chat(user, "^^^----- The preceeding message has been DISCARDED for being over the maximum length of [max_length]. It has NOT been sent! -----^^^")
+ return null
+ if(no_trim)
+ return copytext(html_encode(name), 1, max_length)
+ else
+ return trim(html_encode(name), max_length)
+
#define NO_CHARS_DETECTED 0
#define SPACES_DETECTED 1
#define SYMBOLS_DETECTED 2
@@ -760,6 +776,10 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
else
return "[number]\th"
+
+/proc/random_capital_letter()
+ return uppertext(pick(GLOB.alphabet))
+
/proc/unintelligize(message)
var/regex/word_boundaries = regex(@"\b[\S]+\b", "g")
var/prefix = message[1]
@@ -811,4 +831,4 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
corrupted_text += pick(corruption_options)
if(prob(15))
corrupted_text += pick(corruption_options)
- return corrupted_text
\ No newline at end of file
+ return corrupted_text
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 2c8497d5ed..7a18d2ce01 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -339,10 +339,24 @@
/proc/isLeap(y)
return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
-
+/// For finding out what body parts a body zone covers, the inverse of the below basically
+/proc/zone2body_parts_covered(def_zone)
+ switch(def_zone)
+ if(BODY_ZONE_CHEST)
+ return list(CHEST, GROIN)
+ if(BODY_ZONE_HEAD)
+ return list(HEAD)
+ if(BODY_ZONE_L_ARM)
+ return list(ARM_LEFT, HAND_LEFT)
+ if(BODY_ZONE_R_ARM)
+ return list(ARM_RIGHT, HAND_RIGHT)
+ if(BODY_ZONE_L_LEG)
+ return list(LEG_LEFT, FOOT_LEFT)
+ if(BODY_ZONE_R_LEG)
+ return list(LEG_RIGHT, FOOT_RIGHT)
//Turns a Body_parts_covered bitfield into a list of organ/limb names.
-//(I challenge you to find a use for this)
+//(I challenge you to find a use for this) -I found a use for it!!
/proc/body_parts_covered2organ_names(bpc)
var/list/covered_parts = list()
diff --git a/code/_globalvars/lists/loadout_categories.dm b/code/_globalvars/lists/loadout_categories.dm
new file mode 100644
index 0000000000..0f0ac52214
--- /dev/null
+++ b/code/_globalvars/lists/loadout_categories.dm
@@ -0,0 +1,13 @@
+GLOBAL_LIST_INIT(loadout_categories, list(
+ LOADOUT_CATEGORY_BACKPACK = list(LOADOUT_SUBCATEGORY_BACKPACK_GENERAL, LOADOUT_SUBCATEGORY_BACKPACK_TOYS),
+ LOADOUT_CATEGORY_NECK = list(LOADOUT_SUBCATEGORY_NECK_GENERAL, LOADOUT_SUBCATEGORY_NECK_TIE, LOADOUT_SUBCATEGORY_NECK_SCARVES),
+ LOADOUT_CATEGORY_MASK = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_HANDS = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_UNIFORM = list(LOADOUT_SUBCATEGORY_UNIFORM_GENERAL, LOADOUT_SUBCATEGORY_UNIFORM_JOBS, LOADOUT_SUBCATEGORY_UNIFORM_SUITS, LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS, LOADOUT_SUBCATEGORY_UNIFORM_DRESSES, LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS, LOADOUT_SUBCATEGORY_UNIFORM_PANTS, LOADOUT_SUBCATEGORY_UNIFORM_SHORTS),
+ LOADOUT_CATEGORY_SUIT = list(LOADOUT_SUBCATEGORY_SUIT_GENERAL, LOADOUT_SUBCATEGORY_SUIT_COATS, LOADOUT_SUBCATEGORY_SUIT_JACKETS, LOADOUT_SUBCATEGORY_SUIT_JOBS),
+ LOADOUT_CATEGORY_HEAD = list(LOADOUT_SUBCATEGORY_HEAD_GENERAL, LOADOUT_SUBCATEGORY_HEAD_JOBS),
+ LOADOUT_CATEGORY_SHOES = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_GLOVES = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_GLASSES = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE
+))
diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm
index e334d08040..b80fcf0bbf 100644
--- a/code/_globalvars/lists/names.dm
+++ b/code/_globalvars/lists/names.dm
@@ -17,6 +17,7 @@ GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt"))
GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt"))
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt"))
+GLOBAL_LIST_INIT(ethereal_names, world.file2list("strings/names/ethereal.txt"))
GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt"))
GLOBAL_LIST_INIT(nightmare_names, world.file2list("strings/names/nightmare.txt"))
GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1.txt"))
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 7b40c96a6d..18aaf66659 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -19,10 +19,6 @@
A.move_camera_by_click()
/mob/living/silicon/ai/ClickOn(var/atom/A, params)
- if(world.time <= next_click)
- return
- next_click = world.time + 1
-
if(!can_interact_with(A))
return
@@ -74,16 +70,16 @@
CtrlClickOn(A)
return
- if(world.time <= next_move)
+ if(!CheckActionCooldown(immediate = TRUE))
return
if(aicamera.in_camera_mode)
aicamera.camera_mode_off()
- aicamera.captureimage(pixel_turf, usr)
+ INVOKE_ASYNC(aicamera, /obj/item/camera.proc/captureimage, pixel_turf, usr)
return
if(waypoint_mode)
- waypoint_mode = 0
- set_waypoint(A)
+ waypoint_mode = FALSE
+ INVOKE_ASYNC(src, .proc/set_waypoint, A)
return
A.attack_ai(src)
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 8a63339081..042ab3aaee 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -1,38 +1,3 @@
-/*
- Click code cleanup
- ~Sayu
-*/
-
-// 1 decisecond click delay (above and beyond mob/next_move)
-//This is mainly modified by click code, to modify click delays elsewhere, use next_move and changeNext_move()
-/mob/var/next_click = 0
-
-// THESE DO NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
-/mob/var/next_move_adjust = 0 //Amount to adjust action/click delays by, + or -
-/mob/var/next_move_modifier = 1 //Value to multiply action/click delays by
-
-
-//Delays the mob's next click/action by num deciseconds
-// eg: 10-3 = 7 deciseconds of delay
-// eg: 10*0.5 = 5 deciseconds of delay
-// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
-
-/mob/proc/timeToNextMove()
- return max(0, next_move - world.time)
-
-/mob/proc/changeNext_move(num)
- next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
-
-/mob/living/changeNext_move(num)
- last_click_move = next_move
- var/mod = next_move_modifier
- var/adj = next_move_adjust
- for(var/i in status_effects)
- var/datum/status_effect/S = i
- mod *= S.nextmove_modifier()
- adj += S.nextmove_adjust()
- next_move = world.time + ((num + adj)*mod)
-
/*
Before anything else, defer these calls to a per-mobtype handler. This allows us to
remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
@@ -45,7 +10,7 @@
/atom/Click(location,control,params)
if(flags_1 & INITIALIZED_1)
SEND_SIGNAL(src, COMSIG_CLICK, location, control, params, usr)
- usr.ClickOn(src, params)
+ usr.CommonClickOn(src, params)
/atom/DblClick(location,control,params)
if(flags_1 & INITIALIZED_1)
@@ -55,6 +20,21 @@
if(flags_1 & INITIALIZED_1)
usr.MouseWheelOn(src, delta_x, delta_y, params)
+/**
+ * Common mob click code
+ */
+/mob/proc/CommonClickOn(atom/A, params)
+ SHOULD_NOT_SLEEP(TRUE)
+ if(mob_transforming)
+ return
+ if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON)
+ return
+ . = ClickOn(A, params)
+ if(!(. & DISCARD_LAST_ACTION))
+ FlushCurrentAction()
+ else
+ DiscardCurrentAction()
+
/*
Standard mob ClickOn()
Handles exceptions: Buildmode, middle click, modified clicks, mech actions
@@ -68,50 +48,34 @@
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
*/
-/mob/proc/ClickOn( atom/A, params )
- if(world.time <= next_click)
- return
- next_click = world.time + world.tick_lag
-
+/mob/proc/ClickOn(atom/A, params)
+ SHOULD_NOT_SLEEP(TRUE)
if(check_click_intercept(params,A))
return
- if(mob_transforming)
- return
-
- if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON)
- return
-
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])
- ShiftMiddleClickOn(A)
- return
+ return ShiftMiddleClickOn(A)
if(modifiers["shift"] && modifiers["ctrl"])
- CtrlShiftClickOn(A)
- return
+ return CtrlShiftClickOn(A)
if(modifiers["middle"])
- MiddleClickOn(A)
- return
+ return MiddleClickOn(A)
if(modifiers["shift"] && (client && client.show_popup_menus || modifiers["right"])) //CIT CHANGE - makes shift-click examine use right click instead of left click in combat mode
- ShiftClickOn(A)
- return
+ return ShiftClickOn(A)
if(modifiers["alt"]) // alt and alt-gr (rightalt)
- AltClickOn(A)
- return
+ return AltClickOn(A)
if(modifiers["ctrl"])
- CtrlClickOn(A)
- return
+ return CtrlClickOn(A)
if(modifiers["right"]) //CIT CHANGE - allows right clicking to perform actions
- RightClickOn(A,params) //CIT CHANGE - ditto
- return //CIT CHANGE - ditto
+ return RightClickOn(A, params) //CIT CHANGE - ditto
if(incapacitated(ignore_restraints = 1))
return
face_atom(A)
- if(next_move > world.time) // in the year 2000...
+ if(!CheckActionCooldown(immediate = TRUE))
return
if(!modifiers["catcher"] && A.IsObscured())
@@ -119,12 +83,12 @@
if(ismecha(loc))
var/obj/mecha/M = loc
- return M.click_action(A,src,params)
+ M.click_action(A,src,params)
+ return TRUE
if(restrained())
- changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
- RestrainedClickOn(A)
- return
+ DelayNextAction(CLICK_CD_HANDCUFFED)
+ return RestrainedClickOn(A)
if(in_throw_mode)
throw_item(A)
@@ -141,12 +105,12 @@
//User itself, current loc, and user inventory
if(A in DirectAccess())
if(W)
- W.melee_attack_chain(src, A, params)
+ return W.melee_attack_chain(src, A, params)
else
- if(ismob(A))
- changeNext_move(CLICK_CD_MELEE)
- UnarmedAttack(A)
- return
+ . = UnarmedAttack(A, TRUE, a_intent)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
+ DelayNextAction(CLICK_CD_MELEE)
+ return
//Can't reach anything else in lockers or other weirdness
if(!loc.AllowClick())
@@ -155,16 +119,17 @@
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
- W.melee_attack_chain(src, A, params)
+ return W.melee_attack_chain(src, A, params)
else
- if(ismob(A))
- changeNext_move(CLICK_CD_MELEE)
- UnarmedAttack(A, 1)
+ . = UnarmedAttack(A, TRUE, a_intent)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
+ DelayNextAction(CLICK_CD_MELEE)
+ return
else
if(W)
- W.ranged_attack_chain(src, A, params)
+ return W.ranged_attack_chain(src, A, params)
else
- RangedAttack(A,params)
+ return RangedAttack(A,params)
//Is the atom obscured by a PREVENT_CLICK_UNDER_1 object above it
/atom/proc/IsObscured()
@@ -270,8 +235,6 @@
in human click code to allow glove touches only at melee range.
*/
/mob/proc/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
- if(ismob(A))
- changeNext_move(CLICK_CD_MELEE)
/*
Ranged unarmed attack:
@@ -304,7 +267,6 @@
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
- next_click = world.time + 5
return
swap_hand()
@@ -337,24 +299,24 @@
*/
/mob/proc/CtrlClickOn(atom/A)
- A.CtrlClick(src)
- return
+ return A.CtrlClick(src)
/atom/proc/CtrlClick(mob/user)
SEND_SIGNAL(src, COMSIG_CLICK_CTRL, user)
var/mob/living/ML = user
if(istype(ML))
- ML.pulled(src)
+ INVOKE_ASYNC(ML, /mob/living.verb/pulled, src)
/mob/living/carbon/human/CtrlClick(mob/user)
if(ishuman(user) && Adjacent(user) && !user.incapacitated())
- if(world.time < user.next_move)
+ if(!user.CheckActionCooldown())
return FALSE
var/mob/living/carbon/human/H = user
H.dna.species.grab(H, src, H.mind.martial_art)
- H.changeNext_move(CLICK_CD_MELEE)
+ H.DelayNextAction(CLICK_CD_MELEE)
+ return TRUE
else
- ..()
+ return ..()
/*
Alt click
Unused except for AI
@@ -377,8 +339,8 @@
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
- next_click = world.time + 5
- return
+ DelayNextAction(CLICK_CD_RANGE)
+ return TRUE
..()
/atom/proc/AltClick(mob/user)
@@ -413,9 +375,11 @@
return
/mob/living/LaserEyes(atom/A, params)
- changeNext_move(CLICK_CD_RANGE)
+ if(!CheckActionCooldown(CLICK_CD_RANGE))
+ return
+ DelayNextAction()
- var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
+ var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam(loc)
LE.icon = 'icons/effects/genetics.dmi'
LE.icon_state = "eyelasers"
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
@@ -424,6 +388,7 @@
LE.def_zone = get_organ_target()
LE.preparePixelProjectile(A, src, params)
LE.fire()
+ return TRUE
// Simple helper to face what you clicked on, in case it should be needed in more than one place
/mob/proc/face_atom(atom/A, ismousemovement = FALSE)
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 82288ee0d1..372fe46046 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -7,10 +7,6 @@
*/
/mob/living/silicon/robot/ClickOn(var/atom/A, var/params)
- if(world.time <= next_click)
- return
- next_click = world.time + 1
-
if(check_click_intercept(params,A))
return
@@ -19,25 +15,19 @@
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
- CtrlShiftClickOn(A)
- return
+ return CtrlShiftClickOn(A)
if(modifiers["shift"] && modifiers["middle"])
- ShiftMiddleClickOn(A)
- return
+ return ShiftMiddleClickOn(A)
if(modifiers["middle"])
- MiddleClickOn(A)
- return
+ return MiddleClickOn(A)
if(modifiers["shift"])
- ShiftClickOn(A)
- return
+ return ShiftClickOn(A)
if(modifiers["alt"]) // alt and alt-gr (rightalt)
- AltClickOn(A)
- return
+ return AltClickOn(A)
if(modifiers["ctrl"])
- CtrlClickOn(A)
- return
+ return CtrlClickOn(A)
- if(next_move >= world.time)
+ if(!CheckActionCooldown(immediate = TRUE))
return
face_atom(A) // change direction to face what you clicked on
@@ -50,7 +40,7 @@
*/
if(aicamera.in_camera_mode) //Cyborg picture taking
aicamera.camera_mode_off()
- aicamera.captureimage(A, usr)
+ INVOKE_ASYNC(aicamera, /obj/item/camera.proc/captureimage, A, usr)
return
var/obj/item/W = get_active_held_item()
@@ -58,13 +48,8 @@
if(!W && A.Adjacent(src) && (isobj(A) || ismob(A)))
var/atom/movable/C = A
if(C.can_buckle && C.has_buckled_mobs())
- if(C.buckled_mobs.len > 1)
- var/unbuckled = input(src, "Who do you wish to unbuckle?","Unbuckle Who?") as null|mob in C.buckled_mobs
- if(C.user_unbuckle_mob(unbuckled,src))
- return
- else
- if(C.user_unbuckle_mob(C.buckled_mobs[1],src))
- return
+ INVOKE_ASYNC(C, /atom/movable.proc/precise_user_unbuckle_mob, src)
+ return
if(!W && (get_dist(src,A) <= interaction_range))
A.attack_robot(src)
@@ -81,7 +66,9 @@
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents)
if(A == loc || (A in loc) || (A in contents))
- W.melee_attack_chain(src, A, params)
+ . = W.melee_attack_chain(src, A, params)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
+ DelayNextAction(CLICK_CD_MELEE)
return
if(!isturf(loc))
@@ -90,11 +77,12 @@
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc))
if(isturf(A) || isturf(A.loc))
if(A.Adjacent(src)) // see adjacent.dm
- W.melee_attack_chain(src, A, params)
+ . = W.melee_attack_chain(src, A, params)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
+ DelayNextAction(CLICK_CD_MELEE)
return
else
- W.afterattack(A, src, 0, params)
- return
+ return W.afterattack(A, src, 0, params)
//Middle click cycles through selected modules.
/mob/living/silicon/robot/MiddleClickOn(atom/A)
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index 4b963c730d..467c67e0c3 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -168,6 +168,8 @@
//UI position overrides for 1:1 screen layout. (default is 7:5)
#define ui_stamina "EAST-1:28,CENTER:17" // replacing internals button
#define ui_overridden_resist "EAST-3:24,SOUTH+1:7"
+#define ui_clickdelay "CENTER,SOUTH+1:-31"
+#define ui_resistdelay "EAST-3:24,SOUTH+1:4"
#define ui_combat_toggle "EAST-4:22,SOUTH:5"
#define ui_boxcraft "EAST-4:22,SOUTH+1:6"
diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm
index 0ed3a9cf26..8a66374029 100644
--- a/code/_onclick/hud/action_button.dm
+++ b/code/_onclick/hud/action_button.dm
@@ -56,9 +56,6 @@
if(id && usr.client) //try to (un)remember position
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = locked ? moved : null
return TRUE
- if(usr.next_click > world.time)
- return
- usr.next_click = world.time + 1
linked_action.Trigger()
return TRUE
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 11531a701e..6dc1433bc8 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -22,7 +22,7 @@
if(alerts[category])
thealert = alerts[category]
if(thealert.override_alerts)
- return 0
+ return thealert
if(new_master && new_master != thealert.master)
WARNING("[src] threw alert [category] with new_master [new_master] while already having that alert with master [thealert.master]")
@@ -36,7 +36,7 @@
clear_alert(category)
return .()
else //no need to update
- return 0
+ return thealert
else
thealert = new type()
thealert.override_alerts = override
@@ -272,7 +272,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
return
- L.changeNext_move(CLICK_CD_RESIST)
+ L.MarkResistTime()
if(CHECK_MOBILITY(L, MOBILITY_MOVE))
return L.resist_fire() //I just want to start a flame in your hearrrrrrtttttt.
@@ -447,8 +447,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
var/time_name
if(G.seconds_until_activation)
time_name = "until the Ark activates"
- else if(G.grace_period)
- time_name = "of grace period remaining"
else if(G.progress_in_seconds)
time_name = "until the Ark finishes summoning"
if(time_info)
@@ -495,6 +493,16 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the
desc = "Unit's power cell is running low. Recharging stations are available in robotics, the dormitory bathrooms, and the AI satellite."
icon_state = "lowcell"
+/obj/screen/alert/etherealcharge
+ name = "Low Blood Charge"
+ desc = "Your blood's electric charge is running low, find a source of charge for your blood. Use a recharging station found in robotics or the dormitory bathrooms, or eat some Ethereal-friendly food."
+ icon_state = "etherealcharge"
+
+/obj/screen/alert/ethereal_overcharge
+ name = "Blood Overcharge"
+ desc = "Your blood's electric charge is becoming dangerously high, find an outlet for your energy. Use Grab Intent on an APC to channel your energy into it."
+ icon_state = "ethereal_overcharge"
+
//Need to cover all use cases - emag, illegal upgrade module, malf AI hack, traitor cyborg
/obj/screen/alert/hacked
name = "Hacked"
@@ -600,17 +608,32 @@ so as to remain in compliance with the most up-to-date laws."
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
return
- L.changeNext_move(CLICK_CD_RESIST)
- if(CHECK_MOBILITY(L, MOBILITY_MOVE) && (L.last_special <= world.time))
- return L.resist_restraints()
+ L.MarkResistTime()
+ return L.resist_restraints()
/obj/screen/alert/restrained/buckled/Click()
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
return
- L.changeNext_move(CLICK_CD_RESIST)
- if(L.last_special <= world.time)
- return L.resist_buckle()
+ L.MarkResistTime()
+ return L.resist_buckle()
+
+/obj/screen/alert/shoes/untied
+ name = "Untied Shoes"
+ desc = "Your shoes are untied! Click the alert or your shoes to tie them."
+ icon_state = "shoealert"
+
+/obj/screen/alert/shoes/knotted
+ name = "Knotted Shoes"
+ desc = "Someone tied your shoelaces together! Click the alert or your shoes to undo the knot."
+ icon_state = "shoealert"
+
+/obj/screen/alert/shoes/Click()
+ var/mob/living/carbon/C = usr
+ if(!istype(C) || !C.can_resist() || C != mob_viewer || !C.shoes)
+ return
+ C.MarkResistTime()
+ C.shoes.handle_tying(C)
// PRIVATE = only edit, use, or override these if you're editing the system as a whole
diff --git a/code/_onclick/hud/clockwork_marauder.dm b/code/_onclick/hud/clockwork_marauder.dm
new file mode 100644
index 0000000000..09f85db574
--- /dev/null
+++ b/code/_onclick/hud/clockwork_marauder.dm
@@ -0,0 +1,45 @@
+/datum/hud/marauder
+ var/obj/screen/hosthealth
+ var/obj/screen/blockchance
+ var/obj/screen/counterchance
+
+/datum/hud/marauder/New(mob/living/simple_animal/hostile/clockwork/marauder/guardian/owner)
+ ..()
+ var/obj/screen/using
+
+ healths = new /obj/screen/healths/clock()
+ infodisplay += healths
+
+ hosthealth = new /obj/screen/healths/clock()
+ hosthealth.screen_loc = ui_internal
+ infodisplay += hosthealth
+
+ using = new /obj/screen/marauder/emerge()
+ using.screen_loc = ui_zonesel
+ static_inventory += using
+
+/datum/hud/marauder/Destroy()
+ blockchance = null
+ counterchance = null
+ hosthealth = null
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/create_mob_hud()
+ if(client && !hud_used)
+ hud_used = new /datum/hud/marauder(src, ui_style2icon(client.prefs.UI_style))
+
+/obj/screen/marauder
+ icon = 'icons/mob/clockwork_mobs.dmi'
+
+/obj/screen/marauder/emerge
+ icon_state = "clockguard_emerge"
+ name = "Emerge/Return"
+ desc = "Emerge or Return."
+
+/obj/screen/marauder/emerge/Click()
+ if(istype(usr, /mob/living/simple_animal/hostile/clockwork/marauder/guardian))
+ var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/G = usr
+ if(G.is_in_host())
+ G.try_emerge()
+ else
+ G.return_to_host()
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 9380cf98aa..04141becf2 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -140,6 +140,17 @@
sprint_buffer.hud = src
static_inventory += sprint_buffer
+ // clickdelay
+ clickdelay = new
+ clickdelay.hud = src
+ clickdelay.screen_loc = ui_clickdelay
+ static_inventory += clickdelay
+
+ // resistdelay
+ resistdelay = new
+ resistdelay.hud = src
+ resistdelay.screen_loc = ui_resistdelay
+ static_inventory += resistdelay
using = new /obj/screen/drop()
using.icon = ui_style
diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm
index d8ef1c525a..9050bcb5f0 100755
--- a/code/_onclick/hud/parallax.dm
+++ b/code/_onclick/hud/parallax.dm
@@ -128,7 +128,7 @@
deltimer(C.parallax_animate_timer)
var/datum/callback/CB = CALLBACK(src, .proc/update_parallax_motionblur, C, animatedir, new_parallax_movedir, newtransform)
if(skip_windups)
- CB.Invoke()
+ CB.InvokeAsync()
else
C.parallax_animate_timer = addtimer(CB, min(shortesttimer, PARALLAX_LOOP_TIME), TIMER_CLIENT_TIME|TIMER_STOPPABLE)
@@ -219,6 +219,7 @@
L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]"
/atom/movable/proc/update_parallax_contents()
+ set waitfor = FALSE
if(length(client_mobs_in_contents))
for(var/thing in client_mobs_in_contents)
var/mob/M = thing
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 0088dde15a..126cc18907 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -47,17 +47,7 @@
name = "swap hand"
/obj/screen/swap_hand/Click()
- // At this point in client Click() code we have passed the 1/10 sec check and little else
- // We don't even know if it's a middle click
- if(world.time <= usr.next_move)
- return 1
-
- if(usr.incapacitated())
- return 1
-
- if(ismob(usr))
- var/mob/M = usr
- M.swap_hand()
+ usr.swap_hand()
return 1
/obj/screen/craft
@@ -101,15 +91,9 @@
plane = HUD_PLANE
/obj/screen/inventory/Click(location, control, params)
- // At this point in client Click() code we have passed the 1/10 sec check and little else
- // We don't even know if it's a middle click
- if(world.time <= usr.next_move)
- return TRUE
-
- if(usr.incapacitated())
- return TRUE
- if(ismecha(usr.loc)) // stops inventory actions in a mech
- return TRUE
+ if(hud?.mymob && (hud.mymob != usr))
+ return
+ // just redirect clicks
if(hud?.mymob && slot_id)
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
@@ -190,17 +174,10 @@
/obj/screen/inventory/hand/Click(location, control, params)
- // At this point in client Click() code we have passed the 1/10 sec check and little else
- // We don't even know if it's a middle click
- var/mob/user = hud?.mymob
- if(usr != user)
- return TRUE
- if(world.time <= user.next_move)
- return TRUE
- if(user.incapacitated())
- return TRUE
- if (ismecha(user.loc)) // stops inventory actions in a mech
- return TRUE
+ if(hud?.mymob && (hud.mymob != usr))
+ return
+ var/mob/user = hud.mymob
+ // just redirect clicks
if(user.active_hand_index == held_index)
var/obj/item/I = user.get_active_held_item()
diff --git a/code/_onclick/hud/screen_objects/clickdelay.dm b/code/_onclick/hud/screen_objects/clickdelay.dm
new file mode 100644
index 0000000000..e0ad039cdf
--- /dev/null
+++ b/code/_onclick/hud/screen_objects/clickdelay.dm
@@ -0,0 +1,58 @@
+/obj/screen/action_bar
+
+/obj/screen/action_bar/Destroy()
+ STOP_PROCESSING(SShuds, src)
+ return ..()
+
+/obj/screen/action_bar/proc/mark_dirty()
+ var/mob/living/L = hud?.mymob
+ if(L?.client && update_to_mob(L))
+ START_PROCESSING(SShuds, src)
+
+/obj/screen/action_bar/process()
+ var/mob/living/L = hud?.mymob
+ if(!L?.client || !update_to_mob(L))
+ return PROCESS_KILL
+
+/obj/screen/action_bar/proc/update_to_mob(mob/living/L)
+ return FALSE
+
+/datum/hud/var/obj/screen/action_bar/clickdelay/clickdelay
+
+/obj/screen/action_bar/clickdelay
+ name = "click delay"
+ icon = 'icons/effects/progessbar.dmi'
+ icon_state = "prog_bar_100"
+ layer = 20 // under hand buttons
+
+/obj/screen/action_bar/clickdelay/Initialize()
+ . = ..()
+ var/matrix/M = new
+ M.Scale(2, 1)
+ transform = M
+
+/obj/screen/action_bar/clickdelay/update_to_mob(mob/living/L)
+ var/estimated = L.EstimatedNextActionTime()
+ var/diff = estimated - L.last_action
+ var/left = estimated - world.time
+ if(left < 0 || diff < 0)
+ icon_state = "prog_bar_100"
+ return FALSE
+ icon_state = "prog_bar_[round(clamp(((diff - left)/diff) * 100, 0, 100), 5)]"
+ return TRUE
+
+/datum/hud/var/obj/screen/action_bar/resistdelay/resistdelay
+
+/obj/screen/action_bar/resistdelay
+ name = "resist delay"
+ icon = 'icons/effects/progessbar.dmi'
+ icon_state = "prog_bar_100"
+
+/obj/screen/action_bar/resistdelay/update_to_mob(mob/living/L)
+ var/diff = L.next_resist - L.last_resist
+ var/left = L.next_resist - world.time
+ if(left < 0 || diff < 0)
+ icon_state = "prog_bar_100"
+ return FALSE
+ icon_state = "prog_bar_[round(clamp(((diff - left)/diff) * 100, 0, 100), 5)]"
+ return TRUE
diff --git a/modular_citadel/code/_onclick/hud/sprint.dm b/code/_onclick/hud/screen_objects/sprint.dm
similarity index 100%
rename from modular_citadel/code/_onclick/hud/sprint.dm
rename to code/_onclick/hud/screen_objects/sprint.dm
diff --git a/modular_citadel/code/_onclick/hud/stamina.dm b/code/_onclick/hud/screen_objects/stamina.dm
similarity index 100%
rename from modular_citadel/code/_onclick/hud/stamina.dm
rename to code/_onclick/hud/screen_objects/stamina.dm
diff --git a/code/_onclick/hud/screen_objects/storage.dm b/code/_onclick/hud/screen_objects/storage.dm
index 7e8bfe12ab..ce7bc96c96 100644
--- a/code/_onclick/hud/screen_objects/storage.dm
+++ b/code/_onclick/hud/screen_objects/storage.dm
@@ -9,12 +9,9 @@
/obj/screen/storage/Click(location, control, params)
if(!insertion_click)
return ..()
- if(world.time <= usr.next_move)
- return TRUE
- if(usr.incapacitated())
- return TRUE
- if (ismecha(usr.loc)) // stops inventory actions in a mech
- return TRUE
+ if(hud?.mymob && (hud.mymob != usr))
+ return
+ // just redirect clicks
if(master)
var/obj/item/I = usr.get_active_held_item()
if(I)
diff --git a/modular_citadel/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects/vore.dm
similarity index 100%
rename from modular_citadel/code/_onclick/hud/screen_objects.dm
rename to code/_onclick/hud/screen_objects/vore.dm
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index bef06a69e9..9e88476513 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -7,21 +7,22 @@
*and lastly
*afterattack. The return value does not matter.
*/
-/obj/item/proc/melee_attack_chain(mob/user, atom/target, params, flags, damage_multiplier = 1)
+/obj/item/proc/melee_attack_chain(mob/user, atom/target, params, attackchain_flags, damage_multiplier = 1)
if(isliving(user))
var/mob/living/L = user
- if(!CHECK_MOBILITY(L, MOBILITY_USE) && !(flags & ATTACKCHAIN_PARRY_COUNTERATTACK))
+ if(!CHECK_MOBILITY(L, MOBILITY_USE) && !(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
to_chat(L, "You are unable to swing [src] right now!")
return
- if(tool_behaviour && target.tool_act(user, src, tool_behaviour))
+ . = attackchain_flags
+ if(tool_behaviour && ((. = target.tool_act(user, src, tool_behaviour)) & STOP_ATTACK_PROC_CHAIN))
return
- if(pre_attack(target, user, params))
+ if((. |= pre_attack(target, user, params, ., damage_multiplier)) & STOP_ATTACK_PROC_CHAIN)
return
- if(target.attackby(src, user, params, flags, damage_multiplier))
+ if((. |= target.attackby(src, user, params, ., damage_multiplier)) & STOP_ATTACK_PROC_CHAIN)
return
if(QDELETED(src) || QDELETED(target))
return
- afterattack(target, user, TRUE, params)
+ . |= afterattack(target, user, TRUE, params)
/// Like melee_attack_chain but for ranged.
/obj/item/proc/ranged_attack_chain(mob/user, atom/target, params)
@@ -30,7 +31,7 @@
if(!CHECK_MOBILITY(L, MOBILITY_USE))
to_chat(L, "You are unable to raise [src] right now!")
return
- afterattack(target, user, FALSE, params)
+ return afterattack(target, user, FALSE, params)
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
/obj/item/proc/attack_self(mob/user)
@@ -38,28 +39,43 @@
return
interact(user)
-/obj/item/proc/pre_attack(atom/A, mob/living/user, params) //do stuff before attackby!
+/obj/item/proc/pre_attack(atom/A, mob/living/user, params, attackchain_flags, damage_multiplier) //do stuff before attackby!
if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_NO_ATTACK)
- return TRUE
- return FALSE //return TRUE to avoid calling attackby after this proc does stuff
+ return STOP_ATTACK_PROC_CHAIN
+ if(!(attackchain_flags & ATTACK_IGNORE_CLICKDELAY) && !CheckAttackCooldown(user, A))
+ return STOP_ATTACK_PROC_CHAIN
// No comment
/atom/proc/attackby(obj/item/W, mob/user, params)
if(SEND_SIGNAL(src, COMSIG_PARENT_ATTACKBY, W, user, params) & COMPONENT_NO_AFTERATTACK)
- return TRUE
- return FALSE
+ return STOP_ATTACK_PROC_CHAIN
/obj/attackby(obj/item/I, mob/living/user, params)
- return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_obj(src, user))
+ . = ..()
+ if(. & STOP_ATTACK_PROC_CHAIN)
+ return
+ if(obj_flags & CAN_BE_HIT)
+ . |= I.attack_obj(src, user)
/mob/living/attackby(obj/item/I, mob/living/user, params, attackchain_flags, damage_multiplier)
- if(..())
- return TRUE
- I.attack_delay_done = FALSE //Should be set TRUE in pre_attacked_by()
- . = I.attack(src, user, attackchain_flags, damage_multiplier)
- if(!I.attack_delay_done) //Otherwise, pre_attacked_by() should handle it.
- user.changeNext_move(I.click_delay)
+ . = ..()
+ if(. & STOP_ATTACK_PROC_CHAIN)
+ return
+ . |= I.attack(src, user, attackchain_flags, damage_multiplier)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING)) // SAFETY NET - unless the proc tells us we should not handle this, give them the basic melee cooldown!
+ I.ApplyAttackCooldown(user, src, attackchain_flags)
+/**
+ * Called when someone uses us to attack a mob in melee combat.
+ *
+ * This proc respects CheckAttackCooldown() default clickdelay handling.
+ *
+ * @params
+ * * mob/living/M - target
+ * * mob/living/user - attacker
+ * * attackchain_Flags - see [code/__DEFINES/_flags/return_values.dm]
+ * * damage_multiplier - what to multiply the damage by
+ */
/obj/item/proc/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
return
@@ -88,6 +104,17 @@
if(weight)
user.adjustStaminaLossBuffered(weight)
+ // CIT SCREENSHAKE
+ if(force >= 15)
+ shake_camera(user, ((force - 10) * 0.01 + 1), ((force - 10) * 0.01))
+ if(M.client)
+ switch (M.client.prefs.damagescreenshake)
+ if (1)
+ shake_camera(M, ((force - 10) * 0.015 + 1), ((force - 10) * 0.015))
+ if (2)
+ if(!CHECK_MOBILITY(M, MOBILITY_MOVE))
+ shake_camera(M, ((force - 10) * 0.015 + 1), ((force - 10) * 0.015))
+
//the equivalent of the standard version of attack() but for object targets.
/obj/item/proc/attack_obj(obj/O, mob/living/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
@@ -95,8 +122,7 @@
if(item_flags & NOBLUDGEON)
return
user.do_attack_animation(O)
- if(!O.attacked_by(src, user))
- user.changeNext_move(click_delay)
+ O.attacked_by(src, user)
var/weight = getweight(user, STAM_COST_ATTACK_OBJ_MULT)
if(weight)
user.adjustStaminaLossBuffered(weight)//CIT CHANGE - makes attacking things cause stamina loss
@@ -109,12 +135,9 @@
var/bad_trait
var/stamloss = user.getStaminaLoss()
- var/next_move_mult = 1
if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
totitemdamage *= 1 - penalty
- next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
- user.changeNext_move(I.click_delay*next_move_mult)
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
@@ -126,18 +149,18 @@
if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill]))
continue
user.mind.auto_gain_experience(skill, I.skill_gain)
-
+ if(!(attackchain_flags & NO_AUTO_CLICKDELAY_HANDLING))
+ I.ApplyAttackCooldown(user, src, attackchain_flags)
if(totitemdamage)
visible_message("[user] has hit [src] with [I]!", null, null, COMBAT_MESSAGE_RANGE)
//only witnesses close by and the victim see a hit message.
log_combat(user, src, "attacked", I)
take_damage(totitemdamage, I.damtype, "melee", 1)
- return TRUE
/mob/living/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
var/list/block_return = list()
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
- if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, null, block_return) & BLOCK_SUCCESS)
+ if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_IS_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, null, block_return) & BLOCK_SUCCESS)
return FALSE
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
send_item_attack_message(I, user, null, totitemdamage)
@@ -155,8 +178,7 @@
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
if(I.force < force_threshold || I.damtype == STAMINA)
- playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
- user.changeNext_move(I.click_delay) //pre_attacked_by not called
+ playsound(src, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
else
return ..()
@@ -167,25 +189,21 @@
var/stamloss = user.getStaminaLoss()
var/stam_mobility_mult = 1
- var/next_move_mult = 1
if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
stam_mobility_mult -= penalty
- next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
if(stam_mobility_mult > LYING_DAMAGE_PENALTY && !CHECK_MOBILITY(user, MOBILITY_STAND)) //damage penalty for fighting prone, doesn't stack with the above.
stam_mobility_mult = LYING_DAMAGE_PENALTY
. *= stam_mobility_mult
- user.changeNext_move(I.click_delay*next_move_mult)
- I.attack_delay_done = TRUE
var/bad_trait
if(!(I.item_flags & NO_COMBAT_MODE_FORCE_MODIFIER))
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
- . *= 0.5
+ . *= 0.8
else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- . *= 1.5
+ . *= 1.2
if(!user.mind || !I.used_skills)
return
@@ -197,8 +215,18 @@
var/datum/skill/S = GLOB.skill_datums[skill]
user.mind.auto_gain_experience(skill, I.skill_gain*S.item_skill_gain_multi)
-// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
-// Click parameters is the params string from byond Click() code, see that documentation.
+/**
+ * Called after attacking something if the melee attack chain isn't interrupted before.
+ * Also called when clicking on something with an item without being in melee range
+ *
+ * WARNING: This does not automatically check clickdelay if not in a melee attack! Be sure to account for this!
+ *
+ * @params
+ * * target - The thing we clicked
+ * * user - mob of person clicking
+ * * proximity_flag - are we in melee range/doing it in a melee attack
+ * * click_parameters - mouse control parameters, check BYOND ref.
+ */
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
SEND_SIGNAL(user, COMSIG_MOB_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
@@ -210,25 +238,24 @@
else
return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
-/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, current_force)
+/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, obj/item/bodypart/hit_bodypart)
var/message_verb = "attacked"
- if(I.attack_verb && I.attack_verb.len)
+ if(length(I.attack_verb))
message_verb = "[pick(I.attack_verb)]"
- if(current_force < I.force * FEEBLE_ATTACK_MSG_THRESHOLD)
- message_verb = "[pick("feebly", "limply", "saplessly")] [message_verb]"
else if(!I.force)
return
var/message_hit_area = ""
if(hit_area)
message_hit_area = " in the [hit_area]"
- var/attack_message = "[src] has been [message_verb][message_hit_area] with [I]."
+ var/attack_message = "[src] is [message_verb][message_hit_area] with [I]!"
+ var/attack_message_local = "You're [message_verb][message_hit_area] with [I]!"
if(user in viewers(src, null))
- attack_message = "[user] has [message_verb] [src][message_hit_area] with [I]!"
+ attack_message = "[user] [message_verb] [src][message_hit_area] with [I]!"
+ attack_message_local = "[user] [message_verb] you[message_hit_area] with [I]!"
+ if(user == src)
+ attack_message_local = "You [message_verb] yourself[message_hit_area] with [I]"
visible_message("[attack_message]",\
- "[attack_message]", null, COMBAT_MESSAGE_RANGE)
- if(hit_area == BODY_ZONE_HEAD)
- if(prob(2))
- playsound(src, 'sound/weapons/dink.ogg', 30, 1)
+ "[attack_message_local]", null, COMBAT_MESSAGE_RANGE)
return 1
/// How much stamina this takes to swing this is not for realism purposes hecc off.
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index ed7384697c..8a1e745308 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -37,7 +37,7 @@
CtrlClickOn(A)
return
- if(world.time <= next_move)
+ if(!CheckActionCooldown())
return
// You are responsible for checking config.ghost_interaction when you override this function
// Not all of them require checking, see below
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index ae10358b66..975c6e62d4 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -4,39 +4,57 @@
Otherwise pretty standard.
*/
-/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
+
+/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, intent = a_intent, attackchain_flags = NONE)
if(!has_active_hand()) //can't attack without a hand.
to_chat(src, "You look at your arm and sigh.")
return
+ var/obj/item/bodypart/check_arm = get_active_hand()
+ if(check_arm && check_arm.is_disabled() == BODYPART_DISABLED_WOUND)
+ to_chat(src, "The damage in your [check_arm.name] is preventing you from using it! Get it fixed, or at least splinted!")
+ return
+
+ . = attackchain_flags
// Special glove functions:
// If the gloves do anything, have them return 1 to stop
// normal attack_hand() here.
var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines
- if(proximity && istype(G) && G.Touch(A,1))
- return
-
- var/override = 0
+ if(proximity && istype(G))
+ . |= G.Touch(A, TRUE)
+ if(. & INTERRUPT_UNARMED_ATTACK)
+ return
for(var/datum/mutation/human/HM in dna.mutations)
- override += HM.on_attack_hand(A, proximity, intent, flags)
+ . |= HM.on_attack_hand(A, proximity, intent, .)
- if(override)
+ if(. & INTERRUPT_UNARMED_ATTACK)
return
SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A)
- A.attack_hand(src, intent, flags)
+ return . | A.attack_hand(src, intent, .)
-//Return TRUE to cancel other attack hand effects that respect it.
-/atom/proc/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = FALSE
+/atom/proc/attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
+ SHOULD_NOT_SLEEP(TRUE)
if(!(interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND))
add_fingerprint(user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, user) & COMPONENT_NO_ATTACK_HAND)
- . = TRUE
+ return
+ . = attackchain_flags
+ if(attack_hand_speed && !(. & ATTACK_IGNORE_CLICKDELAY))
+ if(!user.CheckActionCooldown(attack_hand_speed))
+ return
if(interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND)
. = _try_interact(user)
+ INVOKE_ASYNC(src, .proc/on_attack_hand, user, act_intent, .)
+ if(!(. & ATTACK_IGNORE_ACTION))
+ if(attack_hand_unwieldlyness)
+ user.DelayNextAction(attack_hand_unwieldlyness, considered_action = attack_hand_is_action)
+ else if(attack_hand_is_action)
+ user.DelayNextAction()
+
+/atom/proc/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
//Return a non FALSE value to cancel whatever called this from propagating, if it respects it.
/atom/proc/_try_interact(mob/user)
@@ -44,7 +62,6 @@
return interact(user)
if(can_interact(user))
return interact(user)
- return FALSE
/atom/proc/can_interact(mob/user)
if(!user.can_interact_with(src))
@@ -74,8 +91,7 @@
else
add_fingerprint(user)
if(interaction_flags_atom & INTERACT_ATOM_UI_INTERACT)
- return ui_interact(user)
- return FALSE
+ ui_interact(user)
/*
/mob/living/carbon/human/RestrainedClickOn(var/atom/A) ---carbons will handle this
@@ -89,13 +105,19 @@
. = ..()
if(gloves)
var/obj/item/clothing/gloves/G = gloves
- if(istype(G) && G.Touch(A,0)) // for magic gloves
+ . |= G.Touch(A, FALSE)
+ if(. & INTERRUPT_UNARMED_ATTACK)
+ return
+ if(istype(glasses))
+ . |= glasses.ranged_attack(src, A, mouseparams)
+ if(. & INTERRUPT_UNARMED_ATTACK)
return
- if (istype(glasses) && glasses.ranged_attack(src,A,mouseparams))
- return
for(var/datum/mutation/human/HM in dna.mutations)
- HM.on_ranged_attack(A, mouseparams)
+ . |= HM.on_ranged_attack(A, mouseparams)
+
+ if(. & INTERRUPT_UNARMED_ATTACK)
+ return
if(isturf(A) && get_dist(src,A) <= 1)
src.Move_Pulled(A)
@@ -117,7 +139,9 @@
Monkeys
*/
/mob/living/carbon/monkey/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
- A.attack_paw(src, intent, flags)
+ if(!CheckActionCooldown(CLICK_CD_MELEE))
+ return
+ return !isnull(A.attack_paw(src, intent, flags))
/atom/proc/attack_paw(mob/user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_PAW, user) & COMPONENT_NO_ATTACK_HAND)
@@ -138,6 +162,8 @@
return
if(is_muzzled())
return
+ if(!CheckActionCooldown(CLICK_CD_MELEE))
+ return
var/mob/living/carbon/ML = A
if(istype(ML))
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
@@ -157,6 +183,7 @@
ML.ForceContractDisease(D)
else
ML.visible_message("[src] has attempted to bite [ML]!")
+ DelayNextAction()
/*
Aliens
@@ -237,7 +264,7 @@
/mob/living/simple_animal/hostile/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
target = A
if(dextrous && !ismob(A))
- ..()
+ return ..()
else
AttackingTarget()
diff --git a/modular_citadel/code/_onclick/click.dm b/code/_onclick/right_click.dm
similarity index 60%
rename from modular_citadel/code/_onclick/click.dm
rename to code/_onclick/right_click.dm
index 004cc2fe80..4b2480eb8c 100644
--- a/modular_citadel/code/_onclick/click.dm
+++ b/code/_onclick/right_click.dm
@@ -5,7 +5,7 @@
face_atom(A)
- if(next_move > world.time) // in the year 2000...
+ if(!CheckActionCooldown())
return
if(!modifiers["catcher"] && A.IsObscured())
@@ -16,9 +16,8 @@
return M.click_action(A,src,params)
if(restrained())
- changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
- RestrainedClickOn(A)
- return
+ DelayNextAction(CLICK_CD_HANDCUFFED)
+ return RestrainedClickOn(A)
if(in_throw_mode)
throw_item(A)//todo: make it plausible to lightly toss items via right-click
@@ -36,13 +35,14 @@
//User itself, current loc, and user inventory
if(A in DirectAccess())
if(W)
- W.rightclick_melee_attack_chain(src, A, params)
+ return W.rightclick_melee_attack_chain(src, A, params)
else
- if(ismob(A))
- changeNext_move(CLICK_CD_MELEE)
- if(!AltUnarmedAttack(A))
- UnarmedAttack(A)
- return
+ if(!AltUnarmedAttack(A, TRUE))
+ . = UnarmedAttack(A, TRUE, a_intent)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
+ DelayNextAction(CLICK_CD_MELEE)
+ return
+ return
//Can't reach anything else in lockers or other weirdness
if(!loc.AllowClick())
@@ -51,23 +51,25 @@
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
- W.rightclick_melee_attack_chain(src, A, params)
+ return W.rightclick_melee_attack_chain(src, A, params)
else
- if(ismob(A))
- changeNext_move(CLICK_CD_MELEE)
- if(!AltUnarmedAttack(A,1))
- UnarmedAttack(A,1)
+ if(!AltUnarmedAttack(A, TRUE))
+ . = UnarmedAttack(A, TRUE, a_intent)
+ if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
+ DelayNextAction(CLICK_CD_MELEE)
+ return
+ return
else
if(W)
if(!W.altafterattack(A, src, FALSE, params))
- W.afterattack(A, src, FALSE, params)
+ return W.afterattack(A, src, FALSE, params)
else
- if(!AltRangedAttack(A,params))
- RangedAttack(A,params)
+ if(!AltRangedAttack(A, params))
+ return RangedAttack(A, params)
/mob/proc/AltUnarmedAttack(atom/A, proximity_flag)
if(ismob(A))
- changeNext_move(CLICK_CD_MELEE)
+ DelayNextAction(CLICK_CD_MELEE)
return FALSE
/mob/proc/AltRangedAttack(atom/A, params)
diff --git a/modular_citadel/code/_onclick/item_attack.dm b/code/_onclick/right_item_attack.dm
similarity index 82%
rename from modular_citadel/code/_onclick/item_attack.dm
rename to code/_onclick/right_item_attack.dm
index bba3b14e2e..4ac9c96c8e 100644
--- a/modular_citadel/code/_onclick/item_attack.dm
+++ b/code/_onclick/right_item_attack.dm
@@ -1,10 +1,9 @@
/obj/item/proc/rightclick_melee_attack_chain(mob/user, atom/target, params)
if(!alt_pre_attack(target, user, params)) //Hey, does this item have special behavior that should override all normal right-click functionality?
if(!target.altattackby(src, user, params)) //Does the target do anything special when we right-click on it?
- melee_attack_chain(user, target, params) //Ugh. Lame! I'm filing a legal complaint about the discrimination against the right mouse button!
+ . = melee_attack_chain(user, target, params) //Ugh. Lame! I'm filing a legal complaint about the discrimination against the right mouse button!
else
- altafterattack(target, user, TRUE, params)
- return
+ . = altafterattack(target, user, TRUE, params)
/obj/item/proc/alt_pre_attack(atom/A, mob/living/user, params)
return FALSE //return something other than false if you wanna override attacking completely
diff --git a/modular_citadel/code/_onclick/other_mobs.dm b/code/_onclick/right_other_mobs.dm
similarity index 93%
rename from modular_citadel/code/_onclick/other_mobs.dm
rename to code/_onclick/right_other_mobs.dm
index ec740f023b..2dc9fddeef 100644
--- a/modular_citadel/code/_onclick/other_mobs.dm
+++ b/code/_onclick/right_other_mobs.dm
@@ -3,15 +3,14 @@
to_chat(src, "You look at the state of the universe and sigh.") //lets face it, people rarely ever see this message in its intended condition.
return TRUE
- if(!A.alt_attack_hand(src))
- A.attack_hand(src)
- return TRUE
- return TRUE
+ return A.alt_attack_hand(src)
/mob/living/carbon/human/AltRangedAttack(atom/A, params)
if(isturf(A) || incapacitated()) // pretty annoying to wave your fist at floors and walls. And useless.
- return TRUE
- changeNext_move(CLICK_CD_RANGE)
+ return
+ if(!CheckActionCooldown(CLICK_CD_RANGE))
+ return
+ DelayNextAction()
var/list/target_viewers = fov_viewers(11, A) //doesn't check for blindness.
if(!(src in target_viewers)) //click catcher issuing calls for out of view objects.
return TRUE
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
index f95ebf82b5..f8a14b8c30 100644
--- a/code/_onclick/telekinesis.dm
+++ b/code/_onclick/telekinesis.dm
@@ -123,7 +123,8 @@
. = ..()
if(!target || !user)
return
-
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
if(!focus)
focus_object(target)
return
@@ -145,7 +146,7 @@
else
apply_focus_overlay()
focus.throw_at(target, 10, 1,user)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(considered_action = TRUE, flush = TRUE)
update_icon()
/proc/tkMaxRangeCheck(mob/user, atom/target)
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 1be413f065..2d5e69f149 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -470,3 +470,5 @@
/datum/config_entry/flag/minimaps_enabled
config_entry_value = TRUE
+
+/datum/config_entry/string/centcom_ban_db // URL for the CentCom Galactic Ban DB API
diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm
index bbeb0683f0..ba2794d00f 100644
--- a/code/controllers/subsystem/chat.dm
+++ b/code/controllers/subsystem/chat.dm
@@ -31,19 +31,13 @@ SUBSYSTEM_DEF(chat)
//Some macros remain in the string even after parsing and fuck up the eventual output
var/original_message = message
- message = replacetext(message, "\improper", "")
- message = replacetext(message, "\proper", "")
- if(handle_whitespace)
- message = replacetext(message, "\n", " ")
- message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
- if (trailing_newline)
- message += " "
//url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
//Do the double-encoding here to save nanoseconds
- var/twiceEncoded = url_encode(url_encode(message))
+ var/twiceEncoded
if(islist(target))
+ var/sanitized_message = FALSE
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
@@ -55,6 +49,17 @@ SUBSYSTEM_DEF(chat)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
continue
+
+ if(!sanitized_message)
+ message = replacetext(message, "\improper", "")
+ message = replacetext(message, "\proper", "")
+ if(handle_whitespace)
+ message = replacetext(message, "\n", " ")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
+ if (trailing_newline)
+ message += " "
+ twiceEncoded = url_encode(url_encode(message))
+ sanitized_message = TRUE
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
@@ -74,6 +79,15 @@ SUBSYSTEM_DEF(chat)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
return
+ message = replacetext(message, "\improper", "")
+ message = replacetext(message, "\proper", "")
+ if(handle_whitespace)
+ message = replacetext(message, "\n", " ")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
+ if (trailing_newline)
+ message += " "
+ twiceEncoded = url_encode(url_encode(message))
+
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
return
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 4b2cf24f1e..4f59992ace 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -674,7 +674,7 @@ SUBSYSTEM_DEF(job)
return
for(var/i in the_mob.client.prefs.chosen_gear)
var/datum/gear/G = i
- G = GLOB.loadout_items[slot_to_string(initial(G.category))][initial(G.name)]
+ G = GLOB.loadout_items[initial(G.category)][initial(G.subcategory)][initial(G.name)]
if(!G)
continue
var/permitted = TRUE
@@ -682,14 +682,14 @@ SUBSYSTEM_DEF(job)
permitted = FALSE
if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey))
permitted = FALSE
- if(!equipbackpackstuff && G.category == SLOT_IN_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
+ if(!equipbackpackstuff && G.slot == SLOT_IN_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
permitted = FALSE
- if(equipbackpackstuff && G.category != SLOT_IN_BACKPACK)//ditto
+ if(equipbackpackstuff && G.slot != SLOT_IN_BACKPACK)//ditto
permitted = FALSE
if(!permitted)
continue
var/obj/item/I = new G.path
- if(!M.equip_to_slot_if_possible(I, G.category, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
+ if(!M.equip_to_slot_if_possible(I, G.slot, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
if(iscarbon(M))
var/mob/living/carbon/C = M
var/obj/item/storage/backpack/B = C.back
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index ac2afa7cae..97addfa131 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -469,11 +469,10 @@ GLOBAL_LIST_EMPTY(the_station_areas)
else
return
- possible_options = "Custom"
var/away_name
var/datum/space_level/away_level
- var/answer = input("What kind ? ","Away/VR") as null|anything in possible_options
+ var/answer = input("What kind ? ","Away/VR") as null|anything in list(possible_options + "Custom")
switch(answer)
if(null)
return
diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm
index cd577e4ac6..5b60747725 100644
--- a/code/controllers/subsystem/persistence.dm
+++ b/code/controllers/subsystem/persistence.dm
@@ -268,6 +268,7 @@ SUBSYSTEM_DEF(persistence)
SaveRandomizedRecipes()
SavePanicBunker()
SavePaintings()
+ SaveScars()
/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
var/bunker_path = file("data/bunker_passthrough.json")
@@ -547,3 +548,24 @@ SUBSYSTEM_DEF(persistence)
var/json_file = file("data/paintings.json")
fdel(json_file)
WRITE_FILE(json_file, json_encode(paintings))
+
+/datum/controller/subsystem/persistence/proc/SaveScars()
+ for(var/i in GLOB.joined_player_list)
+ var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i)
+ if(!istype(ending_human) || !ending_human.mind || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.persistent_scars)
+ continue
+
+ var/mob/living/carbon/human/original_human = ending_human.mind.original_character
+ if(!original_human || original_human.stat == DEAD || !original_human.all_scars || !(original_human == ending_human))
+ if(ending_human.client) // i was told if i don't check this every step of the way byond might decide a client ceases to exist mid proc so here we go
+ ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ""
+ else
+ for(var/k in ending_human.all_wounds)
+ var/datum/wound/iter_wound = k
+ iter_wound.remove_wound() // so we can get the scars for open wounds
+ if(!ending_human.client)
+ return
+ ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ending_human.format_scars()
+ if(!ending_human.client)
+ return
+ ending_human.client.prefs.save_character()
diff --git a/code/controllers/subsystem/processing/circuit.dm b/code/controllers/subsystem/processing/circuit.dm
index 880e7a16a8..ac720a7fb4 100644
--- a/code/controllers/subsystem/processing/circuit.dm
+++ b/code/controllers/subsystem/processing/circuit.dm
@@ -50,20 +50,17 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
/obj/item/electronic_assembly/simple,
/obj/item/electronic_assembly/hook,
/obj/item/electronic_assembly/pda,
- /obj/item/electronic_assembly/dildo,
/obj/item/electronic_assembly/small/default,
/obj/item/electronic_assembly/small/cylinder,
/obj/item/electronic_assembly/small/scanner,
/obj/item/electronic_assembly/small/hook,
/obj/item/electronic_assembly/small/box,
- /obj/item/electronic_assembly/small/dildo,
/obj/item/electronic_assembly/medium/default,
/obj/item/electronic_assembly/medium/box,
/obj/item/electronic_assembly/medium/clam,
/obj/item/electronic_assembly/medium/medical,
/obj/item/electronic_assembly/medium/gun,
/obj/item/electronic_assembly/medium/radio,
- /obj/item/electronic_assembly/medium/dildo,
/obj/item/electronic_assembly/large/default,
/obj/item/electronic_assembly/large/scope,
/obj/item/electronic_assembly/large/terminal,
diff --git a/code/controllers/subsystem/processing/huds.dm b/code/controllers/subsystem/processing/huds.dm
new file mode 100644
index 0000000000..aea23d2400
--- /dev/null
+++ b/code/controllers/subsystem/processing/huds.dm
@@ -0,0 +1,6 @@
+// Smooth HUD updates, but low priority
+PROCESSING_SUBSYSTEM_DEF(huds)
+ name = "HUD updates"
+ wait = 0.5
+ priority = FIRE_PRIORITY_HUDS
+ stat_tag = "HUDS"
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 9bda1cd233..c802448536 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -775,12 +775,14 @@ SUBSYSTEM_DEF(shuttle)
preview_shuttle = null
-/datum/controller/subsystem/shuttle/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "ShuttleManipulator", name, 800, 600, master_ui, state)
- ui.open()
+/datum/controller/subsystem/shuttle/ui_state(mob/user)
+ return GLOB.admin_state
+/datum/controller/subsystem/shuttle/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ShuttleManipulator")
+ ui.open()
/datum/controller/subsystem/shuttle/ui_data(mob/user)
var/list/data = list()
diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm
index 58bc28fa2f..a5526d2c03 100644
--- a/code/controllers/subsystem/tgui.dm
+++ b/code/controllers/subsystem/tgui.dm
@@ -1,3 +1,12 @@
+/**
+ * tgui subsystem
+ *
+ * Contains all tgui state and subsystem code.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
+ */
+
SUBSYSTEM_DEF(tgui)
name = "tgui"
wait = 9
@@ -5,33 +14,338 @@ SUBSYSTEM_DEF(tgui)
priority = FIRE_PRIORITY_TGUI
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
- var/list/currentrun = list()
- var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key.
- var/list/processing_uis = list() // A list of processing UIs, ungrouped.
- var/basehtml // The HTML base used for all UIs.
+ /// A list of UIs scheduled to process
+ var/list/current_run = list()
+ /// A list of open UIs
+ var/list/open_uis = list()
+ /// A list of open UIs, grouped by src_object.
+ var/list/open_uis_by_src = list()
+ /// The HTML base used for all UIs.
+ var/basehtml
/datum/controller/subsystem/tgui/PreInit()
- basehtml = file2text('tgui/packages/tgui/public/tgui.html')
+ basehtml = file2text('tgui/packages/tgui/public/tgui.html')
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()
/datum/controller/subsystem/tgui/stat_entry()
- ..("P:[processing_uis.len]")
+ ..("P:[open_uis.len]")
/datum/controller/subsystem/tgui/fire(resumed = 0)
- if (!resumed)
- src.currentrun = processing_uis.Copy()
- //cache for sanic speed (lists are references anyways)
- var/list/currentrun = src.currentrun
-
- while(currentrun.len)
- var/datum/tgui/ui = currentrun[currentrun.len]
- currentrun.len--
+ if(!resumed)
+ src.current_run = open_uis.Copy()
+ // Cache for sanic speed (lists are references anyways)
+ var/list/current_run = src.current_run
+ while(current_run.len)
+ var/datum/tgui/ui = current_run[current_run.len]
+ current_run.len--
+ // TODO: Move user/src_object check to process()
if(ui && ui.user && ui.src_object)
ui.process()
else
- processing_uis.Remove(ui)
- if (MC_TICK_CHECK)
+ open_uis.Remove(ui)
+ if(MC_TICK_CHECK)
return
+/**
+ * public
+ *
+ * Requests a usable tgui window from the pool.
+ * Returns null if pool was exhausted.
+ *
+ * required user mob
+ * return datum/tgui
+ */
+/datum/controller/subsystem/tgui/proc/request_pooled_window(mob/user)
+ if(!user.client)
+ return null
+ var/list/windows = user.client.tgui_windows
+ var/window_id
+ var/datum/tgui_window/window
+ var/window_found = FALSE
+ // Find a usable window
+ for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
+ window_id = TGUI_WINDOW_ID(i)
+ window = windows[window_id]
+ // As we are looping, create missing window datums
+ if(!window)
+ window = new(user.client, window_id, pooled = TRUE)
+ // Skip windows with acquired locks
+ if(window.locked)
+ continue
+ if(window.status == TGUI_WINDOW_READY)
+ return window
+ if(window.status == TGUI_WINDOW_CLOSED)
+ window.status = TGUI_WINDOW_LOADING
+ window_found = TRUE
+ break
+ if(!window_found)
+ log_tgui(user, "Error: Pool exhausted")
+ return null
+ return window
+
+/**
+ * public
+ *
+ * Force closes all tgui windows.
+ *
+ * required user mob
+ */
+/datum/controller/subsystem/tgui/proc/force_close_all_windows(mob/user)
+ log_tgui(user, "force_close_all_windows")
+ if(user.client)
+ user.client.tgui_windows = list()
+ for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
+ var/window_id = TGUI_WINDOW_ID(i)
+ user << browse(null, "window=[window_id]")
+
+/**
+ * public
+ *
+ * Force closes the tgui window by window_id.
+ *
+ * required user mob
+ * required window_id string
+ */
+/datum/controller/subsystem/tgui/proc/force_close_window(mob/user, window_id)
+ log_tgui(user, "force_close_window")
+ // Close all tgui datums based on window_id.
+ for(var/datum/tgui/ui in user.tgui_open_uis)
+ if(ui.window && ui.window.id == window_id)
+ ui.close(can_be_suspended = FALSE)
+ // Unset machine just to be sure.
+ user.unset_machine()
+ // Close window directly just to be sure.
+ user << browse(null, "window=[window_id]")
+
+/**
+ * public
+ *
+ * Try to find an instance of a UI, and push an update to it.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * required src_object datum The object/datum which owns the UI.
+ * optional ui datum/tgui The UI to be updated, if it exists.
+ * optional force_open bool If the UI should be re-opened instead of updated.
+ *
+ * return datum/tgui The found UI.
+ */
+/datum/controller/subsystem/tgui/proc/try_update_ui(
+ mob/user,
+ datum/src_object,
+ datum/tgui/ui)
+ // Look up a UI if it wasn't passed
+ if(isnull(ui))
+ ui = get_open_ui(user, src_object)
+ // Couldn't find a UI.
+ if(isnull(ui))
+ return null
+ ui.process_status()
+ // UI ended up with the closed status
+ // or is actively trying to close itself.
+ // FIXME: Doesn't actually fix the paper bug.
+ if(ui.status <= UI_CLOSE)
+ ui.close()
+ return null
+ ui.send_update()
+ return ui
+
+/**
+ * public
+ *
+ * Get a open UI given a user and src_object.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * required src_object datum The object/datum which owns the UI.
+ *
+ * return datum/tgui The found UI.
+ */
+/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object)
+ var/key = "[REF(src_object)]"
+ // No UIs opened for this src_object
+ if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
+ return null
+ for(var/datum/tgui/ui in open_uis_by_src[key])
+ // Make sure we have the right user
+ if(ui.user == user)
+ return ui
+ return null
+
+/**
+ * public
+ *
+ * Update all UIs attached to src_object.
+ *
+ * required src_object datum The object/datum which owns the UIs.
+ *
+ * return int The number of UIs updated.
+ */
+/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
+ var/count = 0
+ var/key = "[REF(src_object)]"
+ // No UIs opened for this src_object
+ if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
+ return count
+ for(var/datum/tgui/ui in open_uis_by_src[key])
+ // Check if UI is valid.
+ if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
+ ui.process(force = 1)
+ count++
+ return count
+
+/**
+ * public
+ *
+ * Close all UIs attached to src_object.
+ *
+ * required src_object datum The object/datum which owns the UIs.
+ *
+ * return int The number of UIs closed.
+ */
+/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
+ var/count = 0
+ var/key = "[REF(src_object)]"
+ // No UIs opened for this src_object
+ if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
+ return count
+ for(var/datum/tgui/ui in open_uis_by_src[key])
+ // Check if UI is valid.
+ if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
+ ui.close()
+ count++
+ return count
+
+/**
+ * public
+ *
+ * Close all UIs regardless of their attachment to src_object.
+ *
+ * return int The number of UIs closed.
+ */
+/datum/controller/subsystem/tgui/proc/close_all_uis()
+ var/count = 0
+ for(var/key in open_uis_by_src)
+ for(var/datum/tgui/ui in open_uis_by_src[key])
+ // Check if UI is valid.
+ if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
+ ui.close()
+ count++
+ return count
+
+/**
+ * public
+ *
+ * Update all UIs belonging to a user.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * optional src_object datum If provided, only update UIs belonging this src_object.
+ *
+ * return int The number of UIs updated.
+ */
+/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object)
+ var/count = 0
+ if(length(user?.tgui_open_uis) == 0)
+ return count
+ for(var/datum/tgui/ui in user.tgui_open_uis)
+ if(isnull(src_object) || ui.src_object == src_object)
+ ui.process(force = 1)
+ count++
+ return count
+
+/**
+ * public
+ *
+ * Close all UIs belonging to a user.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * optional src_object datum If provided, only close UIs belonging this src_object.
+ *
+ * return int The number of UIs closed.
+ */
+/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object)
+ var/count = 0
+ if(length(user?.tgui_open_uis) == 0)
+ return count
+ for(var/datum/tgui/ui in user.tgui_open_uis)
+ if(isnull(src_object) || ui.src_object == src_object)
+ ui.close()
+ count++
+ return count
+
+/**
+ * private
+ *
+ * Add a UI to the list of open UIs.
+ *
+ * required ui datum/tgui The UI to be added.
+ */
+/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
+ var/key = "[REF(ui.src_object)]"
+ if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
+ open_uis_by_src[key] = list()
+ ui.user.tgui_open_uis |= ui
+ var/list/uis = open_uis_by_src[key]
+ uis |= ui
+ open_uis |= ui
+
+/**
+ * private
+ *
+ * Remove a UI from the list of open UIs.
+ *
+ * required ui datum/tgui The UI to be removed.
+ *
+ * return bool If the UI was removed or not.
+ */
+/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
+ var/key = "[REF(ui.src_object)]"
+ if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
+ return FALSE
+ // Remove it from the list of processing UIs.
+ open_uis.Remove(ui)
+ // If the user exists, remove it from them too.
+ if(ui.user)
+ ui.user.tgui_open_uis.Remove(ui)
+ var/list/uis = open_uis_by_src[key]
+ uis.Remove(ui)
+ if(length(uis) == 0)
+ open_uis_by_src.Remove(key)
+ return TRUE
+
+/**
+ * private
+ *
+ * Handle client logout, by closing all their UIs.
+ *
+ * required user mob The mob which logged out.
+ *
+ * return int The number of UIs closed.
+ */
+/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
+ close_user_uis(user)
+
+/**
+ * private
+ *
+ * Handle clients switching mobs, by transferring their UIs.
+ *
+ * required user source The client's original mob.
+ * required user target The client's new mob.
+ *
+ * return bool If the UIs were transferred.
+ */
+/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
+ // The old mob had no open UIs.
+ if(length(source?.tgui_open_uis) == 0)
+ return FALSE
+ if(isnull(target.tgui_open_uis) || !istype(target.tgui_open_uis, /list))
+ target.tgui_open_uis = list()
+ // Transfer all the UIs.
+ for(var/datum/tgui/ui in source.tgui_open_uis)
+ // Inform the UIs of their new owner.
+ ui.user = target
+ target.tgui_open_uis.Add(ui)
+ // Clear the old list.
+ source.tgui_open_uis.Cut()
+ return TRUE
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 765f0c8382..0bc4e6665a 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -711,7 +711,8 @@ SUBSYSTEM_DEF(ticker)
'sound/roundend/yeehaw.ogg',
'sound/roundend/disappointed.ogg',
'sound/roundend/gondolabridge.ogg',
- 'sound/roundend/haveabeautifultime.ogg'\
+ 'sound/roundend/haveabeautifultime.ogg',
+ 'sound/roundend/CitadelStationHasSeenBetterDays.ogg'\
)
SEND_SOUND(world, sound(round_end_sound))
diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm
index 9c6bb2ebfd..15115b62c0 100644
--- a/code/datums/ai_laws.dm
+++ b/code/datums/ai_laws.dm
@@ -431,25 +431,31 @@
if(!owner)
owner = M
-/datum/ai_laws/proc/get_law_list(include_zeroth = 0, show_numbers = 1)
+/**
+ * Generates a list of all laws on this datum, including rendered HTML tags if required
+ *
+ * Arguments:
+ * * include_zeroth - Operator that controls if law 0 or law 666 is returned in the set
+ * * show_numbers - Operator that controls if law numbers are prepended to the returned laws
+ * * render_html - Operator controlling if HTML tags are rendered on the returned laws
+ */
+/datum/ai_laws/proc/get_law_list(include_zeroth = FALSE, show_numbers = TRUE, render_html = TRUE)
var/list/data = list()
- if (include_zeroth && devillaws && devillaws.len)
- for(var/i in devillaws)
- data += "[show_numbers ? "666:" : ""] [i]"
+ if (include_zeroth && devillaws)
+ for(var/law in devillaws)
+ data += "[show_numbers ? "666:" : ""] [render_html ? "[law]" : law]"
if (include_zeroth && zeroth)
- data += "[show_numbers ? "0:" : ""] [zeroth]"
+ data += "[show_numbers ? "0:" : ""] [render_html ? "[zeroth]" : zeroth]"
for(var/law in hacked)
if (length(law) > 0)
- var/num = ionnum()
- data += "[show_numbers ? "[num]:" : ""] [law]"
+ data += "[show_numbers ? "[ionnum()]:" : ""] [render_html ? "[law]" : law]"
for(var/law in ion)
if (length(law) > 0)
- var/num = ionnum()
- data += "[show_numbers ? "[num]:" : ""] [law]"
+ data += "[show_numbers ? "[ionnum()]:" : ""] [render_html ? "[law]" : law]"
var/number = 1
for(var/law in inherent)
@@ -459,6 +465,7 @@
for(var/law in supplied)
if (length(law) > 0)
- data += "[show_numbers ? "[number]:" : ""] [law]"
+ data += "[show_numbers ? "[number]:" : ""] [render_html ? "[law]" : law]"
number++
return data
+
diff --git a/code/datums/armor.dm b/code/datums/armor.dm
index 85915395f8..88170541c6 100644
--- a/code/datums/armor.dm
+++ b/code/datums/armor.dm
@@ -1,9 +1,9 @@
-#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]"
+#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]-[wound]"
-/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
+/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0)
. = locate(ARMORID)
if (!.)
- . = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
+ . = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, wound)
/datum/armor
datum_flags = DF_USE_TAG
@@ -17,8 +17,9 @@
var/fire
var/acid
var/magic
+ var/wound
-/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
+/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0)
src.melee = melee
src.bullet = bullet
src.laser = laser
@@ -29,15 +30,16 @@
src.fire = fire
src.acid = acid
src.magic = magic
+ src.wound = wound
tag = ARMORID
-/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
- return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic)
+/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0)
+ return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic, src.wound+wound)
/datum/armor/proc/modifyAllRatings(modifier = 0)
- return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier)
+ return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier, wound+modifier)
-/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
+/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, wound)
return getArmor((isnull(melee) ? src.melee : melee),\
(isnull(bullet) ? src.bullet : bullet),\
(isnull(laser) ? src.laser : laser),\
@@ -47,19 +49,20 @@
(isnull(rad) ? src.rad : rad),\
(isnull(fire) ? src.fire : fire),\
(isnull(acid) ? src.acid : acid),\
- (isnull(magic) ? src.magic : magic))
+ (isnull(magic) ? src.magic : magic),\
+ (isnull(wound) ? src.wound : wound))
/datum/armor/proc/getRating(rating)
return vars[rating]
/datum/armor/proc/getList()
- return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid, "magic" = magic)
+ return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid, "magic" = magic, "wound" = wound)
/datum/armor/proc/attachArmor(datum/armor/AA)
- return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic)
+ return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic, wound+AA.wound)
/datum/armor/proc/detachArmor(datum/armor/AA)
- return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic)
+ return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic, wound-AA.wound)
/datum/armor/vv_edit_var(var_name, var_value)
if (var_name == NAMEOF(src, tag))
diff --git a/code/datums/beepsky_fashion.dm b/code/datums/beepsky_fashion.dm
new file mode 100644
index 0000000000..1156822c93
--- /dev/null
+++ b/code/datums/beepsky_fashion.dm
@@ -0,0 +1,221 @@
+//similar to dog_fashion, but for beepsky, who has far more refined fashion tastes
+/datum/beepsky_fashion
+ var/name //not setting the name and desc makes them go to the default
+ var/desc
+
+ var/icon_file = 'icons/mob/secbot_accessories.dmi' //we sell secbots and secbot accessories
+ var/obj_icon_state
+ var/obj_alpha
+ var/obj_color
+
+ var/list/stun_sounds //sound that replaces the stun attack when set
+ var/ignore_sound = FALSE //whether to ignore sounds entirely or not
+
+ //emotes (don't set them if you want the default value)
+ var/death_emote //what is said when beepsky dies
+ var/capture_one //what is said when cuffing someone
+ var/capture_two //what is said when cuffing someone, directly to the person being cuffed
+ var/infraction //the level of threat detected
+ var/taunt // beepsky pointing at a criminal
+ var/attack_one //text when attacking criminal
+ var/attack_two //text when attacking criminal, but directly to the criminal
+ var/patrol_emote //engaging patrol text
+ var/patrol_fail_emote //failing to engage patrol text
+ var/list/arrest_texts //first is for not-cuffing, second is for cuffing
+ var/arrest_emote //text stating that you're cuffing some criminal C with a threat of level X in location Y
+
+ //for reference, the following words are replaced when processed before speech:
+ //LOCATION = the location passed, if any (this is only used by arrest_emote)
+ //CRIMINAL = the name of the criminal (this is used by everything but patrol_emote and infraction)
+ //BOT = the name of the bot (this can be used on any of the emotes)
+ //THREAT_LEVEL = the level of the threat detected (can be used on arrest_emote and infraction)
+
+/datum/beepsky_fashion/proc/get_overlay(var/dir)
+ if(icon_file && obj_icon_state)
+ var/image/beepsky_overlay = image(icon_file, obj_icon_state, dir = dir)
+ beepsky_overlay.alpha = obj_alpha
+ beepsky_overlay.color = obj_color
+ return beepsky_overlay
+
+/datum/beepsky_fashion/proc/stun_attack(mob/living/carbon/C) //fired when beepsky does a stun attack with the fashion worn, for sounds/overlays/etc
+ return
+
+//actual fashions from here on out
+/datum/beepsky_fashion/wizard
+ obj_icon_state = "wizard"
+ name = "Archmage Beepsky"
+ desc = "A secbot stolen from the wizard federation."
+ death_emote = "BOT casts EI NATH on themselves!"
+ capture_one = "BOT is casting cable ties on CRIMINAL!"
+ capture_two = "BOT is casting cable ties on you!"
+ infraction = "Magical disturbance of magnitude THREAT_LEVEL detected!"
+ taunt = "BOT points his staff towards CRIMINAL!"
+ attack_one = "BOT casts magic missile on CRIMINAL!"
+ attack_two = "BOT casts magic missile on you!"
+ patrol_emote = "Beginning search for magical disturbances."
+ patrol_fail_emote = "Failure to find magical disturbances. Recallibrating."
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL magical practitioner CRIMINAL in LOCATION."
+ stun_sounds = list('sound/magic/lightningbolt.ogg',
+ 'sound/magic/fireball.ogg',
+ 'sound/weapons/zapbang.ogg',
+ 'sound/magic/knock.ogg',
+ 'sound/magic/fleshtostone.ogg',
+ 'sound/effects/magic.ogg',
+ 'sound/magic/disintegrate.ogg')
+
+/datum/beepsky_fashion/cowboy
+ obj_icon_state = "cowboy"
+ name = "Sheriff Beepsky"
+ desc = "The sheriff of this here station."
+ capture_one = "BOT is tying CRIMINAL up!"
+ capture_two = "BOT is tying you up!"
+ infraction = "Outlaws with a bounty of THREAT_LEVEL000 space dollars detected!"
+ taunt = "BOT aims his revolver towards CRIMINAL!"
+ attack_one = "BOT unloads his revolver onto CRIMINAL!"
+ attack_two = "BOT unloads his revolver onto you!"
+ patrol_emote = "Engaging bounty hunting protocols."
+ patrol_fail_emote = "Unable to find any bounties due to error. Rebooting."
+ arrest_emote = "ARREST_TYPE outlaw CRIMINAL with a bounty of THREAT_LEVEL000 in LOCATION."
+ stun_sounds = list('sound/weapons/Gunshot.ogg',
+ 'sound/weapons/Gunshot2.ogg',
+ 'sound/weapons/Gunshot3.ogg',
+ 'sound/weapons/Gunshot4.ogg')
+
+/datum/beepsky_fashion/chef
+ obj_icon_state = "chef"
+ name = "Chef Beepsky"
+ desc = "Cooking up the finest foods the station has ever seen."
+ death_emote = "Mamma-mia!"
+ infraction = "Grade THREAT_LEVEL prosciutto detected!"
+ taunt = "BOT glares at CRIMINAL."
+ attack_one = "BOT CQCs CRIMINAL!"
+ attack_two = "BOT CQCs you!"
+ patrol_emote = "Beginning search for the bad prosciutto."
+ patrol_fail_emote = "All prosciutto is stale. Rebooting."
+ arrest_texts = list("Frying", "Grilling") //any good secoff knows the difference
+ arrest_emote = "ARREST_TYPE grade THREAT_LEVEL prosciutto CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/cqchit1.ogg',
+ 'sound/weapons/cqchit2.ogg')
+
+/datum/beepsky_fashion/cat
+ obj_icon_state = "cat"
+ name = "OwOfficer Bweepskwee"
+ desc = "A beepsky unit with cat ears. Catgirl science has gone too far."
+ death_emote = "Nya!"
+ capture_one = "BOT is tying CRIMINAL up!!"
+ capture_two = "BOT is tying you up!"
+ infraction = "Wevel THREAT_LEVEL infwactwion awert!!!"
+ taunt = "BOT points at CRIMINAL and nyas!"
+ attack_one = "BOT shoves CRIMINAL onto a table!"
+ attack_two = "BOT shoves you onto a table!"
+ patrol_emote = "Enwgagwing patwol mwodies.."
+ patrol_fail_emote = "Unawbwle two stwawt patwollies. Nya."
+ arrest_texts = list("Dwetwaining", "Awwesting")
+ arrest_emote = "ARREST_TYPE wevel THREAT_LEVEL scwumbwag CRIMINAL in LOCATION. Nya."
+ ignore_sound = TRUE //we instead make the stunned person fire the nya emote
+
+/datum/beepsky_fashion/cat/stun_attack(var/mob/living/carbon/C) //makes a fake table under you on hit, makes cat people nya when hit
+ if(iscatperson(C))
+ C.emote("nya")
+ var/turf/target_turf = get_turf(C)
+ if(target_turf) //slams you on a fake table
+ playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
+ var/obj/effect/overlay_holder = new(target_turf)
+ overlay_holder.name = "Catboy Table"
+ overlay_holder.desc = "Where bad catboys go."
+ var/image/table_overlay = image('icons/obj/smooth_structures/table.dmi', "table")
+ overlay_holder.add_overlay(table_overlay)
+ QDEL_IN(overlay_holder, 10)
+
+/datum/beepsky_fashion/cake //nothing else. it's just beepsky. with a cake on his head.
+ obj_icon_state = "cake"
+ name = "Cakesky"
+ desc = "It's a secbot, wearing a cake on his head!"
+
+/datum/beepsky_fashion/captain
+ obj_icon_state = "captain"
+ name = "Captainsky"
+ desc = "The real captain of this station."
+ capture_one = "BOT is lecturing CRIMINAL on why he is the captain!"
+ capture_two = "BOT is lecturing you on why he is the captain!"
+ infraction = "Level THREAT_LEVEL greytider detected."
+ attack_one = "BOT beats CRIMINAL with the chain of command!"
+ attack_two = "BOT beats you with the chain of command!"
+ patrol_emote = "Uselessness protocols engaged."
+ patrol_fail_emote = "Unit has been found as useless. Rebooting."
+ arrest_texts = list("Demoting", "Firing")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL lesser crewmember CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/chainhit.ogg')
+
+/datum/beepsky_fashion/king
+ obj_icon_state = "king"
+ name = "King Beepsky"
+ desc = "He who has ascended to bare the right of king, sits atop the throne."
+ capture_one = "BOT is calling the guards onto CRIMINAL!"
+ capture_two = "BOT is calling the guards onto you!"
+ infraction = "Treason of level THREAT_LEVEL detected!"
+ attack_one = "BOT strikes CRIMINAL with his kingly authority!"
+ attack_two = "BOT strikes you with his kingly authority!"
+ patrol_emote = "Searching for peasants to beat up."
+ patrol_fail_emote = "Peasants are using dark magic. Recallibrating."
+ arrest_texts = list("Knighting", "Executing")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL peasant CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/punch1.ogg',
+ 'sound/weapons/punch2.ogg',
+ 'sound/weapons/punch3.ogg',
+ 'sound/weapons/punch4.ogg')
+
+/datum/beepsky_fashion/pirate
+ obj_icon_state = "pirate"
+ name = "Beepsbeard the Pirate"
+ desc = "Sailor of the seven seas, all sea-faring bots fear the one known as Beepsbeard."
+ capture_one = "BOT is making CRIMINAL walk the plank!"
+ capture_two = "BOT is making you walk the plank!"
+ infraction = "Enemy vessel spotted with threat level THREAT_LEVEL!"
+ attack_one = "BOT strikes CRIMINAL with his cutlass!"
+ attack_two = "BOT strikes you with his cutlass!"
+ patrol_emote = "Searching for enemy vessels to board."
+ patrol_fail_emote = "No way to engage enemy vessels. Rebooting."
+ arrest_texts = list("Boarding", "Sinking")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL vessel CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/bladeslice.ogg')
+
+/datum/beepsky_fashion/engineer
+ obj_icon_state = "engineer"
+ name = "Chief Engineer Beepsky"
+ desc = "He fixes criminals with a wrench to the face."
+ capture_one = "BOT is tying CRIMINAL up!"
+ capture_two = "BOT is tying you up!"
+ infraction = "Structural integrity issue spotted with threat level THREAT_LEVEL"
+ attack_one = "BOT strikes CRIMINAL with his wrench!"
+ attack_two = "BOT strikes you with his wrench!"
+ arrest_texts = list("Fixing", "Repairing")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL structural issue in LOCATION"
+ stun_sounds = list('sound/weapons/genhit.ogg')
+
+/datum/beepsky_fashion/tophat
+ obj_icon_state = "tophat"
+ name = "Fancy Beepsky"
+ desc = "It's a secbot, wearing a top hat! How fancy."
+
+/datum/beepsky_fashion/fedora
+ obj_icon_state = "fedora"
+ name = "Fedorasky"
+ desc = "It's a secbot, wearing a fedora!"
+
+/datum/beepsky_fashion/sombrero
+ obj_icon_state = "sombrero"
+ name = "Sombrerosky"
+ desc = "A secbot wearing a sombrero. Truly, a hombre to all."
+
+/datum/beepsky_fashion/santa
+ obj_icon_state = "santa"
+ name = "Saint Beepsky"
+ desc = "Have you been a level 7 infraction this holiday season?"
+ capture_one = "BOT is tying CRIMINAL up with fairy lights!"
+ capture_two = "BOT is tying you up with fairy lights!"
+ infraction = "Level THREAT_LEVEL threat to holiday cheer spotted!"
+ attack_one = "BOT crushes CRIMINAL with their holiday spirit!"
+ attack_two = "BOT crushes you with their holiday spirit!"
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL threat to holiday cheer in LOCATION"
+
diff --git a/code/datums/brain_damage/magic.dm b/code/datums/brain_damage/magic.dm
index ff04ceead9..a00b341b82 100644
--- a/code/datums/brain_damage/magic.dm
+++ b/code/datums/brain_damage/magic.dm
@@ -94,7 +94,7 @@
if(get_dist(owner, stalker) <= 1)
playsound(owner, 'sound/magic/demon_attack1.ogg', 50)
owner.visible_message("[owner] is torn apart by invisible claws!", "Ghostly claws tear your body apart!")
- owner.take_bodypart_damage(rand(20, 45))
+ owner.take_bodypart_damage(rand(20, 45), wound_bonus=CANT_WOUND)
else if(prob(50))
stalker.forceMove(get_step_towards(stalker, owner))
if(get_dist(owner, stalker) <= 8)
diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm
index 13cf2add97..7cc5348a0a 100644
--- a/code/datums/brain_damage/special.dm
+++ b/code/datums/brain_damage/special.dm
@@ -103,8 +103,7 @@
. = ..()
QDEL_IN(src, 300)
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/effect/hallucination/simple/bluespace_stream/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user != seer || !linked_to)
return
var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\
diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm
index 441a161428..4f56f58d23 100644
--- a/code/datums/components/butchering.dm
+++ b/code/datums/components/butchering.dm
@@ -2,7 +2,7 @@
var/speed = 80 //time in deciseconds taken to butcher something
var/effectiveness = 100 //percentage effectiveness; numbers above 100 yield extra drops
var/bonus_modifier = 0 //percentage increase to bonus item chance
- var/butcher_sound = 'sound/weapons/slice.ogg' //sound played when butchering
+ var/butcher_sound = 'sound/effects/butcher.ogg' //sound played when butchering
var/butchering_enabled = TRUE
var/can_be_blunt = FALSE
@@ -64,8 +64,11 @@
H.visible_message("[user] slits [H]'s throat!", \
"[user] slits your throat...")
log_combat(user, H, "finishes slicing the throat of")
- H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD)
- H.bleed_rate = clamp(H.bleed_rate + 20, 0, 30)
+ H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
+ var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
+ if(slit_throat)
+ var/datum/wound/slash/critical/screaming_through_a_slit_throat = new
+ screaming_through_a_slit_throat.apply_wound(slit_throat)
H.apply_status_effect(/datum/status_effect/neck_slice)
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm
index 863d55ccab..d138cf1971 100644
--- a/code/datums/components/caltrop.dm
+++ b/code/datums/components/caltrop.dm
@@ -48,7 +48,7 @@
var/damage = rand(min_damage, max_damage)
if(HAS_TRAIT(H, TRAIT_LIGHT_STEP))
damage *= 0.75
- H.apply_damage(damage, BRUTE, picked_def_zone)
+ H.apply_damage(damage, BRUTE, picked_def_zone, wound_bonus = CANT_WOUND)
if(cooldown < world.time - 10) //cooldown to avoid message spam.
if(!H.incapacitated(ignore_restraints = TRUE))
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index b9a1b5ec3b..1a9f4c0512 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -203,9 +203,9 @@
Set var amt to the value current cycle req is pointing to, its amount of type we need to delete
Get var/surroundings list of things accessable to crafting by get_environment()
Check the type of the current cycle req
- If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isnt remove thing from surroundings
+ If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isn't remove thing from surroundings
If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list
- If there isnt enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching
+ If there isn't enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching
While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one
If its stack check if it has enough amount
If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack
@@ -216,7 +216,7 @@
Then do a loop over parts var of the recipe
Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return
- After its done loop over deletion list and delete all the shit that wasnt taken by parts loop
+ After its done loop over deletion list and delete all the shit that wasn't taken by parts loop
del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already
*/
@@ -323,9 +323,12 @@
if(user == parent)
ui_interact(user)
+/datum/component/personal_crafting/ui_state(mob/user)
+ return GLOB.not_incapacitated_turf_state
+
//For the UI related things we're going to assume the user is a mob rather than typesetting it to an atom as the UI isn't generated if the parent is an atom
-/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/component/personal_crafting/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
cur_category = categories[1]
if(islist(categories[cur_category]))
@@ -333,7 +336,7 @@
cur_subcategory = subcats[1]
else
cur_subcategory = CAT_NONE
- ui = new(user, src, ui_key, "PersonalCrafting", "Crafting Menu", 700, 800, master_ui, state)
+ ui = new(user, src, "PersonalCrafting")
ui.open()
/datum/component/personal_crafting/ui_data(mob/user)
@@ -413,13 +416,8 @@
display_compact = !display_compact
. = TRUE
if("set_category")
- if(!isnull(params["category"]))
- cur_category = params["category"]
- if(!isnull(params["subcategory"]))
- if(params["subcategory"] == "0")
- cur_subcategory = ""
- else
- cur_subcategory = params["subcategory"]
+ cur_category = params["category"]
+ cur_subcategory = params["subcategory"] || ""
. = TRUE
/datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R)
diff --git a/code/datums/components/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm
index 7a7379c834..2a24c0b451 100644
--- a/code/datums/components/crafting/recipes/recipes_clothing.dm
+++ b/code/datums/components/crafting/recipes/recipes_clothing.dm
@@ -263,6 +263,14 @@
time = 30
category = CAT_CLOTHING
+/datum/crafting_recipe/durathread_reinforcement_kit
+ name = "Durathread Reinforcement Kit"
+ result = /obj/item/armorkit
+ reqs = list(/obj/item/stack/sheet/durathread = 4)
+ tools = list(/obj/item/stack/sheet/mineral/titanium, TOOL_WIRECUTTER) // tough needle for a tough fabric
+ time = 40
+ category = CAT_CLOTHING
+
/datum/crafting_recipe/durathread_duffelbag
name = "Durathread Dufflebag"
result = /obj/item/storage/backpack/duffelbag/durathread
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index 86d1e77661..214c1b1427 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -324,6 +324,13 @@
result = /obj/item/toy/sword/cx
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
+
+/datum/crafting_recipe/catgirlplushie
+ name = "Catgirl Plushie"
+ reqs = list(/obj/item/toy/plush/hairball = 3)
+ result = /obj/item/toy/plush/catgirl
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
////////////
//Unsorted//
diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm
index 137a1bb864..51098756d3 100644
--- a/code/datums/components/embedded.dm
+++ b/code/datums/components/embedded.dm
@@ -29,7 +29,6 @@
*/
-
/datum/component/embedded
dupe_mode = COMPONENT_DUPE_ALLOWED
var/obj/item/bodypart/limb
@@ -139,31 +138,37 @@
limb.embedded_objects |= weapon // on the inside... on the inside...
weapon.forceMove(victim)
RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/byeItemCarbon)
-
+ var/damage = 0
if(harmful)
victim.visible_message("[weapon] embeds itself in [victim]'s [limb.name]!",ignored_mobs=victim)
to_chat(victim, "[weapon] embeds itself in your [limb.name]!")
victim.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
playsound(victim,'sound/weapons/bladeslice.ogg', 40)
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
- var/damage = weapon.w_class * impact_pain_mult
- limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
+ damage = weapon.w_class * impact_pain_mult
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
else
victim.visible_message("[weapon] sticks itself to [victim]'s [limb.name]!",ignored_mobs=victim)
to_chat(victim, "[weapon] sticks itself to your [limb.name]!")
+ if(damage > 0)
+ var/armor = victim.run_armor_check(limb.body_zone, "melee", "Your armor has protected your [limb.name].", "Your armor has softened a hit to your [limb.name].",weapon.armour_penetration)
+ limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, blocked=armor, sharpness = weapon.get_sharpness())
+
/// Called every time a carbon with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the carbon is crawling or walking.
/datum/component/embedded/proc/jostleCheck()
var/mob/living/carbon/victim = parent
- var/chance = jostle_chance
+ var/damage = weapon.w_class * pain_mult
+ var/pain_chance_current = jostle_chance
if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND))
- chance *= 0.5
+ pain_chance_current *= 0.5
- if(harmful && prob(chance))
- var/damage = weapon.w_class * jostle_pain_mult
- limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
+ if(pain_stam_pct && IS_STAMCRIT(victim)) //if it's a less-lethal embed, give them a break if they're already stamcritted
+ pain_chance_current *= 0.2
+ damage *= 0.5
+ if(harmful && prob(pain_chance_current))
+ limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
to_chat(victim, "[weapon] embedded in your [limb.name] jostles and stings!")
@@ -173,7 +178,7 @@
if(harmful)
var/damage = weapon.w_class * remove_pain_mult
- limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
+ limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
victim.visible_message("[weapon] falls out of [victim.name]'s [limb.name]!", ignored_mobs=victim)
to_chat(victim, "[weapon] falls out of your [limb.name]!")
else
@@ -199,7 +204,7 @@
if(harmful)
var/damage = weapon.w_class * remove_pain_mult
- limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage) //It hurts to rip it out, get surgery you dingus.
+ limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND) //It hurts to rip it out, get surgery you dingus.
victim.emote("scream")
victim.visible_message("[victim] successfully rips [weapon] out of [victim.p_their()] [limb.name]!", "You successfully remove [weapon] from your [limb.name].")
else
@@ -276,14 +281,16 @@
damage *= 0.7
if(harmful && prob(chance))
- limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
+ limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
to_chat(victim, "[weapon] embedded in your [limb.name] hurts!")
- if(prob(fall_chance))
+ var/fall_chance_current = fall_chance
+ if(victim.mobility_flags & ~MOBILITY_STAND)
+ fall_chance_current *= 0.2
+
+ if(prob(fall_chance_current))
fallOutCarbon()
-
-
////////////////////////////////////////
//////////////TURF PROCS////////////////
////////////////////////////////////////
diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm
index 200ec2b956..c2b3ad1f30 100644
--- a/code/datums/components/gps.dm
+++ b/code/datums/components/gps.dm
@@ -80,19 +80,15 @@ GLOBAL_LIST_EMPTY(GPS_list)
to_chat(user, "[parent] is now tracking, and visible to other GPS devices.")
tracking = TRUE
-/datum/component/gps/item/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
+/datum/component/gps/item/ui_interact(mob/user, datum/tgui/ui)
if(emped)
to_chat(user, "[parent] fizzles weakly.")
return
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- // Variable window height, depending on how many GPS units there are
- // to show, clamped to relatively safe range.
- var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700)
- ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
+ ui = new(user, src, "Gps")
ui.open()
-
- ui.set_autoupdate(state = updating)
+ ui.set_autoupdate(updating)
/datum/component/gps/item/ui_data(mob/user)
var/list/data = list()
diff --git a/code/datums/components/killerqueen.dm b/code/datums/components/killerqueen.dm
new file mode 100644
index 0000000000..1c660d0a87
--- /dev/null
+++ b/code/datums/components/killerqueen.dm
@@ -0,0 +1,91 @@
+/**
+ * KILLER QUEEN
+ *
+ * Simple contact bomb component
+ * Blows up the first person to touch it.
+ */
+/datum/component/killerqueen
+ can_transfer = TRUE
+ /// strength of explosion on the touch-er. 0 to disable. usually only used if the normal explosion is disabled (this is the default).
+ var/ex_strength = EXPLODE_HEAVY
+ /// callback to invoke with (parent, victim) before standard detonation - useful for losing a reference to this component or implementing custom behavior. return FALSE to prevent explosion.
+ var/datum/callback/pre_explode
+ /// callback to invoke with (parent) when deleting without an explosion
+ var/datum/callback/failure
+ /// did we explode
+ var/exploded = FALSE
+ /// examine message
+ var/examine_message
+ /// light explosion radius
+ var/light = 0
+ /// heavy explosion radius
+ var/heavy = 0
+ /// dev explosion radius
+ var/dev = 0
+ /// flame explosion radius
+ var/flame = 0
+ /// only triggered by living mobs
+ var/living_only = TRUE
+
+
+/datum/component/killerqueen/Initialize(ex_strength = EXPLODE_HEAVY, datum/callback/pre_explode, datum/callback/failure, examine_message, light = 0, heavy = 0, dev = 0, flame = 0, living_only = TRUE)
+ . = ..()
+ if(. & COMPONENT_INCOMPATIBLE)
+ return
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+ src.ex_strength = ex_strength
+ src.pre_explode = pre_explode
+ src.failure = failure
+ src.examine_message = examine_message
+ src.light = light
+ src.heavy = heavy
+ src.dev = dev
+ src.flame = flame
+ src.living_only = living_only
+
+/datum/component/killerqueen/Destroy()
+ if(!exploded)
+ failure?.Invoke(parent)
+ return ..()
+
+/datum/component/killerqueen/RegisterWithParent()
+ . = ..()
+ RegisterSignal(parent, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_ANIMAL), .proc/touch_detonate)
+ RegisterSignal(parent, COMSIG_MOVABLE_BUMP, .proc/bump_detonate)
+ RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/attackby_detonate)
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
+
+/datum/component/killerqueen/UnregisterFromParent()
+ . = ..()
+ UnregisterSignal(parent, list(COMSIG_ATOM_ATTACK_ANIMAL, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW,
+ COMSIG_MOVABLE_BUMP, COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
+
+/datum/component/killerqueen/proc/attackby_detonate(datum/source, obj/item/I, mob/user)
+ detonate(user)
+
+/datum/component/killerqueen/proc/bump_detonate(datum/source, atom/A)
+ detonate(A)
+
+/datum/component/killerqueen/proc/touch_detonate(datum/source, mob/user)
+ detonate(user)
+
+/datum/component/killerqueen/proc/on_examine(datum/source, mob/examiner, list/examine_return)
+ if(examine_message)
+ examine_return += examine_message
+
+/datum/component/killerqueen/proc/detonate(atom/victim)
+ if(!isliving(victim) && living_only)
+ return
+ if(pre_explode && !pre_explode.Invoke(parent, victim))
+ return
+ if(ex_strength)
+ victim.ex_act(ex_strength)
+ if(light || heavy || dev || flame)
+ explosion(parent, dev, heavy, light, flame_range = flame)
+ else
+ var/turf/T = get_turf(parent)
+ playsound(T, 'sound/effects/explosion2.ogg', 200, 1)
+ new /obj/effect/temp_visual/explosion(T)
+ exploded = TRUE
+ qdel(src)
diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
index 90fea9ec8a..87bc681651 100644
--- a/code/datums/components/mood.dm
+++ b/code/datums/components/mood.dm
@@ -307,6 +307,10 @@
/datum/component/mood/proc/HandleNutrition(mob/living/L)
+ if(isethereal(L))
+ HandleCharge(L)
+ if(HAS_TRAIT(L, TRAIT_NOHUNGER))
+ return FALSE //no mood events for nutrition
switch(L.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
add_event(null, "nutrition", /datum/mood_event/fat)
@@ -321,6 +325,22 @@
if(0 to NUTRITION_LEVEL_STARVING)
add_event(null, "nutrition", /datum/mood_event/starving)
+/datum/component/mood/proc/HandleCharge(mob/living/carbon/human/H)
+ var/datum/species/ethereal/E = H.dna.species
+ switch(E.get_charge(H))
+ if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER)
+ add_event(null, "charge", /datum/mood_event/decharged)
+ if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
+ add_event(null, "charge", /datum/mood_event/lowpower)
+ if(ETHEREAL_CHARGE_NORMAL to ETHEREAL_CHARGE_ALMOSTFULL)
+ clear_event(null, "charge")
+ if(ETHEREAL_CHARGE_ALMOSTFULL to ETHEREAL_CHARGE_FULL)
+ add_event(null, "charge", /datum/mood_event/charged)
+ if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD)
+ add_event(null, "charge", /datum/mood_event/overcharged)
+ if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
+ add_event(null, "charge", /datum/mood_event/supercharged)
+
/datum/component/mood/proc/update_beauty(area/A)
if(A.outdoors) //if we're outside, we don't care.
clear_event(null, "area_beauty")
diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm
index 938d9f5f56..6a1028cc65 100644
--- a/code/datums/components/pellet_cloud.dm
+++ b/code/datums/components/pellet_cloud.dm
@@ -1,3 +1,8 @@
+// the following defines are used for [/datum/component/pellet_cloud/var/list/wound_info_by_part] to store the damage, wound_bonus, and bw_bonus for each bodypart hit
+#define CLOUD_POSITION_DAMAGE 1
+#define CLOUD_POSITION_W_BONUS 2
+#define CLOUD_POSITION_BW_BONUS 3
+
/*
* This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point,
* without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated
@@ -29,7 +34,10 @@
var/list/pellets = list()
/// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages
var/list/targets_hit = list()
- /// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
+
+ /// Another associated list for hit bodyparts on carbons so we can track how much wounding potential we have for each bodypart
+ var/list/wound_info_by_part = list()
+ /// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs]
var/list/bodies
/// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
var/list/purple_hearts
@@ -64,6 +72,7 @@
/datum/component/pellet_cloud/Destroy(force, silent)
purple_hearts = null
pellets = null
+ wound_info_by_part = null
targets_hit = null
bodies = null
return ..()
@@ -187,10 +196,26 @@
break
///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets)
-/datum/component/pellet_cloud/proc/pellet_hit(obj/item/projectile/P, atom/movable/firer, atom/target, Angle)
+/datum/component/pellet_cloud/proc/pellet_hit(obj/item/projectile/P, atom/movable/firer, atom/target, Angle, hit_zone)
pellets -= P
terminated++
hits++
+ var/obj/item/bodypart/hit_part
+ if(iscarbon(target) && hit_zone)
+ var/mob/living/carbon/hit_carbon = target
+ hit_part = hit_carbon.get_bodypart(hit_zone)
+ if(hit_part)
+ target = hit_part
+ if(P.wound_bonus != CANT_WOUND) // handle wounding
+ // unfortunately, due to how pellet clouds handle finalizing only after every pellet is accounted for, that also means there might be a short delay in dealing wounds if one pellet goes wide
+ // while buckshot may reach a target or miss it all in one tick, we also have to account for possible ricochets that may take a bit longer to hit the target
+ if(isnull(wound_info_by_part[hit_part]))
+ wound_info_by_part[hit_part] = list(0, 0, 0)
+ wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE] += P.damage // these account for decay
+ wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS] += P.wound_bonus
+ wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS] += P.bare_wound_bonus
+ P.wound_bonus = CANT_WOUND // actual wounding will be handled aggregate
+
targets_hit[target]++
if(targets_hit[target] == 1)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
@@ -231,13 +256,23 @@
for(var/atom/target in targets_hit)
var/num_hits = targets_hit[target]
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
- if(num_hits > 1)
- target.visible_message("[target] is hit by [num_hits] [proj_name]s!", null, null, COMBAT_MESSAGE_RANGE, target)
- to_chat(target, "You're hit by [num_hits] [proj_name]s!")
- else
- target.visible_message("[target] is hit by a [proj_name]!", null, null, COMBAT_MESSAGE_RANGE, target)
- to_chat(target, "You're hit by a [proj_name]!")
+ var/obj/item/bodypart/hit_part
+ if(isbodypart(target))
+ hit_part = target
+ target = hit_part.owner
+ var/damage_dealt = wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE]
+ var/w_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS]
+ var/bw_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS]
+ var/wound_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling
+ wound_info_by_part[hit_part] = null
+ hit_part.painless_wound_roll(wound_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness))
+ if(num_hits > 1)
+ target.visible_message("[target] is hit by [num_hits] [proj_name]s[hit_part ? " in the [hit_part.name]" : ""]!", null, null, COMBAT_MESSAGE_RANGE, target)
+ to_chat(target, "You're hit by [num_hits] [proj_name]s[hit_part ? " in the [hit_part.name]" : ""]!")
+ else
+ target.visible_message("[target] is hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!", null, null, COMBAT_MESSAGE_RANGE, target)
+ to_chat(target, "You're hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!")
UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED)
if(queued_delete)
qdel(parent)
@@ -281,3 +316,7 @@
targets_hit -= target
bodies -= target
purple_hearts -= target
+
+#undef CLOUD_POSITION_DAMAGE
+#undef CLOUD_POSITION_W_BONUS
+#undef CLOUD_POSITION_BW_BONUS
diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm
index f12e8bf007..8afa4353b2 100644
--- a/code/datums/components/radioactive.dm
+++ b/code/datums/components/radioactive.dm
@@ -29,10 +29,18 @@
if(strength > RAD_MINIMUM_CONTAMINATION)
SSradiation.warn(src)
+ //Let's make er glow
+ //This relies on parent not being a turf or something. IF YOU CHANGE THAT, CHANGE THIS
+ var/atom/movable/master = parent
+ master.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
+ addtimer(CALLBACK(src, .proc/glow_loop, master), rand(1,19))//Things should look uneven
+
START_PROCESSING(SSradiation, src)
/datum/component/radioactive/Destroy()
STOP_PROCESSING(SSradiation, src)
+ var/atom/movable/master = parent
+ master.remove_filter("rad_glow")
return ..()
/datum/component/radioactive/process()
@@ -46,6 +54,13 @@
if(strength <= RAD_BACKGROUND_RADIATION)
return PROCESS_KILL
+
+/datum/component/radioactive/proc/glow_loop(atom/movable/master)
+ var/filter = master.get_filter("rad_glow")
+ if(filter)
+ animate(filter, alpha = 110, time = 15, loop = -1)
+ animate(alpha = 40, time = 25)
+
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, _half_life, _can_contaminate)
if(!i_am_original)
return
diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm
index f5da669c3a..129faabdb7 100644
--- a/code/datums/components/rotation.dm
+++ b/code/datums/components/rotation.dm
@@ -98,16 +98,16 @@
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
if(can_be_rotated)
- if(!can_be_rotated.Invoke(user, default_rotation_direction))
+ if(!can_be_rotated.Invoke(user, rotation))
return
else
- if(!default_can_be_rotated(user, default_rotation_direction))
+ if(!default_can_be_rotated(user, rotation))
return
if(can_user_rotate)
- if(!can_user_rotate.Invoke(user, default_rotation_direction))
+ if(!can_user_rotate.Invoke(user, rotation))
return
else
- if(!default_can_user_rotate(user, default_rotation_direction))
+ if(!default_can_user_rotate(user, rotation))
return
BaseRot(user, rotation)
return TRUE
diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm
index 792222b27b..df44aef4de 100644
--- a/code/datums/components/squeak.dm
+++ b/code/datums/components/squeak.dm
@@ -11,6 +11,13 @@
// This is to stop squeak spam from inhand usage
var/last_use = 0
var/use_delay = 20
+
+ // squeak cooldowns
+ var/last_squeak = 0
+ var/squeak_delay = 5
+
+ /// chance we'll be stopped from squeaking by cooldown when something crossing us squeaks
+ var/cross_squeak_delay_chance = 33 // about 3 things can squeak at a time
/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override)
if(!isatom(parent))
@@ -19,6 +26,7 @@
if(ismovable(parent))
RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak)
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED), .proc/play_squeak_crossed)
+ RegisterSignal(parent, COMSIG_CROSS_SQUEAKED, .proc/delay_squeak)
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react)
if(isitem(parent))
RegisterSignal(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_HIT_REACT), .proc/play_squeak)
@@ -39,20 +47,28 @@
use_delay = use_delay_override
/datum/component/squeak/proc/play_squeak()
+ do_play_squeak()
+
+/datum/component/squeak/proc/do_play_squeak(bypass_cooldown = FALSE)
+ if(!bypass_cooldown && ((last_squeak + squeak_delay) >= world.time))
+ return FALSE
if(prob(squeak_chance))
if(!override_squeak_sounds)
playsound(parent, pickweight(default_squeak_sounds), volume, 1, -1)
else
playsound(parent, pickweight(override_squeak_sounds), volume, 1, -1)
+ last_squeak = world.time
+ return TRUE
+ return FALSE
/datum/component/squeak/proc/step_squeak()
if(steps > step_delay)
- play_squeak()
+ do_play_squeak(TRUE)
steps = 0
else
steps++
-/datum/component/squeak/proc/play_squeak_crossed(atom/movable/AM)
+/datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/AM)
if(isitem(AM))
var/obj/item/I = AM
if(I.item_flags & ABSTRACT)
@@ -63,13 +79,18 @@
return
var/atom/current_parent = parent
if(isturf(current_parent.loc))
- play_squeak()
+ if(do_play_squeak())
+ SEND_SIGNAL(AM, COMSIG_CROSS_SQUEAKED)
/datum/component/squeak/proc/use_squeak()
if(last_use + use_delay < world.time)
last_use = world.time
play_squeak()
+/datum/component/squeak/proc/delay_squeak()
+ if(prob(cross_squeak_delay_chance))
+ last_squeak = world.time
+
/datum/component/squeak/proc/on_equip(datum/source, mob/equipper, slot)
RegisterSignal(equipper, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react, TRUE)
diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm
index bd12ecc092..a5f9271f4b 100644
--- a/code/datums/components/tackle.dm
+++ b/code/datums/components/tackle.dm
@@ -62,6 +62,7 @@
///Store the thrownthing datum for later use
/datum/component/tackler/proc/registerTackle(mob/living/carbon/user, datum/thrownthing/TT)
tackle = TT
+ tackle.thrower = user
///See if we can tackle or not. If we can, leap!
/datum/component/tackler/proc/checkTackle(mob/living/carbon/user, atom/A, params)
diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm
index 77a9a79bf4..bcbf979101 100644
--- a/code/datums/components/twohanded.dm
+++ b/code/datums/components/twohanded.dm
@@ -105,6 +105,8 @@
/// Triggered on attack self of the item containing the component
/datum/component/two_handed/proc/on_attack_self(datum/source, mob/user)
+ if(!user.is_holding(parent))
+ return //give no quarter to telekinesis powergaemrs (telekinetic wielding will desync the offhand and result in all sorts of bugs so no until someone codes it properly)
if(wielded)
unwield(user)
else
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index a269e24974..460a73bf5a 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -102,6 +102,15 @@ GLOBAL_LIST_EMPTY(uplinks)
return //no hitting everyone/everything just to try to slot tcs in!
if(istype(I, /obj/item/stack/telecrystal))
LoadTC(user, I)
+ if(active)
+ if(I.GetComponent(/datum/component/uplink))
+ var/datum/component/uplink/hidden_uplink = I.GetComponent(/datum/component/uplink)
+ var/amt = hidden_uplink.telecrystals
+ hidden_uplink.telecrystals -= amt
+ src.telecrystals += amt
+ to_chat(user, "You connect the [I] to your uplink, siphoning [amt] telecrystals before quickly undoing the connection.")
+ else
+ return
for(var/category in uplink_items)
for(var/item in uplink_items[category])
var/datum/uplink_item/UI = uplink_items[category][item]
@@ -134,23 +143,19 @@ GLOBAL_LIST_EMPTY(uplinks)
// an unlocked uplink blocks also opening the PDA or headset menu
return COMPONENT_NO_INTERACT
-/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
+/datum/component/uplink/ui_state(mob/user)
+ return GLOB.inventory_state
+
+/datum/component/uplink/ui_interact(mob/user, datum/tgui/ui)
active = TRUE
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Uplink", name, 620, 580, master_ui, state)
+ ui = new(user, src, "Uplink", name)
// This UI is only ever opened by one person,
// and never is updated outside of user input.
ui.set_autoupdate(FALSE)
ui.open()
-/datum/component/uplink/ui_host(mob/user)
- if(istype(parent, /obj/item/implant)) //implants are like organs, not really located inside mobs codewise.
- var/obj/item/implant/I = parent
- return I.imp_in
- return ..()
-
/datum/component/uplink/ui_data(mob/user)
if(!user.mind)
return
@@ -178,8 +183,18 @@ GLOBAL_LIST_EMPTY(uplinks)
is_inaccessible = FALSE
if(is_inaccessible)
continue
+ /*
+ if(I.restricted_species) //catpeople specfic gloves.
+ if(ishuman(user))
+ var/is_inaccessible = TRUE
+ var/mob/living/carbon/human/H = user
+ for(var/F in I.restricted_species)
+ if(F == H.dna.species.id || debug)
+ is_inaccessible = FALSE
+ break
if(is_inaccessible)
continue
+ */
cat["items"] += list(list(
"name" = I.name,
"cost" = I.cost,
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 94940b3855..5aeb7626f6 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -1,13 +1,13 @@
-
+//TODO: someone please get rid of this shit
/datum/datacore
- var/medical[] = list()
+ var/list/medical = list()
var/medicalPrintCount = 0
- var/general[] = list()
- var/security[] = list()
+ var/list/general = list()
+ var/list/security = list()
var/securityPrintCount = 0
var/securityCrimeCounter = 0
- //This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
- var/locked[] = list()
+ ///This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
+ var/list/locked = list()
/datum/data
var/name = "data"
@@ -78,6 +78,8 @@
/datum/datacore/proc/manifest()
for(var/mob/dead/new_player/N in GLOB.player_list)
+ if(!N?.client)
+ continue
if(N.new_character)
log_manifest(N.ckey,N.new_character.mind,N.new_character)
if(ishuman(N.new_character))
@@ -89,6 +91,42 @@
if(foundrecord)
foundrecord.fields["rank"] = assignment
+/datum/datacore/proc/get_manifest_tg() //copypasted from tg, renamed to avoid namespace conflicts
+ var/list/manifest_out = list()
+ var/list/departments = list(
+ "Command" = GLOB.command_positions,
+ "Security" = GLOB.security_positions,
+ "Engineering" = GLOB.engineering_positions,
+ "Medical" = GLOB.medical_positions,
+ "Science" = GLOB.science_positions,
+ "Supply" = GLOB.supply_positions,
+ "Service" = GLOB.civilian_positions,
+ "Silicon" = GLOB.nonhuman_positions
+ )
+ for(var/datum/data/record/t in GLOB.data_core.general)
+ var/name = t.fields["name"]
+ var/rank = t.fields["rank"]
+ var/has_department = FALSE
+ for(var/department in departments)
+ var/list/jobs = departments[department]
+ if(rank in jobs)
+ if(!manifest_out[department])
+ manifest_out[department] = list()
+ manifest_out[department] += list(list(
+ "name" = name,
+ "rank" = rank
+ ))
+ has_department = TRUE
+ break
+ if(!has_department)
+ if(!manifest_out["Misc"])
+ manifest_out["Misc"] = list()
+ manifest_out["Misc"] += list(list(
+ "name" = name,
+ "rank" = rank
+ ))
+ return manifest_out
+
/datum/datacore/proc/get_manifest(monochrome, OOC)
var/list/heads = list()
var/list/sec = list()
diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm
index 774d97202e..0fad819e8e 100644
--- a/code/datums/diseases/advance/symptoms/flesh_eating.dm
+++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm
@@ -64,7 +64,8 @@ Bonus
if(bleed)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- H.bleed_rate += 5 * power
+ var/obj/item/bodypart/random_part = pick(H.bodyparts)
+ random_part.generic_bleedstacks += 5 * power
return 1
/*
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 23b6704080..de5c1ece91 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -50,6 +50,7 @@
destination.dna.skin_tone_override = skin_tone_override
destination.dna.features = features.Copy()
destination.set_species(species.type, icon_update=0)
+ destination.dna.species.say_mod = species.say_mod
destination.dna.real_name = real_name
destination.dna.nameless = nameless
destination.dna.custom_species = custom_species
@@ -74,6 +75,7 @@
new_dna.skin_tone_override = skin_tone_override
new_dna.features = features.Copy()
new_dna.species = new species.type
+ new_dna.species.say_mod = species.say_mod
new_dna.real_name = real_name
new_dna.nameless = nameless
new_dna.custom_species = custom_species
@@ -131,9 +133,9 @@
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color)
- L[DNA_COLOR_ONE_BLOCK] = sanitize_hexcolor(features["mcolor"])
- L[DNA_COLOR_TWO_BLOCK] = sanitize_hexcolor(features["mcolor2"])
- L[DNA_COLOR_THREE_BLOCK] = sanitize_hexcolor(features["mcolor3"])
+ L[DNA_COLOR_ONE_BLOCK] = sanitize_hexcolor(features["mcolor"], 6)
+ L[DNA_COLOR_TWO_BLOCK] = sanitize_hexcolor(features["mcolor2"], 6)
+ L[DNA_COLOR_THREE_BLOCK] = sanitize_hexcolor(features["mcolor3"], 6)
if(!GLOB.mam_tails_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
L[DNA_MUTANTTAIL_BLOCK] = construct_block(GLOB.mam_tails_list.Find(features["mam_tail"]), GLOB.mam_tails_list.len)
@@ -239,11 +241,11 @@
if(DNA_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len))
if(DNA_COLOR_ONE_BLOCK)
- sanitize_hexcolor(features["mcolor"])
+ sanitize_hexcolor(features["mcolor"], 6)
if(DNA_COLOR_TWO_BLOCK)
- sanitize_hexcolor(features["mcolor2"])
+ sanitize_hexcolor(features["mcolor2"], 6)
if(DNA_COLOR_THREE_BLOCK)
- sanitize_hexcolor(features["mcolor3"])
+ sanitize_hexcolor(features["mcolor3"], 6)
if(DNA_MUTANTTAIL_BLOCK)
construct_block(GLOB.mam_tails_list.Find(features["mam_tail"]), GLOB.mam_tails_list.len)
if(DNA_MUTANTEAR_BLOCK)
diff --git a/code/datums/dog_fashion.dm b/code/datums/dog_fashion.dm
index 744f57c391..2e80feac67 100644
--- a/code/datums/dog_fashion.dm
+++ b/code/datums/dog_fashion.dm
@@ -38,7 +38,6 @@
corgI.color = obj_color
return corgI
-
/datum/dog_fashion/head
icon_file = 'icons/mob/corgi_head.dmi'
@@ -53,7 +52,6 @@
name = "Sous chef REAL_NAME"
desc = "Your food will be taste-tested. All of it."
-
/datum/dog_fashion/head/captain
name = "Captain REAL_NAME"
desc = "Probably better than the last captain."
diff --git a/code/datums/elements/embed.dm b/code/datums/elements/embed.dm
index 8a7acde9cb..876414330f 100644
--- a/code/datums/elements/embed.dm
+++ b/code/datums/elements/embed.dm
@@ -2,7 +2,7 @@
The presence of this element allows an item (or a projectile carrying an item) to embed itself in a human or turf when it is thrown into a target (whether by hand, gun, or explosive wave) with either
at least 4 throwspeed (EMBED_THROWSPEED_THRESHOLD) or ignore_throwspeed_threshold set to TRUE. Items meant to be used as shrapnel for projectiles should have ignore_throwspeed_threshold set to true.
- Whether we're dealing with a direct /obj/item (throwing a knife at someone) or an /obj/projectile with a shrapnel_type, how we handle things plays out the same, with one extra step separating them.
+ Whether we're dealing with a direct /obj/item (throwing a knife at someone) or an /obj/item/projectile with a shrapnel_type, how we handle things plays out the same, with one extra step separating them.
Items simply make their COMSIG_MOVABLE_IMPACT or COMSIG_MOVABLE_IMPACT_ZONE check (against a closed turf or a carbon, respectively), while projectiles check on COMSIG_PROJECTILE_SELF_ON_HIT.
Upon a projectile hitting a valid target, it spawns whatever type of payload it has defined, then has that try to embed itself in the target on its own.
@@ -37,10 +37,10 @@
if(!isitem(target) && !isprojectile(target))
return ELEMENT_INCOMPATIBLE
+ RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage)
if(isitem(target))
RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbedMob)
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, .proc/checkEmbedOther)
- RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage)
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/examined)
RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, .proc/tryForceEmbed)
RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, .proc/detachFromWeapon)
@@ -68,7 +68,7 @@
if(isitem(target))
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_PARENT_EXAMINE, COMSIG_EMBED_TRY_FORCE, COMSIG_ITEM_DISABLE_EMBED))
else
- UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT))
+ UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT, COMSIG_ELEMENT_ATTACH))
/// Checking to see if we're gonna embed into a human
@@ -79,13 +79,13 @@
var/actual_chance = embed_chance
if(!weapon.isEmbedHarmless()) // all the armor in the world won't save you from a kick me sign
- var/armor = max(victim.run_armor_check(hit_zone, "bullet", silent=TRUE), victim.run_armor_check(hit_zone, "bomb", silent=TRUE)) // we'll be nice and take the better of bullet and bomb armor
+ var/armor = max(victim.run_armor_check(hit_zone, "bullet", silent=TRUE), victim.run_armor_check(hit_zone, "bomb", silent=TRUE)) * 0.5 // we'll be nice and take the better of bullet and bomb armor, halved
if(armor) // we only care about armor penetration if there's actually armor to penetrate
var/pen_mod = -armor + weapon.armour_penetration // even a little bit of armor can make a big difference for shrapnel with large negative armor pen
actual_chance += pen_mod // doing the armor pen as a separate calc just in case this ever gets expanded on
if(actual_chance <= 0)
- victim.visible_message("[weapon] bounces off [victim]'s armor!", "[weapon] bounces off your armor!", vision_distance = COMBAT_MESSAGE_RANGE)
+ victim.visible_message("[weapon] bounces off [victim]'s armor, unable to embed!", "[weapon] bounces off your armor, unable to embed!", vision_distance = COMBAT_MESSAGE_RANGE)
return
var/roll_embed = prob(actual_chance)
@@ -147,7 +147,7 @@
return TRUE
///A different embed element has been attached, so we'll detach and let them handle things
-/datum/element/embed/proc/severancePackage(obj/item/weapon, datum/element/E)
+/datum/element/embed/proc/severancePackage(obj/weapon, datum/element/E)
if(istype(E, /datum/element/embed))
Detach(weapon)
@@ -169,46 +169,35 @@
* it to call tryForceEmbed() on its own embed element (it's out of our hands here, our projectile is done), where it will run through all the checks it needs to.
*/
/datum/element/embed/proc/checkEmbedProjectile(obj/item/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone)
- if(!iscarbon(hit) && !isclosedturf(hit))
+ if(!iscarbon(hit))
Detach(P)
return // we don't care
var/obj/item/payload = new payload_type(get_turf(hit))
- var/did_embed
- if(iscarbon(hit))
- var/mob/living/carbon/C = hit
- var/obj/item/bodypart/limb
- limb = C.get_bodypart(hit_zone)
- if(!limb)
- limb = C.get_bodypart()
- did_embed = payload.tryEmbed(limb)
- else
- did_embed = payload.tryEmbed(hit)
+ if(istype(payload, /obj/item/shrapnel/bullet))
+ payload.name = P.name
+ payload.embedding = P.embedding
+ payload.updateEmbedding()
+ var/mob/living/carbon/C = hit
+ var/obj/item/bodypart/limb = C.get_bodypart(hit_zone)
+ if(!limb)
+ limb = C.get_bodypart()
- if(!did_embed)
- payload.failedEmbed()
+ payload.tryEmbed(limb)
Detach(P)
/**
- * tryForceEmbed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it.
- *
- * The reason for this extra mucking about is avoiding having to do an extra hitby(), and annoying the target by impacting them once with the projectile, then again with the shrapnel (which likely represents said bullet), and possibly
- * AGAIN if we actually embed. This way, we save on at least one message. Runs the standard embed checks on the mob/turf.
- *
* Arguments:
- * * I- what we're trying to embed, obviously
- * * target- what we're trying to shish-kabob, either a bodypart, a carbon, or a closed turf
+ * * I- the item we're trying to insert into the target
+ * * target- what we're trying to shish-kabob, either a bodypart or a carbon
* * hit_zone- if our target is a carbon, try to hit them in this zone, if we don't have one, pick a random one. If our target is a bodypart, we already know where we're hitting.
* * forced- if we want this to succeed 100%
*/
/datum/element/embed/proc/tryForceEmbed(obj/item/I, atom/target, hit_zone, forced=FALSE)
var/obj/item/bodypart/limb
var/mob/living/carbon/C
- var/turf/closed/T
-
if(!forced && !prob(embed_chance))
return
-
if(iscarbon(target))
C = target
if(!hit_zone)
@@ -218,10 +207,5 @@
limb = target
hit_zone = limb.body_zone
C = limb.owner
- else if(isclosedturf(target))
- T = target
-
- if(C)
- return checkEmbedMob(I, C, hit_zone, forced=TRUE)
- else if(T)
- return checkEmbedOther(I, T, forced=TRUE)
+ checkEmbedMob(I, C, hit_zone, forced=TRUE)
+ return TRUE
diff --git a/code/datums/elements/photosynthesis.dm b/code/datums/elements/photosynthesis.dm
index 93e4369b8b..4fe0615b1f 100644
--- a/code/datums/elements/photosynthesis.dm
+++ b/code/datums/elements/photosynthesis.dm
@@ -60,7 +60,7 @@
if(L.stat == DEAD)
continue
if(light_nutrition_gain)
- L.adjust_nutrition(light_amount * light_nutrition_gain * attached_atoms[AM], NUTRITION_LEVEL_FULL)
+ L.adjust_nutrition(light_amount * light_nutrition_gain * attached_atoms[AM], NUTRITION_LEVEL_WELL_FED)
if(light_amount > bonus_lum || light_amount < malus_lum)
var/mult = ((light_amount > bonus_lum) ? 1 : -1) * attached_atoms[AM]
if(light_bruteheal)
diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm
index dc32902e5e..dc9569a4d5 100644
--- a/code/datums/explosion.dm
+++ b/code/datums/explosion.dm
@@ -196,14 +196,12 @@ GLOBAL_LIST_EMPTY(explosions)
//------- EX_ACT AND TURF FIRES -------
- if(T == epicenter) // Ensures explosives detonating from bags trigger other explosives in that bag
- var/list/items = list()
- for(var/I in T)
- var/atom/A = I
- if (!(A.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
- items += A.GetAllContents()
- for(var/O in items)
- var/atom/A = O
+ if((T == epicenter) && !QDELETED(explosion_source) && ismovable(explosion_source) && (get_turf(explosion_source) == T)) // Ensures explosives detonating from bags trigger other explosives in that bag
+ var/list/atoms = list()
+ for(var/atom/A in explosion_source.loc) // the ismovableatom check 2 lines above makes sure we don't nuke an /area
+ atoms += A
+ for(var/i in atoms)
+ var/atom/A = i
if(!QDELETED(A))
A.ex_act(dist)
diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm
index 0f4f02ae2a..4bf02e8587 100644
--- a/code/datums/holocall.dm
+++ b/code/datums/holocall.dm
@@ -32,20 +32,29 @@
var/datum/action/innate/end_holocall/hangup //hangup action
var/call_start_time
+ var/head_call = FALSE //calls from a head of staff autoconnect, if the receiving pad is not secure.
//creates a holocall made by `caller` from `calling_pad` to `callees`
-/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees)
+/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees, elevated_access = FALSE)
call_start_time = world.time
user = caller
calling_pad.outgoing_call = src
calling_holopad = calling_pad
+ head_call = elevated_access
dialed_holopads = list()
for(var/I in callees)
var/obj/machinery/holopad/H = I
if(!QDELETED(H) && H.is_operational())
dialed_holopads += H
- H.say("Incoming call.")
+ if(head_call)
+ if(H.secure)
+ calling_pad.say("Auto-connection refused, falling back to call mode.")
+ H.say("Incoming call.")
+ else
+ H.say("Incoming connection.")
+ else
+ H.say("Incoming call.")
LAZYADD(H.holo_calls, src)
if(!dialed_holopads.len)
@@ -79,6 +88,7 @@
dialed_holopads.Cut()
if(calling_holopad)
+ calling_holopad.calling = FALSE
calling_holopad.outgoing_call = null
calling_holopad.SetLightsAndPower()
calling_holopad = null
@@ -145,6 +155,7 @@
if(!Check())
return
+ calling_holopad.calling = FALSE
hologram = H.activate_holo(user)
hologram.HC = src
@@ -160,6 +171,8 @@
hangup = new(eye, src)
hangup.Grant(user)
+ playsound(H, 'sound/machines/ping.ogg', 100)
+ H.say("Connection established.")
//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
/datum/holocall/proc/Check()
@@ -178,7 +191,6 @@
. = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME)
if(!.)
calling_holopad.say("No answer received.")
- calling_holopad.temp = ""
if(!.)
testing("Holocall Check fail")
@@ -241,10 +253,10 @@
record.caller_image = holodiskOriginal.record.caller_image
record.entries = holodiskOriginal.record.entries.Copy()
record.language = holodiskOriginal.record.language
- to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!")
+ to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!")
name = holodiskOriginal.name
else
- to_chat(user, "[holodiskOriginal] has no record on it!")
+ to_chat(user, "[holodiskOriginal] has no record on it!")
..()
/obj/item/disk/holodisk/proc/build_record()
@@ -331,6 +343,21 @@
DELAY 20"}
/datum/preset_holoimage/engineer
+ outfit_type = /datum/outfit/job/engineer
+
+/datum/preset_holoimage/engineer/rig
+ outfit_type = /datum/outfit/job/engineer/gloved/rig
+
+/datum/preset_holoimage/engineer/ce
+ outfit_type = /datum/outfit/job/ce
+
+/datum/preset_holoimage/engineer/ce/rig
+ outfit_type = /datum/outfit/job/engineer/gloved/rig
+
+/datum/preset_holoimage/engineer/atmos
+ outfit_type = /datum/outfit/job/atmos
+
+/datum/preset_holoimage/engineer/atmos/rig
outfit_type = /datum/outfit/job/engineer/gloved/rig
/datum/preset_holoimage/researcher
@@ -350,3 +377,90 @@
/datum/preset_holoimage/clown
outfit_type = /datum/outfit/job/clown
+
+/obj/item/disk/holodisk/donutstation/whiteship
+ name = "Blackbox Print-out #DS024"
+ desc = "A holodisk containing the last viable recording of DS024's blackbox."
+ preset_image_type = /datum/preset_holoimage/engineer/ce
+ preset_record_text = {"
+ NAME Geysr Shorthalt
+ SAY Engine renovations complete and the ships been loaded. We all ready?
+ DELAY 25
+ PRESET /datum/preset_holoimage/engineer
+ NAME Jacob Ullman
+ SAY Lets blow this popsicle stand of a station.
+ DELAY 20
+ PRESET /datum/preset_holoimage/engineer/atmos
+ NAME Lindsey Cuffler
+ SAY Uh, sir? Shouldn't we call for a secondary shuttle? The bluespace drive on this thing made an awfully weird noise when we jumped here..
+ DELAY 30
+ PRESET /datum/preset_holoimage/engineer/ce
+ NAME Geysr Shorthalt
+ SAY Pah! Ship techie at the dock said to give it a good few kicks if it started acting up, let me just..
+ DELAY 25
+ SOUND punch
+ SOUND sparks
+ DELAY 10
+ SOUND punch
+ SOUND sparks
+ DELAY 10
+ SOUND punch
+ SOUND sparks
+ SOUND warpspeed
+ DELAY 15
+ PRESET /datum/preset_holoimage/engineer/atmos
+ NAME Lindsey Cuffler
+ SAY Uhh.. is it supposed to be doing that??
+ DELAY 15
+ PRESET /datum/preset_holoimage/engineer/ce
+ NAME Geysr Shorthalt
+ SAY See? Working as intended. Now, are we all ready?
+ DELAY 10
+ PRESET /datum/preset_holoimage/engineer
+ NAME Jacob Ullman
+ SAY Is it supposed to be glowing like that?
+ DELAY 20
+ SOUND explosion
+
+ "}
+
+/obj/item/disk/holodisk/ruin/snowengieruin
+ name = "Blackbox Print-out #EB412"
+ desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it."
+ preset_image_type = /datum/preset_holoimage/engineer
+ preset_record_text = {"
+ NAME Dave Tundrale
+ SAY Maria, how's Build?
+ DELAY 10
+ NAME Maria Dell
+ PRESET /datum/preset_holoimage/engineer/atmos
+ SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator.
+ DELAY 30
+ NAME Dave Tundrale
+ PRESET /datum/preset_holoimage/engineer
+ SAY Aight, wonderful. The science mans been kinda shit though. No RCDs-
+ DELAY 20
+ NAME Maria Dell
+ PRESET /datum/preset_holoimage/engineer/atmos
+ SAY Enough about your RCDs. They're not even that important, just bui-
+ DELAY 15
+ SOUND explosion
+ DELAY 10
+ SAY Oh, shit!
+ DELAY 10
+ PRESET /datum/preset_holoimage/engineer/atmos/rig
+ LANGUAGE /datum/language/narsie
+ NAME Unknown
+ SAY RISE, MY LORD!!
+ DELAY 10
+ LANGUAGE /datum/language/common
+ NAME Plastic
+ PRESET /datum/preset_holoimage/engineer/rig
+ SAY Fuck, fuck, fuck!
+ DELAY 20
+ SAY It's loose! CALL THE FUCKING SHUTT-
+ DELAY 10
+ PRESET /datum/preset_holoimage/corgi
+ NAME Blackbox Automated Message
+ SAY Connection lost. Dumping audio logs to disk.
+ DELAY 50"}
diff --git a/code/datums/http.dm b/code/datums/http.dm
new file mode 100644
index 0000000000..2a9b53f131
--- /dev/null
+++ b/code/datums/http.dm
@@ -0,0 +1,74 @@
+/datum/http_request
+ var/id
+ var/in_progress = FALSE
+
+ var/method
+ var/body
+ var/headers
+ var/url
+
+ var/_raw_response
+
+/datum/http_request/proc/prepare(method, url, body = "", list/headers)
+ if (!length(headers))
+ headers = ""
+ else
+ headers = json_encode(headers)
+
+ src.method = method
+ src.url = url
+ src.body = body
+ src.headers = headers
+
+/datum/http_request/proc/execute_blocking()
+ _raw_response = rustg_http_request_blocking(method, url, body, headers)
+
+/datum/http_request/proc/begin_async()
+ if (in_progress)
+ CRASH("Attempted to re-use a request object.")
+
+ id = rustg_http_request_async(method, url, body, headers)
+
+ if (isnull(text2num(id)))
+ stack_trace("Proc error: [id]")
+ _raw_response = "Proc error: [id]"
+ else
+ in_progress = TRUE
+
+/datum/http_request/proc/is_complete()
+ if (isnull(id))
+ return TRUE
+
+ if (!in_progress)
+ return TRUE
+
+ var/r = rustg_http_check_request(id)
+
+ if (r == RUSTG_JOB_NO_RESULTS_YET)
+ return FALSE
+ else
+ _raw_response = r
+ in_progress = FALSE
+ return TRUE
+
+/datum/http_request/proc/into_response()
+ var/datum/http_response/R = new()
+
+ try
+ var/list/L = json_decode(_raw_response)
+ R.status_code = L["status_code"]
+ R.headers = L["headers"]
+ R.body = L["body"]
+ catch
+ R.errored = TRUE
+ R.error = _raw_response
+
+ return R
+
+/datum/http_response
+ var/status_code
+ var/body
+ var/list/headers
+
+ var/errored = FALSE
+ var/error
diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm
index f110d5e8ed..8bee4f3d1c 100644
--- a/code/datums/looping_sounds/_looping_sound.dm
+++ b/code/datums/looping_sounds/_looping_sound.dm
@@ -60,6 +60,7 @@
output_atoms -= remove_thing
if(init_timerid)
deltimer(init_timerid)
+ init_timerid = null
if(!timerid)
return
on_stop()
diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm
index 8241f685d7..1581323f89 100644
--- a/code/datums/martial/_martial.dm
+++ b/code/datums/martial/_martial.dm
@@ -44,11 +44,11 @@
//Here we roll for our damage to be added into the damage var in the various attack procs. This is changed depending on whether we are in combat mode, lying down, or if our target is in combat mode.
var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
if(SEND_SIGNAL(D, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- damage *= 1.5
+ damage *= 1.2
if(!CHECK_MOBILITY(A, MOBILITY_STAND))
- damage *= 0.5
+ damage *= 0.7
if(SEND_SIGNAL(A, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- damage *= 0.25
+ damage *= 0.8
return damage
/datum/martial_art/proc/teach(mob/living/carbon/human/H, make_temporary = FALSE)
diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm
index c2fe24a20d..3691b2fccc 100644
--- a/code/datums/martial/krav_maga.dm
+++ b/code/datums/martial/krav_maga.dm
@@ -223,8 +223,8 @@
/obj/item/clothing/gloves/krav_maga/combatglovesplus
name = "combat gloves plus"
desc = "These tactical gloves are fireproof and shock resistant, and using nanochip technology it teaches you the powers of krav maga."
- icon_state = "combat"
- item_state = "blackgloves"
+ icon_state = "fightglovesblack"
+ item_state = "fightglovesblack"
siemens_coefficient = 0
permeability_coefficient = 0.05
strip_delay = 80
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index a2a9e376e1..7d884344f1 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -44,7 +44,7 @@
else
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, TRUE, -1)
log_combat(A, D, "strong punched (Sleeping Carp)")//so as to not double up on logging
- D.apply_damage((damage + 15) + crit_damage, BRUTE, affecting)
+ D.apply_damage((damage + 15) + crit_damage, BRUTE, affecting, wound_bonus = CANT_WOUND)
return TRUE
///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards
@@ -56,7 +56,7 @@
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
var/atom/throw_target = get_edge_target_turf(D, A.dir)
D.throw_at(throw_target, 7, 14, A)
- D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
+ D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST, wound_bonus = CANT_WOUND, wound_bonus = CANT_WOUND)
log_combat(A, D, "launchkicked (Sleeping Carp)")
return TRUE
@@ -66,14 +66,14 @@
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
if((D.mobility_flags & MOBILITY_STAND))
- D.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
+ D.apply_damage(damage, BRUTE, BODY_ZONE_HEAD, wound_bonus = CANT_WOUND)
D.DefaultCombatKnockdown(50, override_hardstun = 0.01, override_stamdmg = 0)
- D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD) //A cit specific change form the tg port to really punish anyone who tries to stand up
+ D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD, wound_bonus = CANT_WOUND) //A cit specific change form the tg port to really punish anyone who tries to stand up
D.visible_message("[A] kicks [D] in the head, sending them face first into the floor!", \
"You are kicked in the head by [A], sending you crashing to the floor!", "You hear a sickening sound of flesh hitting flesh!", COMBAT_MESSAGE_RANGE, A)
else
- D.apply_damage(damage*0.5, BRUTE, BODY_ZONE_HEAD)
- D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD)
+ D.apply_damage(damage*0.5, BRUTE, BODY_ZONE_HEAD, wound_bonus = CANT_WOUND)
+ D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD, wound_bonus = CANT_WOUND)
D.drop_all_held_items()
D.visible_message("[A] kicks [D] in the head!", \
"You are kicked in the head by [A]!", "You hear a sickening sound of flesh hitting flesh!", COMBAT_MESSAGE_RANGE, A)
@@ -99,7 +99,7 @@
D.visible_message("[A] [atk_verb]s [D]!", \
"[A] [atk_verb]s you!", null, null, A)
to_chat(A, "You [atk_verb] [D]!")
- D.apply_damage(damage, BRUTE, affecting)
+ D.apply_damage(damage, BRUTE, affecting, wound_bonus = CANT_WOUND)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, TRUE, -1)
if(CHECK_MOBILITY(D, MOBILITY_STAND) && damage >= stunthreshold)
to_chat(D, "You stumble and fall!")
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index d02249fb38..cb99fdc5a3 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -66,6 +66,9 @@
/// Our skill holder.
var/datum/skill_holder/skill_holder
+ ///What character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not
+ var/mob/original_character
+
/datum/mind/New(var/key)
skill_holder = new(src)
src.key = key
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index f5692c297a..787d6375a7 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -77,10 +77,14 @@
description = "Pull it out!\n"
mood_change = -7
-/datum/mood_event/table
- description = "Someone threw me on a table!\n"
- mood_change = -2
- timeout = 2 MINUTES
+/datum/mood_event/table_limbsmash
+ description = "That fucking table, man that hurts...\n"
+ mood_change = -3
+ timeout = 3 MINUTES
+
+/datum/mood_event/table_limbsmash/add_effects(obj/item/bodypart/banged_limb)
+ if(banged_limb)
+ description = "My fucking [banged_limb.name], man that hurts...\n"
/datum/mood_event/table/add_effects()
if(ishuman(owner))
@@ -270,3 +274,13 @@
description = "I've produced better art than that from my ass.\n"
mood_change = -2
timeout = 1200
+
+/datum/mood_event/tripped
+ description = "I can't believe I fell for the oldest trick in the book!\n"
+ mood_change = -6
+ timeout = 2 MINUTES
+
+/datum/mood_event/untied
+ description = "I hate when my shoes come untied!\n"
+ mood_change = -3
+ timeout = 1 MINUTES
diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm
index 95177f6869..8f98917ed3 100644
--- a/code/datums/mood_events/generic_positive_events.dm
+++ b/code/datums/mood_events/generic_positive_events.dm
@@ -196,3 +196,7 @@
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
+
+/datum/mood_event/cleared_stomach
+ description = "Feels nice to get that out of the way!\n"
+ mood_change = 3
diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm
index 962681eb94..b307bcb0aa 100644
--- a/code/datums/mood_events/needs_events.dm
+++ b/code/datums/mood_events/needs_events.dm
@@ -19,6 +19,27 @@
description = "I'm starving!\n"
mood_change = -15
+//charge
+/datum/mood_event/supercharged
+ description = "I can't possibly keep all this power inside, I need to release some quick!\n"
+ mood_change = -10
+
+/datum/mood_event/overcharged
+ description = "I feel dangerously overcharged, perhaps I should release some power.\n"
+ mood_change = -4
+
+/datum/mood_event/charged
+ description = "I feel the power in my veins!\n"
+ mood_change = 6
+
+/datum/mood_event/lowpower
+ description = "My power is running low, I should go charge up somewhere.\n"
+ mood_change = -6
+
+/datum/mood_event/decharged
+ description = "I'm in desperate need of some electricity!\n"
+ mood_change = -10
+
//Disgust
/datum/mood_event/gross
description = "I saw something gross.\n"
diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm
index 7e6d567cfa..bd9ecaeeaa 100644
--- a/code/datums/mutations/actions.dm
+++ b/code/datums/mutations/actions.dm
@@ -410,7 +410,7 @@
throw_speed = 4
embedding = list("embedded_pain_multiplier" = 4, "embed_chance" = 100, "embedded_fall_chance" = 0)
w_class = WEIGHT_CLASS_SMALL
- sharpness = IS_SHARP
+ sharpness = SHARP_POINTY
var/mob/living/carbon/human/fired_by
/// if we missed our target
var/missed = TRUE
diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm
index 2df2b20cbc..5d363124d9 100644
--- a/code/datums/mutations/hulk.dm
+++ b/code/datums/mutations/hulk.dm
@@ -21,7 +21,29 @@
/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags)
if(proximity && (act_intent == INTENT_HARM)) //no telekinetic hulk attack
- return target.attack_hulk(owner)
+ if(!owner.CheckActionCooldown(CLICK_CD_MELEE))
+ return INTERRUPT_UNARMED_ATTACK | NO_AUTO_CLICKDELAY_HANDLING
+ owner.DelayNextAction()
+ target.attack_hulk(owner)
+ return INTERRUPT_UNARMED_ATTACK | NO_AUTO_CLICKDELAY_HANDLING
+
+/**
+ *Checks damage of a hulk's arm and applies bone wounds as necessary.
+ *
+ *Called by specific atoms being attacked, such as walls. If an atom
+ *does not call this proc, than punching that atom will not cause
+ *arm breaking (even if the atom deals recoil damage to hulks).
+ *Arguments:
+ *arg1 is the arm to evaluate damage of and possibly break.
+ */
+/datum/mutation/human/hulk/proc/break_an_arm(obj/item/bodypart/arm)
+ switch(arm.brute_dam)
+ if(45 to 50)
+ arm.force_wound_upwards(/datum/wound/blunt/critical)
+ if(41 to 45)
+ arm.force_wound_upwards(/datum/wound/blunt/severe)
+ if(35 to 41)
+ arm.force_wound_upwards(/datum/wound/blunt/moderate)
/datum/mutation/human/hulk/on_life()
if(owner.health < 0)
diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm
index fe018a8761..8dc3b64e16 100644
--- a/code/datums/radiation_wave.dm
+++ b/code/datums/radiation_wave.dm
@@ -105,7 +105,6 @@
// modify the ignored_things list in __HELPERS/radiation.dm instead
var/static/list/blacklisted = typecacheof(list(
/turf,
- /mob,
/obj/structure/cable,
/obj/machinery/atmospherics,
/obj/item/ammo_casing,
diff --git a/code/datums/skills/_check_skills.dm b/code/datums/skills/_check_skills.dm
index 41939dbee3..91b36a123f 100644
--- a/code/datums/skills/_check_skills.dm
+++ b/code/datums/skills/_check_skills.dm
@@ -14,11 +14,14 @@
mind.skill_holder.ui_interact(src)
-/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/skill_holder/ui_state(mob/user)
+ return GLOB.always_state
+
+/datum/skill_holder/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "SkillPanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
- ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
+ ui = new(user, src, "SkillPanel", "[owner.name]'s Skills")
+ ui.set_autoupdate(FALSE)
ui.open()
else if(need_static_data_update)
update_static_data(user)
diff --git a/code/datums/spawners_menu.dm b/code/datums/spawners_menu.dm
index d66445b8a1..95a7d8e633 100644
--- a/code/datums/spawners_menu.dm
+++ b/code/datums/spawners_menu.dm
@@ -6,10 +6,13 @@
qdel(src)
owner = new_owner
-/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/spawners_menu/ui_state(mob/user)
+ return GLOB.observer_state
+
+/datum/spawners_menu/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state)
+ ui = new(user, src, "SpawnersMenu")
ui.open()
/datum/spawners_menu/ui_data(mob/user)
@@ -42,11 +45,15 @@
if(..())
return
- var/spawner_ref = pick(GLOB.mob_spawners[params["name"]])
- var/obj/effect/mob_spawn/MS = locate(spawner_ref) in GLOB.poi_list
- if(!MS)
+ var/group_name = params["name"]
+ if(!group_name || !(group_name in GLOB.mob_spawners))
+ return
+ var/list/spawnerlist = GLOB.mob_spawners[group_name]
+ if(!spawnerlist.len)
+ return
+ var/obj/effect/mob_spawn/MS = pick(spawnerlist)
+ if(!istype(MS) || !(MS in GLOB.poi_list))
return
-
switch(action)
if("jump")
if(MS)
@@ -55,4 +62,4 @@
if("spawn")
if(MS)
MS.attack_ghost(owner)
- . = TRUE
\ No newline at end of file
+ . = TRUE
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index e080e597a3..179ed765c5 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -441,6 +441,10 @@
owner.adjustBruteLoss(-10, FALSE)
owner.adjustFireLoss(-5, FALSE)
owner.adjustOxyLoss(-10)
+ if(!iscarbon(owner))
+ return
+ var/mob/living/carbon/C = owner
+ QDEL_LIST(C.all_scars)
/obj/screen/alert/status_effect/fleshmend
name = "Fleshmend"
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index faed65e9c4..6e59d4fa2c 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -97,6 +97,21 @@
duration = set_duration
return ..()
+/datum/status_effect/off_balance
+ id = "offbalance"
+ alert_type = null
+
+/datum/status_effect/off_balance/on_creation(mob/living/new_owner, set_duration)
+ if(isnum(set_duration))
+ duration = set_duration
+ return ..()
+
+/datum/status_effect/off_balance/on_remove()
+ var/active_item = owner.get_active_held_item()
+ if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
+ owner.visible_message("[owner.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE)
+ return ..()
+
/obj/screen/alert/status_effect/asleep
name = "Asleep"
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
@@ -144,7 +159,6 @@
id = "tased"
alert_type = null
var/movespeed_mod = /datum/movespeed_modifier/status_effect/tased
- var/nextmove_modifier = 1
var/stamdmg_per_ds = 0 //a 20 duration would do 20 stamdmg, disablers do 24 or something
var/last_tick = 0 //fastprocess processing speed is a goddamn sham, don't trust it.
@@ -173,13 +187,9 @@
C.adjustStaminaLoss(max(0, stamdmg_per_ds * diff)) //if you really want to try to stamcrit someone with a taser alone, you can, but it'll take time and good timing.
last_tick = world.time
-/datum/status_effect/electrode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y
- return nextmove_modifier
-
/datum/status_effect/electrode/no_combat_mode
id = "tased_strong"
movespeed_mod = /datum/movespeed_modifier/status_effect/tased/no_combat_mode
- nextmove_modifier = 2
blocks_combatmode = TRUE
stamdmg_per_ds = 1
@@ -430,10 +440,19 @@
/datum/status_effect/neck_slice/tick()
var/mob/living/carbon/human/H = owner
- if(H.stat == DEAD || H.bleed_rate <= 8)
+ var/obj/item/bodypart/throat = H.get_bodypart(BODY_ZONE_HEAD)
+ if(H.stat == DEAD || !throat)
H.remove_status_effect(/datum/status_effect/neck_slice)
if(prob(10))
H.emote(pick("gasp", "gag", "choke"))
+ var/still_bleeding = FALSE
+ for(var/thing in throat.wounds)
+ var/datum/wound/W = thing
+ if(W.wound_type == WOUND_SLASH && W.severity > WOUND_SEVERITY_MODERATE)
+ still_bleeding = TRUE
+ break
+ if(!still_bleeding)
+ H.remove_status_effect(/datum/status_effect/neck_slice)
/mob/living/proc/apply_necropolis_curse(set_curse, duration = 10 MINUTES)
var/datum/status_effect/necropolis_curse/C = has_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE)
@@ -543,8 +562,8 @@
owner.DefaultCombatKnockdown(15, TRUE, FALSE, 15)
if(iscarbon(owner))
var/mob/living/carbon/C = owner
- C.silent = max(2, C.silent)
- C.stuttering = max(5, C.stuttering)
+ C.silent = max(5, C.silent) //Increased, now lasts until five seconds after it ends, instead of 2
+ C.stuttering = max(10, C.stuttering) //Increased, now lasts for five seconds after the mute ends, instead of 3
if(!old_health)
old_health = owner.health
if(!old_oxyloss)
diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm
index 12c223f500..461ae9c65d 100644
--- a/code/datums/status_effects/status_effect.dm
+++ b/code/datums/status_effects/status_effect.dm
@@ -90,13 +90,12 @@
return
duration = world.time + original_duration
-//clickdelay/nextmove modifiers!
-/datum/status_effect/proc/nextmove_modifier()
+/**
+ * Multiplied to clickdelays
+ */
+/datum/status_effect/proc/action_cooldown_mod()
return 1
-/datum/status_effect/proc/nextmove_adjust()
- return 0
-
////////////////
// ALERT HOOK //
////////////////
@@ -279,3 +278,7 @@
/datum/status_effect/grouped/before_remove(source)
sources -= source
return !length(sources)
+
+//do_after modifier!
+/datum/status_effect/proc/interact_speed_modifier()
+ return 1
diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm
new file mode 100644
index 0000000000..045b1b257d
--- /dev/null
+++ b/code/datums/status_effects/wound_effects.dm
@@ -0,0 +1,197 @@
+
+// The shattered remnants of your broken limbs fill you with determination!
+/obj/screen/alert/status_effect/determined
+ name = "Determined"
+ desc = "The serious wounds you've sustained have put your body into fight-or-flight mode! Now's the time to look for an exit!"
+ icon_state = "regenerative_core"
+
+/datum/status_effect/determined
+ id = "determined"
+ alert_type = /obj/screen/alert/status_effect/determined
+
+/datum/status_effect/determined/on_apply()
+ . = ..()
+ owner.visible_message("[owner] grits [owner.p_their()] teeth in pain!", "Your senses sharpen as your body tenses up from the wounds you've sustained!", vision_distance=COMBAT_MESSAGE_RANGE)
+
+/datum/status_effect/determined/on_remove()
+ owner.visible_message("[owner]'s body slackens noticeably!", "Your adrenaline rush dies off, and the pain from your wounds come aching back in...", vision_distance=COMBAT_MESSAGE_RANGE)
+ return ..()
+
+/datum/status_effect/limp
+ id = "limp"
+ status_type = STATUS_EFFECT_REPLACE
+ tick_interval = 10
+ alert_type = /obj/screen/alert/status_effect/limp
+ var/msg_stage = 0//so you dont get the most intense messages immediately
+ /// The left leg of the limping person
+ var/obj/item/bodypart/l_leg/left
+ /// The right leg of the limping person
+ var/obj/item/bodypart/r_leg/right
+ /// Which leg we're limping with next
+ var/obj/item/bodypart/next_leg
+ /// How many deciseconds we limp for on the left leg
+ var/slowdown_left = 0
+ /// How many deciseconds we limp for on the right leg
+ var/slowdown_right = 0
+
+/datum/status_effect/limp/on_apply()
+ if(!iscarbon(owner))
+ return FALSE
+ var/mob/living/carbon/C = owner
+ left = C.get_bodypart(BODY_ZONE_L_LEG)
+ right = C.get_bodypart(BODY_ZONE_R_LEG)
+ update_limp()
+ RegisterSignal(C, COMSIG_MOVABLE_MOVED, .proc/check_step)
+ RegisterSignal(C, list(COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB), .proc/update_limp)
+ return ..()
+
+/datum/status_effect/limp/on_remove()
+ UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB))
+ return ..()
+
+/obj/screen/alert/status_effect/limp
+ name = "Limping"
+ desc = "One or more of your legs has been wounded, slowing down steps with that leg! Get it fixed, or at least splinted!"
+
+/datum/status_effect/limp/proc/check_step(mob/whocares, OldLoc, Dir, forced)
+ if(!owner.client || !(owner.mobility_flags & MOBILITY_STAND) || !owner.has_gravity() || (owner.movement_type & FLYING) || forced)
+ return
+ var/determined_mod = 1
+ if(owner.has_status_effect(STATUS_EFFECT_DETERMINED))
+ determined_mod = 0.25
+ if(next_leg == left)
+ owner.client.move_delay += slowdown_left * determined_mod
+ next_leg = right
+ else
+ owner.client.move_delay += slowdown_right * determined_mod
+ next_leg = left
+
+/datum/status_effect/limp/proc/update_limp()
+ var/mob/living/carbon/C = owner
+ left = C.get_bodypart(BODY_ZONE_L_LEG)
+ right = C.get_bodypart(BODY_ZONE_R_LEG)
+
+ if(!left && !right)
+ C.remove_status_effect(src)
+ return
+
+ slowdown_left = 0
+ slowdown_right = 0
+
+ if(left)
+ for(var/thing in left.wounds)
+ var/datum/wound/W = thing
+ slowdown_left += W.limp_slowdown
+
+ if(right)
+ for(var/thing in right.wounds)
+ var/datum/wound/W = thing
+ slowdown_right += W.limp_slowdown
+
+ // this handles losing your leg with the limp and the other one being in good shape as well
+ if(!slowdown_left && !slowdown_right)
+ C.remove_status_effect(src)
+ return
+
+
+/////////////////////////
+//////// WOUNDS /////////
+/////////////////////////
+
+// wound alert
+/obj/screen/alert/status_effect/wound
+ name = "Wounded"
+ desc = "Your body has sustained serious damage, click here to inspect yourself."
+
+/obj/screen/alert/status_effect/wound/Click()
+ var/mob/living/carbon/C = usr
+ C.check_self_for_injuries()
+
+// wound status effect base
+/datum/status_effect/wound
+ id = "wound"
+ status_type = STATUS_EFFECT_MULTIPLE
+ var/obj/item/bodypart/linked_limb
+ var/datum/wound/linked_wound
+ alert_type = NONE
+
+/datum/status_effect/wound/on_creation(mob/living/new_owner, incoming_wound)
+ . = ..()
+ linked_wound = incoming_wound
+ linked_limb = linked_wound.limb
+
+/datum/status_effect/wound/on_remove()
+ linked_wound = null
+ linked_limb = null
+ UnregisterSignal(owner, COMSIG_CARBON_LOSE_WOUND)
+ return ..()
+
+/datum/status_effect/wound/on_apply()
+ if(!iscarbon(owner))
+ return FALSE
+ RegisterSignal(owner, COMSIG_CARBON_LOSE_WOUND, .proc/check_remove)
+ return ..()
+
+/// check if the wound getting removed is the wound we're tied to
+/datum/status_effect/wound/proc/check_remove(mob/living/L, datum/wound/W)
+ if(W == linked_wound)
+ qdel(src)
+
+
+// bones
+/datum/status_effect/wound/blunt
+
+/datum/status_effect/wound/blunt/interact_speed_modifier()
+ var/mob/living/carbon/C = owner
+
+ if(C.get_active_hand() == linked_limb)
+ to_chat(C, "The [lowertext(linked_wound)] in your [linked_limb.name] slows your progress!")
+ return linked_wound.interaction_efficiency_penalty
+
+ return 1
+
+/datum/status_effect/wound/blunt/action_cooldown_mod()
+ var/mob/living/carbon/C = owner
+
+ if(C.get_active_hand() == linked_limb)
+ return linked_wound.interaction_efficiency_penalty
+
+ return 1
+
+/datum/status_effect/wound/blunt/moderate
+ id = "disjoint"
+/datum/status_effect/wound/blunt/severe
+ id = "hairline"
+
+/datum/status_effect/wound/blunt/critical
+ id = "compound"
+
+// cuts
+/datum/status_effect/wound/slash/moderate
+ id = "abrasion"
+
+/datum/status_effect/wound/slash/severe
+ id = "laceration"
+
+/datum/status_effect/wound/slash/critical
+ id = "avulsion"
+
+// pierce
+/datum/status_effect/wound/pierce/moderate
+ id = "breakage"
+
+/datum/status_effect/wound/pierce/severe
+ id = "puncture"
+
+/datum/status_effect/wound/pierce/critical
+ id = "rupture"
+
+// burns
+/datum/status_effect/wound/burn/moderate
+ id = "seconddeg"
+
+/datum/status_effect/wound/burn/severe
+ id = "thirddeg"
+
+/datum/status_effect/wound/burn/critical
+ id = "fourthdeg"
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index 8f902fa088..68b5d6f987 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -14,7 +14,7 @@
if(NOBLOOD in H.dna.species.species_traits) //can't lose blood if your species doesn't have any
return
else
- quirk_holder.blood_volume -= 0.275
+ quirk_holder.blood_volume -= 0.2
/datum/quirk/depression
name = "Depression"
@@ -54,9 +54,9 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
if("Botanist")
heirloom_type = pick(/obj/item/cultivator, /obj/item/reagent_containers/glass/bucket, /obj/item/storage/bag/plants, /obj/item/toy/plush/beeplushie)
if("Medical Doctor")
- heirloom_type = /obj/item/healthanalyzer/advanced
+ heirloom_type = /obj/item/healthanalyzer
if("Paramedic")
- heirloom_type = pick(/obj/item/clothing/neck/stethoscope, /obj/item/bodybag)
+ heirloom_type = /obj/item/lighter
if("Station Engineer")
heirloom_type = /obj/item/wirecutters/brass
if("Atmospheric Technician")
@@ -337,10 +337,8 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
dumb_thing = FALSE //only once per life
if(prob(1))
new/obj/item/reagent_containers/food/snacks/pastatomato(get_turf(H)) //now that's what I call spaghetti code
+
// small chance to make eye contact with inanimate objects/mindless mobs because of nerves
-
-
-
/datum/quirk/social_anxiety/proc/looks_at_floor(datum/source, atom/A)
var/mob/living/mind_check = A
if(prob(85) || (istype(mind_check) && mind_check.mind))
@@ -452,8 +450,8 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
mob_trait = TRAIT_COLDBLOODED
gain_text = "You feel cold-blooded."
lose_text = "You feel more warm-blooded."
-
- /datum/quirk/monophobia
+
+/datum/quirk/monophobia
name = "Monophobia"
desc = "You will become increasingly stressed when not in company of others, triggering panic reactions ranging from sickness to heart attacks."
value = -3 // Might change it to 4.
diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm
index 4b039aa1b5..e92564a3b4 100644
--- a/code/datums/traits/neutral.dm
+++ b/code/datums/traits/neutral.dm
@@ -122,3 +122,19 @@
if(H)
var/datum/species/species = H.dna.species
species.disliked_food &= ~ALCOHOL
+
+/datum/quirk/longtimer
+ name = "Longtimer"
+ desc = "You've been around for a long time and seen more than your fair share of action, suffering some pretty nasty scars along the way. For whatever reason, you've declined to get them removed or augmented."
+ value = 0
+ gain_text = "Your body has seen better days."
+ lose_text = "Your sins may wash away, but those scars are here to stay..."
+ medical_record_text = "Patient has withstood significant physical trauma and declined plastic surgery procedures to heal scarring."
+ /// the minimum amount of scars we can generate
+ var/min_scars = 3
+ /// the maximum amount of scars we can generate
+ var/max_scars = 7
+
+/datum/quirk/longtimer/on_spawn()
+ var/mob/living/carbon/C = quirk_holder
+ C.generate_fake_scars(rand(min_scars, max_scars))
diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm
index 75bd4f5c17..04fbc4a590 100644
--- a/code/datums/wires/_wires.dm
+++ b/code/datums/wires/_wires.dm
@@ -97,6 +97,12 @@
/datum/wires/proc/get_wire(color)
return colors[color]
+/datum/wires/proc/get_color_of_wire(wire_type)
+ for(var/color in colors)
+ var/other_type = colors[color]
+ if(wire_type == other_type)
+ return color
+
/datum/wires/proc/get_attached(color)
if(assemblies[color])
return assemblies[color]
@@ -117,7 +123,7 @@
return TRUE
/datum/wires/proc/is_dud(wire)
- return findtext(wire, WIRE_DUD_PREFIX)
+ return findtext(wire, WIRE_DUD_PREFIX, 1, length(WIRE_DUD_PREFIX) + 1)
/datum/wires/proc/is_dud_color(color)
return is_dud(get_wire(color))
@@ -197,6 +203,7 @@
S.forceMove(holder.drop_location())
return S
+/// Called from [/atom/proc/emp_act]
/datum/wires/proc/emp_pulse()
var/list/possible_wires = shuffle(wires)
var/remaining_pulses = MAXIMUM_EMP_WIRES
@@ -239,11 +246,13 @@
return ..()
return UI_CLOSE
-/datum/wires/ui_interact(mob/user, ui_key = "wires", 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)
+/datum/wires/ui_state(mob/user)
+ return GLOB.physical_state
+
+/datum/wires/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
- ui = new(user, src, ui_key, "Wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state)
+ ui = new(user, src, "Wires", "[holder.name] Wires")
ui.open()
/datum/wires/ui_data(mob/user)
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index 2b13344cc6..6cef7ac50f 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -53,11 +53,10 @@
/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
- if(!A.panel_open)
- return FALSE
if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100))
return FALSE
- return TRUE
+ if(A.panel_open)
+ return TRUE
/datum/wires/airlock/get_status()
var/obj/machinery/door/airlock/A = holder
@@ -115,10 +114,7 @@
A.aiControlDisabled = -1
if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks.
if(!A.secondsElectrified)
- A.set_electrified(30)
- if(usr)
- LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]"))
- log_combat(usr, A, "electrified")
+ A.set_electrified(30, usr)
if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
@@ -135,21 +131,17 @@
if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power.
if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2))
A.regainMainPower()
- if(usr)
- A.shock(usr, 50)
else
A.loseMainPower()
- if(usr)
- A.shock(usr, 50)
+ if(isliving(usr))
+ A.shock(usr, 50)
if(WIRE_BACKUP1, WIRE_BACKUP2) // Cut to loose backup power, repair all to gain backup power.
if(mend && !is_cut(WIRE_BACKUP1) && !is_cut(WIRE_BACKUP2))
A.regainBackupPower()
- if(usr)
- A.shock(usr, 50)
else
A.loseBackupPower()
- if(usr)
- A.shock(usr, 50)
+ if(isliving(usr))
+ A.shock(usr, 50)
if(WIRE_BOLTS) // Cut to drop bolts, mend does nothing.
if(!mend)
A.bolt()
@@ -170,10 +162,7 @@
A.set_electrified(0)
else
if(A.secondsElectrified != -1)
- A.set_electrified(-1)
- if(usr)
- LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]"))
- log_combat(usr, A, "electrified")
+ A.set_electrified(-1, usr)
if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable.
A.safe = mend
if(WIRE_TIMING) // Cut to disable auto-close, mend to re-enable.
@@ -184,5 +173,5 @@
A.lights = mend
A.update_icon()
if(WIRE_ZAP1, WIRE_ZAP2) // Ouch.
- if(usr)
- A.shock(usr, 50)
+ if(isliving(usr))
+ A.shock(usr, 50)
\ No newline at end of file
diff --git a/code/datums/wounds/_scars.dm b/code/datums/wounds/_scars.dm
new file mode 100644
index 0000000000..8cd0d8a047
--- /dev/null
+++ b/code/datums/wounds/_scars.dm
@@ -0,0 +1,152 @@
+/**
+ * scars are cosmetic datums that are assigned to bodyparts once they recover from wounds. Each wound type and severity have their own descriptions for what the scars
+ * look like, and then each body part has a list of "specific locations" like your elbow or wrist or wherever the scar can appear, to make it more interesting than "right arm"
+ *
+ *
+ * Arguments:
+ * *
+ */
+/datum/scar
+ var/obj/item/bodypart/limb
+ var/mob/living/carbon/victim
+ var/severity
+ var/description
+ var/precise_location
+
+ /// Scars from the longtimer quirk are "fake" and won't be saved with persistent scarring, since it makes you spawn with a lot by default
+ var/fake=FALSE
+
+ /// How many tiles away someone can see this scar, goes up with severity. Clothes covering this limb will decrease visibility by 1 each, except for the head/face which is a binary "is mask obscuring face" check
+ var/visibility = 2
+ /// Whether this scar can actually be covered up by clothing
+ var/coverable = TRUE
+ /// What zones this scar can be applied to
+ var/list/applicable_zones = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG)
+
+/datum/scar/Destroy(force, ...)
+ if(limb)
+ LAZYREMOVE(limb.scars, src)
+ if(victim)
+ LAZYREMOVE(victim.all_scars, src)
+ . = ..()
+
+/**
+ * generate() is used to actually fill out the info for a scar, according to the limb and wound it is provided.
+ *
+ * After creating a scar, call this on it while targeting the scarred bodypart with a given wound to apply the scar.
+ *
+ * Arguments:
+ * * BP- The bodypart being targeted
+ * * W- The wound being used to generate the severity and description info
+ * * add_to_scars- Should always be TRUE unless you're just storing a scar for later usage, like how cuts want to store a scar for the highest severity of cut, rather than the severity when the wound is fully healed (probably demoted to moderate)
+ */
+/datum/scar/proc/generate(obj/item/bodypart/BP, datum/wound/W, add_to_scars=TRUE)
+ if(!(BP.body_zone in applicable_zones))
+ qdel(src)
+ return
+ limb = BP
+ severity = W.severity
+ if(limb.owner)
+ victim = limb.owner
+ if(add_to_scars)
+ LAZYADD(limb.scars, src)
+ if(victim)
+ LAZYADD(victim.all_scars, src)
+
+ if(victim && victim.get_biological_state() == BIO_JUST_BONE)
+ description = pick(strings(BONE_SCAR_FILE, W.scar_keyword)) || "general disfigurement"
+ else
+ description = pick(strings(FLESH_SCAR_FILE, W.scar_keyword)) || "general disfigurement"
+
+ precise_location = pick(strings(SCAR_LOC_FILE, limb.body_zone))
+ switch(W.severity)
+ if(WOUND_SEVERITY_MODERATE)
+ visibility = 2
+ if(WOUND_SEVERITY_SEVERE)
+ visibility = 3
+ if(WOUND_SEVERITY_CRITICAL)
+ visibility = 5
+ if(WOUND_SEVERITY_LOSS)
+ visibility = 7
+ precise_location = "amputation"
+
+/// Used when we finalize a scar from a healing cut
+/datum/scar/proc/lazy_attach(obj/item/bodypart/BP, datum/wound/W)
+ LAZYADD(BP.scars, src)
+ if(BP.owner)
+ victim = BP.owner
+ LAZYADD(victim.all_scars, src)
+
+/// Used to "load" a persistent scar
+/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE)
+ if(!(BP.body_zone in applicable_zones) || !BP.is_organic_limb())
+ qdel(src)
+ return
+
+ limb = BP
+ src.severity = severity
+ LAZYADD(limb.scars, src)
+ if(BP.owner)
+ victim = BP.owner
+ LAZYADD(victim.all_scars, src)
+ src.description = description
+ precise_location = specific_location
+ switch(severity)
+ if(WOUND_SEVERITY_MODERATE)
+ visibility = 2
+ if(WOUND_SEVERITY_SEVERE)
+ visibility = 3
+ if(WOUND_SEVERITY_CRITICAL)
+ visibility = 5
+ if(WOUND_SEVERITY_LOSS)
+ visibility = 7
+ return TRUE
+
+/// What will show up in examine_more() if this scar is visible
+/datum/scar/proc/get_examine_description(mob/viewer)
+ if(!victim || !is_visible(viewer))
+ return
+
+ var/msg = "[victim.p_they(TRUE)] [victim.p_have()] [description] on [victim.p_their()] [precise_location]."
+ switch(severity)
+ if(WOUND_SEVERITY_MODERATE)
+ msg = "[msg]"
+ if(WOUND_SEVERITY_SEVERE)
+ msg = "[msg]"
+ if(WOUND_SEVERITY_CRITICAL)
+ msg = "[msg]"
+ if(WOUND_SEVERITY_LOSS)
+ msg = "[victim.p_their(TRUE)] [limb.name] [description]." // different format
+ msg = "[msg]"
+ return "\t[msg]"
+
+/// Whether a scar can currently be seen by the viewer
+/datum/scar/proc/is_visible(mob/viewer)
+ if(!victim || !viewer)
+ return
+ if(get_dist(viewer, victim) > visibility)
+ return
+
+ if(!ishuman(victim) || isobserver(viewer) || victim == viewer)
+ return TRUE
+
+ var/mob/living/carbon/human/human_victim = victim
+ if(istype(limb, /obj/item/bodypart/head))
+ if((human_victim.wear_mask && (human_victim.wear_mask.flags_inv & HIDEFACE)) || (human_victim.head && (human_victim.head.flags_inv & HIDEFACE)))
+ return FALSE
+ else if(limb.scars_covered_by_clothes)
+ var/num_covers = LAZYLEN(human_victim.clothingonpart(limb))
+ if(num_covers + get_dist(viewer, victim) >= visibility)
+ return FALSE
+
+ return TRUE
+
+/// Used to format a scar to safe in preferences for persistent scars
+/datum/scar/proc/format()
+ if(!fake)
+ return "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]"
+
+/// Used to format a scar to safe in preferences for persistent scars
+/datum/scar/proc/format_amputated(body_zone)
+ description = pick(list("is several skintone shades paler than the rest of the body", "is a gruesome patchwork of artificial flesh", "has a large series of attachment scars at the articulation points"))
+ return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]"
\ No newline at end of file
diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm
new file mode 100644
index 0000000000..29c87b32d4
--- /dev/null
+++ b/code/datums/wounds/_wounds.dm
@@ -0,0 +1,327 @@
+/*
+ Wounds are specific medical complications that can arise and be applied to (currently) carbons, with a focus on humans. All of the code for and related to this is heavily WIP,
+ and the documentation will be slanted towards explaining what each part/piece is leading up to, until such a time as I finish the core implementations. The original design doc
+ can be found at https://hackmd.io/@Ryll/r1lb4SOwU
+
+ Wounds are datums that operate like a mix of diseases, brain traumas, and components, and are applied to a /obj/item/bodypart (preferably attached to a carbon) when they take large spikes of damage
+ or under other certain conditions (thrown hard against a wall, sustained exposure to plasma fire, etc). Wounds are categorized by the three following criteria:
+ 1. Severity: Either MODERATE, SEVERE, or CRITICAL. See the hackmd for more details
+ 2. Viable zones: What body parts the wound is applicable to. Generic wounds like broken bones and severe burns can apply to every zone, but you may want to add special wounds for certain limbs
+ like a twisted ankle for legs only, or open air exposure of the organs for particularly gruesome chest wounds. Wounds should be able to function for every zone they are marked viable for.
+ 3. Damage type: Currently either BRUTE or BURN. Again, see the hackmd for a breakdown of my plans for each type.
+
+ When a body part suffers enough damage to get a wound, the severity (determined by a roll or something, worse damage leading to worse wounds), affected limb, and damage type sustained are factored into
+ deciding what specific wound will be applied. I'd like to have a few different types of wounds for at least some of the choices, but I'm just doing rough generals for now. Expect polishing
+*/
+
+/datum/wound
+ /// What it's named
+ var/name = "ouchie"
+ /// The description shown on the scanners
+ var/desc = ""
+ /// The basic treatment suggested by health analyzers
+ var/treat_text = ""
+ /// What the limb looks like on a cursory examine
+ var/examine_desc = "is badly hurt"
+
+ /// needed for "your arm has a compound fracture" vs "your arm has some third degree burns"
+ var/a_or_from = "a"
+ /// The visible message when this happens
+ var/occur_text = ""
+ /// This sound will be played upon the wound being applied
+ var/sound_effect
+
+ /// Either WOUND_SEVERITY_TRIVIAL (meme wounds like stubbed toe), WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, or WOUND_SEVERITY_CRITICAL (or maybe WOUND_SEVERITY_LOSS)
+ var/severity = WOUND_SEVERITY_MODERATE
+ /// The list of wounds it belongs in, WOUND_LIST_BLUNT, WOUND_LIST_SLASH, or WOUND_LIST_BURN
+ var/wound_type
+
+ /// What body zones can we affect
+ var/list/viable_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ /// Who owns the body part that we're wounding
+ var/mob/living/carbon/victim = null
+ /// The bodypart we're parented to
+ var/obj/item/bodypart/limb = null
+
+ /// Specific items such as bandages or sutures that can try directly treating this wound
+ var/list/treatable_by
+ /// Specific items such as bandages or sutures that can try directly treating this wound only if the user has the victim in an aggressive grab or higher
+ var/list/treatable_by_grabbed
+ /// Tools with the specified tool flag will also be able to try directly treating this wound
+ var/treatable_tool
+ /// How long it will take to treat this wound with a standard effective tool, assuming it doesn't need surgery
+ var/base_treat_time = 5 SECONDS
+
+ /// Using this limb in a do_after interaction will multiply the length by this duration (arms)
+ var/interaction_efficiency_penalty = 1
+ /// Incoming damage on this limb will be multiplied by this, to simulate tenderness and vulnerability (mostly burns).
+ var/damage_mulitplier_penalty = 1
+ /// If set and this wound is applied to a leg, we take this many deciseconds extra per step on this leg
+ var/limp_slowdown
+ /// How much we're contributing to this limb's bleed_rate
+ var/blood_flow
+
+ /// The minimum we need to roll on [/obj/item/bodypart/proc/check_wounding] to begin suffering this wound, see check_wounding_mods() for more
+ var/threshold_minimum
+ /// How much having this wound will add to all future check_wounding() rolls on this limb, to allow progression to worse injuries with repeated damage
+ var/threshold_penalty
+ /// If we need to process each life tick
+ var/processes = FALSE
+
+ /// If having this wound makes currently makes the parent bodypart unusable
+ var/disabling
+
+ /// What status effect we assign on application
+ var/status_effect_type
+ /// The status effect we're linked to
+ var/datum/status_effect/linked_status_effect
+ /// If we're operating on this wound and it gets healed, we'll nix the surgery too
+ var/datum/surgery/attached_surgery
+ /// if you're a lazy git and just throw them in cryo, the wound will go away after accumulating severity * 25 power
+ var/cryo_progress
+
+ /// What kind of scars this wound will create description wise once healed
+ var/scar_keyword = "generic"
+ /// If we've already tried scarring while removing (since remove_wound calls qdel, and qdel calls remove wound, .....) TODO: make this cleaner
+ var/already_scarred = FALSE
+ /// If we forced this wound through badmin smite, we won't count it towards the round totals
+ var/from_smite
+
+ /// What flags apply to this wound
+ var/wound_flags = (FLESH_WOUND | BONE_WOUND | ACCEPTS_GAUZE)
+
+/datum/wound/Destroy()
+ if(attached_surgery)
+ QDEL_NULL(attached_surgery)
+ if(limb?.wounds && (src in limb.wounds)) // destroy can call remove_wound() and remove_wound() calls qdel, so we check to make sure there's anything to remove first
+ remove_wound()
+ limb = null
+ victim = null
+ return ..()
+
+/**
+ * apply_wound() is used once a wound type is instantiated to assign it to a bodypart, and actually come into play.
+ *
+ *
+ * Arguments:
+ * * L: The bodypart we're wounding, we don't care about the person, we can get them through the limb
+ * * silent: Not actually necessary I don't think, was originally used for demoting wounds so they wouldn't make new messages, but I believe old_wound took over that, I may remove this shortly
+ * * old_wound: If our new wound is a replacement for one of the same time (promotion or demotion), we can reference the old one just before it's removed to copy over necessary vars
+ * * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented)
+ */
+/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE)
+ if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || isalien(L.owner) || !L.is_organic_limb())
+ qdel(src)
+ return
+
+ if(ishuman(L.owner))
+ var/mob/living/carbon/human/H = L.owner
+ if(((wound_flags & BONE_WOUND) && !(HAS_BONE in H.dna.species.species_traits)) || ((wound_flags & FLESH_WOUND) && !(HAS_FLESH in H.dna.species.species_traits)))
+ qdel(src)
+ return
+
+ // we accept promotions and demotions, but no point in redundancy. This should have already been checked wherever the wound was rolled and applied for (see: bodypart damage code), but we do an extra check
+ // in case we ever directly add wounds
+ for(var/i in L.wounds)
+ var/datum/wound/preexisting_wound = i
+ if((preexisting_wound.type == type) && (preexisting_wound != old_wound))
+ qdel(src)
+ return
+
+ victim = L.owner
+ limb = L
+ LAZYADD(victim.all_wounds, src)
+ LAZYADD(limb.wounds, src)
+ limb.update_wounds()
+ if(status_effect_type)
+ linked_status_effect = victim.apply_status_effect(status_effect_type, src)
+ SEND_SIGNAL(victim, COMSIG_CARBON_GAIN_WOUND, src, limb)
+ if(!victim.alerts["wound"]) // only one alert is shared between all of the wounds
+ victim.throw_alert("wound", /obj/screen/alert/status_effect/wound)
+
+ var/demoted
+ if(old_wound)
+ demoted = (severity <= old_wound.severity)
+
+ if(severity == WOUND_SEVERITY_TRIVIAL)
+ return
+
+ if(!(silent || demoted))
+ var/msg = "[victim]'s [limb.name] [occur_text]!"
+ var/vis_dist = COMBAT_MESSAGE_RANGE
+
+ if(severity != WOUND_SEVERITY_MODERATE)
+ msg = "[msg]"
+ vis_dist = DEFAULT_MESSAGE_RANGE
+
+ victim.visible_message(msg, "Your [limb.name] [occur_text]!", vision_distance = vis_dist)
+ if(sound_effect)
+ playsound(L.owner, sound_effect, 70 + 20 * severity, TRUE)
+
+ if(!demoted)
+ wound_injury(old_wound)
+ second_wind()
+
+/// Remove the wound from whatever it's afflicting, and cleans up whateverstatus effects it had or modifiers it had on interaction times. ignore_limb is used for detachments where we only want to forget the victim
+/datum/wound/proc/remove_wound(ignore_limb, replaced = FALSE)
+ //TODO: have better way to tell if we're getting removed without replacement (full heal) scar stuff
+ if(limb && !already_scarred && !replaced)
+ already_scarred = TRUE
+ var/datum/scar/new_scar = new
+ new_scar.generate(limb, src)
+ if(victim)
+ LAZYREMOVE(victim.all_wounds, src)
+ if(!victim.all_wounds)
+ victim.clear_alert("wound")
+ SEND_SIGNAL(victim, COMSIG_CARBON_LOSE_WOUND, src, limb)
+ if(limb && !ignore_limb)
+ LAZYREMOVE(limb.wounds, src)
+ limb.update_wounds(replaced)
+
+/**
+ * replace_wound() is used when you want to replace the current wound with a new wound, presumably of the same category, just of a different severity (either up or down counts)
+ *
+ * This proc actually instantiates the new wound based off the specific type path passed, then returns the new instantiated wound datum.
+ *
+ * Arguments:
+ * * new_type- The TYPE PATH of the wound you want to replace this, like /datum/wound/slash/severe
+ * * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented)
+ */
+/datum/wound/proc/replace_wound(new_type, smited = FALSE)
+ var/datum/wound/new_wound = new new_type
+ already_scarred = TRUE
+ remove_wound(replaced=TRUE)
+ new_wound.apply_wound(limb, old_wound = src, smited = smited)
+ qdel(src)
+ return new_wound
+
+/// The immediate negative effects faced as a result of the wound
+/datum/wound/proc/wound_injury(datum/wound/old_wound = null)
+ return
+
+/// Additional beneficial effects when the wound is gained, in case you want to give a temporary boost to allow the victim to try an escape or last stand
+/datum/wound/proc/second_wind()
+ switch(severity)
+ if(WOUND_SEVERITY_MODERATE)
+ victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_MODERATE)
+ if(WOUND_SEVERITY_SEVERE)
+ victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_SEVERE)
+ if(WOUND_SEVERITY_CRITICAL)
+ victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_CRITICAL)
+ if(WOUND_SEVERITY_LOSS)
+ victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_LOSS)
+
+/**
+ * try_treating() is an intercept run from [/mob/living/carbon/proc/attackby] right after surgeries but before anything else. Return TRUE here if the item is something that is relevant to treatment to take over the interaction.
+ *
+ * This proc leads into [/datum/wound/proc/treat] and probably shouldn't be added onto in children types. You can specify what items or tools you want to be intercepted
+ * with var/list/treatable_by and var/treatable_tool, then if an item fulfills one of those requirements and our wound claims it first, it goes over to treat() and treat_self().
+ *
+ * Arguments:
+ * * I: The item we're trying to use
+ * * user: The mob trying to use it on us
+ */
+/datum/wound/proc/try_treating(obj/item/I, mob/user)
+ // first we weed out if we're not dealing with our wound's bodypart, or if it might be an attack
+ if(!I || limb.body_zone != user.zone_selected || (I.force && user.a_intent != INTENT_HELP))
+ return FALSE
+
+ var/allowed = FALSE
+
+ // check if we have a valid treatable tool (or, if cauteries are allowed, if we have something hot)
+ if((I.tool_behaviour == treatable_tool) || (treatable_tool == TOOL_CAUTERY && I.get_temperature()))
+ allowed = TRUE
+ // failing that, see if we're aggro grabbing them and if we have an item that works for aggro grabs only
+ else if(user.pulling == victim && user.grab_state >= GRAB_AGGRESSIVE && check_grab_treatments(I, user))
+ allowed = TRUE
+ // failing THAT, we check if we have a generally allowed item
+ else
+ for(var/allowed_type in treatable_by)
+ if(istype(I, allowed_type))
+ allowed = TRUE
+ break
+
+ // if none of those apply, we return false to avoid interrupting
+ if(!allowed)
+ return FALSE
+
+ // now that we've determined we have a valid attempt at treating, we can stomp on their dreams if we're already interacting with the patient
+ if(INTERACTING_WITH(user, victim))
+ to_chat(user, "You're already interacting with [victim]!")
+ return TRUE
+
+ // lastly, treat them
+ treat(I, user)
+ return TRUE
+
+/// Return TRUE if we have an item that can only be used while aggro grabbed (unhanded aggro grab treatments go in [/datum/wound/proc/try_handling]). Treatment is still is handled in [/datum/wound/proc/treat]
+/datum/wound/proc/check_grab_treatments(obj/item/I, mob/user)
+ return FALSE
+
+/// Like try_treating() but for unhanded interactions from humans, used by joint dislocations for manual bodypart chiropractice for example.
+/datum/wound/proc/try_handling(mob/living/carbon/human/user)
+ return FALSE
+
+/// Someone is using something that might be used for treating the wound on this limb
+/datum/wound/proc/treat(obj/item/I, mob/user)
+ return
+
+/// If var/processing is TRUE, this is run on each life tick
+/datum/wound/proc/handle_process()
+ return
+
+/// For use in do_after callback checks
+/datum/wound/proc/still_exists()
+ return (!QDELETED(src) && limb)
+
+/// When our parent bodypart is hurt
+/datum/wound/proc/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ return
+
+/// Called from cryoxadone and pyroxadone when they're proc'ing. Wounds will slowly be fixed separately from other methods when these are in effect. crappy name but eh
+/datum/wound/proc/on_xadone(power)
+ cryo_progress += power
+ if(cryo_progress > 33 * severity)
+ qdel(src)
+
+/// When synthflesh is applied to the victim, we call this. No sense in setting up an entire chem reaction system for wounds when we only care for a few chems. Probably will change in the future
+/datum/wound/proc/on_synthflesh(power)
+ return
+
+/// Called when the patient is undergoing stasis, so that having fully treated a wound doesn't make you sit there helplessly until you think to unbuckle them
+/datum/wound/proc/on_stasis()
+ return
+
+/// Called when we're crushed in an airlock or firedoor, for one of the improvised joint dislocation fixes
+/datum/wound/proc/crush()
+ return
+
+/// Used when we're being dragged while bleeding, the value we return is how much bloodloss this wound causes from being dragged. Since it's a proc, you can let bandages soak some of the blood
+/datum/wound/proc/drag_bleed_amount()
+ return
+
+/**
+ * get_examine_description() is used in carbon/examine and human/examine to show the status of this wound. Useful if you need to show some status like the wound being splinted or bandaged.
+ *
+ * Return the full string line you want to show, note that we're already dealing with the 'warning' span at this point, and that \n is already appended for you in the place this is called from
+ *
+ * Arguments:
+ * * mob/user: The user examining the wound's owner, if that matters
+ */
+/datum/wound/proc/get_examine_description(mob/user)
+ . = "[victim.p_their(TRUE)] [limb.name] [examine_desc]"
+ . = severity <= WOUND_SEVERITY_MODERATE ? "[.]." : "[.]!"
+
+/datum/wound/proc/get_scanner_description(mob/user)
+ return "Type: [name]\nSeverity: [severity_text()]\nDescription: [desc]\nRecommended Treatment: [treat_text]"
+
+/datum/wound/proc/severity_text()
+ switch(severity)
+ if(WOUND_SEVERITY_TRIVIAL)
+ return "Trivial"
+ if(WOUND_SEVERITY_MODERATE)
+ return "Moderate"
+ if(WOUND_SEVERITY_SEVERE)
+ return "Severe"
+ if(WOUND_SEVERITY_CRITICAL)
+ return "Critical"
diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm
new file mode 100644
index 0000000000..128c860a6d
--- /dev/null
+++ b/code/datums/wounds/bones.dm
@@ -0,0 +1,420 @@
+/*
+ Bones
+*/
+// TODO: well, a lot really, but i'd kill to get overlays and a bonebreaking effect like Blitz: The League, similar to electric shock skeletons
+
+/*
+ Base definition
+*/
+/datum/wound/blunt
+ sound_effect = 'sound/effects/wounds/crack1.ogg'
+ wound_type = WOUND_BLUNT
+ wound_flags = (BONE_WOUND | ACCEPTS_GAUZE)
+
+ /// Have we been taped?
+ var/taped
+ /// Have we been bone gel'd?
+ var/gelled
+ /// If we did the gel + surgical tape healing method for fractures, how many regen points we need
+ var/regen_points_needed
+ /// Our current counter for gel + surgical tape regeneration
+ var/regen_points_current
+ /// If we suffer severe head booboos, we can get brain traumas tied to them
+ var/datum/brain_trauma/active_trauma
+ /// What brain trauma group, if any, we can draw from for head wounds
+ var/brain_trauma_group
+ /// If we deal brain traumas, when is the next one due?
+ var/next_trauma_cycle
+ /// How long do we wait +/- 20% for the next trauma?
+ var/trauma_cycle_cooldown
+ /// If this is a chest wound and this is set, we have this chance to cough up blood when hit in the chest
+ var/internal_bleeding_chance = 0
+
+/*
+ Overwriting of base procs
+*/
+/datum/wound/blunt/wound_injury(datum/wound/old_wound = null)
+ if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group)
+ processes = TRUE
+ active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
+ next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
+
+ RegisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, .proc/attack_with_hurt_hand)
+ if(limb.held_index && victim.get_item_for_held_index(limb.held_index) && (disabling || prob(30 * severity)))
+ var/obj/item/I = victim.get_item_for_held_index(limb.held_index)
+ if(istype(I, /obj/item/offhand))
+ I = victim.get_inactive_held_item()
+
+ if(I && victim.dropItemToGround(I))
+ victim.visible_message("[victim] drops [I] in shock!", "The force on your [limb.name] causes you to drop [I]!", vision_distance=COMBAT_MESSAGE_RANGE)
+
+ update_inefficiencies()
+
+/datum/wound/blunt/remove_wound(ignore_limb, replaced)
+ limp_slowdown = 0
+ QDEL_NULL(active_trauma)
+ if(victim)
+ UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
+ return ..()
+
+/datum/wound/blunt/handle_process()
+ . = ..()
+ if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle)
+ if(active_trauma)
+ QDEL_NULL(active_trauma)
+ else
+ active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
+ next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
+
+ if(!regen_points_needed)
+ return
+
+ regen_points_current++
+ if(prob(severity * 2))
+ victim.take_bodypart_damage(rand(2, severity * 2), stamina=rand(2, severity * 2.5), wound_bonus=CANT_WOUND)
+ if(prob(33))
+ to_chat(victim, "You feel a sharp pain in your body as your bones are reforming!")
+
+ if(regen_points_current > regen_points_needed)
+ if(!victim || !limb)
+ qdel(src)
+ return
+ to_chat(victim, "Your [limb.name] has recovered from your fracture!")
+ remove_wound()
+
+/// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so
+/datum/wound/blunt/proc/attack_with_hurt_hand(mob/M, atom/target, proximity)
+ if(victim.get_active_hand() != limb || victim.a_intent == INTENT_HELP || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE)
+ return
+
+ // With a severe or critical wound, you have a 15% or 30% chance to proc pain on hit
+ if(prob((severity - 1) * 15))
+ // And you have a 70% or 50% chance to actually land the blow, respectively
+ if(prob(70 - 20 * (severity - 1)))
+ to_chat(victim, "The fracture in your [limb.name] shoots with pain as you strike [target]!")
+ limb.receive_damage(brute=rand(1,5))
+ else
+ victim.visible_message("[victim] weakly strikes [target] with [victim.p_their()] broken [limb.name], recoiling from pain!", \
+ "You fail to strike [target] as the fracture in your [limb.name] lights up in unbearable pain!", vision_distance=COMBAT_MESSAGE_RANGE)
+ victim.emote("scream")
+ victim.Stun(0.5 SECONDS)
+ limb.receive_damage(brute=rand(3,7))
+ return COMPONENT_NO_ATTACK_HAND
+
+/datum/wound/blunt/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE)
+ return
+ if(ishuman(victim))
+ var/mob/living/carbon/human/human_victim = victim
+ if(NOBLOOD in human_victim.dna?.species.species_traits)
+ return
+
+ if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg))
+ var/blood_bled = rand(1, wounding_dmg * (severity == WOUND_SEVERITY_CRITICAL ? 2 : 1.5)) // 12 brute toolbox can cause up to 18/24 bleeding with a severe/critical chest wound
+ switch(blood_bled)
+ if(1 to 6)
+ victim.bleed(blood_bled, TRUE)
+ if(7 to 13)
+ victim.visible_message("[victim] coughs up a bit of blood from the blow to [victim.p_their()] chest.", "You cough up a bit of blood from the blow to your chest.", vision_distance=COMBAT_MESSAGE_RANGE)
+ victim.bleed(blood_bled, TRUE)
+ if(14 to 19)
+ victim.visible_message("[victim] spits out a string of blood from the blow to [victim.p_their()] chest!", "You spit out a string of blood from the blow to your chest!", vision_distance=COMBAT_MESSAGE_RANGE)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
+ victim.bleed(blood_bled)
+ if(20 to INFINITY)
+ victim.visible_message("[victim] chokes up a spray of blood from the blow to [victim.p_their()] chest!", "You choke up on a spray of blood from the blow to your chest!", vision_distance=COMBAT_MESSAGE_RANGE)
+ victim.bleed(blood_bled)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
+ victim.add_splatter_floor(get_step(victim.loc, victim.dir))
+
+
+/datum/wound/blunt/get_examine_description(mob/user)
+ if(!limb.current_gauze && !gelled && !taped)
+ return ..()
+
+ var/list/msg = list()
+ if(!limb.current_gauze)
+ msg += "[victim.p_their(TRUE)] [limb.name] [examine_desc]"
+ else
+ var/sling_condition = ""
+ // how much life we have left in these bandages
+ switch(limb.current_gauze.obj_integrity / limb.current_gauze.max_integrity * 100)
+ if(0 to 25)
+ sling_condition = "just barely "
+ if(25 to 50)
+ sling_condition = "loosely "
+ if(50 to 75)
+ sling_condition = "mostly "
+ if(75 to INFINITY)
+ sling_condition = "tightly "
+
+ msg += "[victim.p_their(TRUE)] [limb.name] is [sling_condition] fastened in a sling of [limb.current_gauze.name]"
+
+ if(taped)
+ msg += ", and appears to be reforming itself under some surgical tape!"
+ else if(gelled)
+ msg += ", with fizzing flecks of blue bone gel sparking off the bone!"
+ else
+ msg += "!"
+ return "[msg.Join()]"
+
+/*
+ New common procs for /datum/wound/blunt/
+*/
+
+/datum/wound/blunt/proc/update_inefficiencies()
+ if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
+ if(limb.current_gauze)
+ limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor
+ else
+ limp_slowdown = initial(limp_slowdown)
+ victim.apply_status_effect(STATUS_EFFECT_LIMP)
+ else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
+ if(limb.current_gauze)
+ interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_gauze.splint_factor)
+ else
+ interaction_efficiency_penalty = interaction_efficiency_penalty
+
+ if(initial(disabling))
+ disabling = !limb.current_gauze
+
+ limb.update_wounds()
+
+/*
+ Moderate (Joint Dislocation)
+*/
+
+/datum/wound/blunt/moderate
+ name = "Joint Dislocation"
+ desc = "Patient's bone has been unset from socket, causing pain and reduced motor function."
+ treat_text = "Recommended application of bonesetter to affected limb, though manual relocation by applying an aggressive grab to the patient and helpfully interacting with afflicted limb may suffice."
+ examine_desc = "is awkwardly jammed out of place"
+ occur_text = "jerks violently and becomes unseated"
+ severity = WOUND_SEVERITY_MODERATE
+ viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ interaction_efficiency_penalty = 1.5
+ limp_slowdown = 1.5
+ threshold_minimum = 45
+ threshold_penalty = 15
+ treatable_tool = TOOL_BONESET
+ wound_flags = (BONE_WOUND)
+ status_effect_type = /datum/status_effect/wound/blunt/moderate
+ scar_keyword = "bluntmoderate"
+
+/datum/wound/blunt/moderate/crush()
+ if(prob(33))
+ victim.visible_message("[victim]'s dislocated [limb.name] pops back into place!", "Your dislocated [limb.name] pops back into place! Ow!")
+ remove_wound()
+
+/datum/wound/blunt/moderate/try_handling(mob/living/carbon/human/user)
+ if(user.pulling != victim || user.zone_selected != limb.body_zone || user.a_intent == INTENT_GRAB)
+ return FALSE
+
+ if(user.grab_state == GRAB_PASSIVE)
+ to_chat(user, "You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(name)]!")
+ return TRUE
+
+ if(user.grab_state >= GRAB_AGGRESSIVE)
+ user.visible_message("[user] begins twisting and straining [victim]'s dislocated [limb.name]!", "You begin twisting and straining [victim]'s dislocated [limb.name]...", ignored_mobs=victim)
+ to_chat(victim, "[user] begins twisting and straining your dislocated [limb.name]!")
+ if(user.a_intent == INTENT_HELP)
+ chiropractice(user)
+ else
+ malpractice(user)
+ return TRUE
+
+/// If someone is snapping our dislocated joint back into place by hand with an aggro grab and help intent
+/datum/wound/blunt/moderate/proc/chiropractice(mob/living/carbon/human/user)
+ var/time = base_treat_time
+
+ if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+
+ if(prob(65))
+ user.visible_message("[user] snaps [victim]'s dislocated [limb.name] back into place!", "You snap [victim]'s dislocated [limb.name] back into place!", ignored_mobs=victim)
+ to_chat(victim, "[user] snaps your dislocated [limb.name] back into place!")
+ victim.emote("scream")
+ limb.receive_damage(brute=20, wound_bonus=CANT_WOUND)
+ qdel(src)
+ else
+ user.visible_message("[user] wrenches [victim]'s dislocated [limb.name] around painfully!", "You wrench [victim]'s dislocated [limb.name] around painfully!", ignored_mobs=victim)
+ to_chat(victim, "[user] wrenches your dislocated [limb.name] around painfully!")
+ limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
+ chiropractice(user)
+
+/// If someone is snapping our dislocated joint into a fracture by hand with an aggro grab and harm or disarm intent
+/datum/wound/blunt/moderate/proc/malpractice(mob/living/carbon/human/user)
+ var/time = base_treat_time
+
+ if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+
+ if(prob(65))
+ user.visible_message("[user] snaps [victim]'s dislocated [limb.name] with a sickening crack!", "You snap [victim]'s dislocated [limb.name] with a sickening crack!", ignored_mobs=victim)
+ to_chat(victim, "[user] snaps your dislocated [limb.name] with a sickening crack!")
+ victim.emote("scream")
+ limb.receive_damage(brute=25, wound_bonus=30)
+ else
+ user.visible_message("[user] wrenches [victim]'s dislocated [limb.name] around painfully!", "You wrench [victim]'s dislocated [limb.name] around painfully!", ignored_mobs=victim)
+ to_chat(victim, "[user] wrenches your dislocated [limb.name] around painfully!")
+ limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
+ malpractice(user)
+
+
+/datum/wound/blunt/moderate/treat(obj/item/I, mob/user)
+ if(victim == user)
+ victim.visible_message("[user] begins resetting [victim.p_their()] [limb.name] with [I].", "You begin resetting your [limb.name] with [I]...")
+ else
+ user.visible_message("[user] begins resetting [victim]'s [limb.name] with [I].", "You begin resetting [victim]'s [limb.name] with [I]...")
+
+ if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists)))
+ return
+
+ if(victim == user)
+ limb.receive_damage(brute=15, wound_bonus=CANT_WOUND)
+ victim.visible_message("[user] finishes resetting [victim.p_their()] [limb.name]!", "You reset your [limb.name]!")
+ else
+ limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
+ user.visible_message("[user] finishes resetting [victim]'s [limb.name]!", "You finish resetting [victim]'s [limb.name]!", victim)
+ to_chat(victim, "[user] resets your [limb.name]!")
+
+ victim.emote("scream")
+ qdel(src)
+
+/*
+ Severe (Hairline Fracture)
+*/
+
+/datum/wound/blunt/severe
+ name = "Hairline Fracture"
+ desc = "Patient's bone has suffered a crack in the foundation, causing serious pain and reduced limb functionality."
+ treat_text = "Recommended light surgical application of bone gel, though a sling of medical gauze will prevent worsening situation."
+ examine_desc = "appears grotesquely swollen, its attachment weakened"
+ occur_text = "sprays chips of bone and develops a nasty looking bruise"
+
+ severity = WOUND_SEVERITY_SEVERE
+ interaction_efficiency_penalty = 2
+ limp_slowdown = 4
+ threshold_minimum = 70
+ threshold_penalty = 30
+ treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
+ status_effect_type = /datum/status_effect/wound/blunt/severe
+ scar_keyword = "bluntsevere"
+ brain_trauma_group = BRAIN_TRAUMA_MILD
+ trauma_cycle_cooldown = 1.5 MINUTES
+ internal_bleeding_chance = 40
+ wound_flags = (BONE_WOUND | ACCEPTS_GAUZE | MANGLES_BONE)
+
+/datum/wound/blunt/critical
+ name = "Compound Fracture"
+ desc = "Patient's bones have suffered multiple gruesome fractures, causing significant pain and near uselessness of limb."
+ treat_text = "Immediate binding of affected limb, followed by surgical intervention ASAP."
+ examine_desc = "is mangled and pulped, seemingly held together by tissue alone"
+ occur_text = "cracks apart, exposing broken bones to open air"
+
+ severity = WOUND_SEVERITY_CRITICAL
+ interaction_efficiency_penalty = 4
+ limp_slowdown = 6
+ sound_effect = 'sound/effects/wounds/crack2.ogg'
+ threshold_minimum = 125
+ threshold_penalty = 50
+ disabling = TRUE
+ treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
+ status_effect_type = /datum/status_effect/wound/blunt/critical
+ scar_keyword = "bluntcritical"
+ brain_trauma_group = BRAIN_TRAUMA_SEVERE
+ trauma_cycle_cooldown = 2.5 MINUTES
+ internal_bleeding_chance = 60
+ wound_flags = (BONE_WOUND | ACCEPTS_GAUZE | MANGLES_BONE)
+
+// doesn't make much sense for "a" bone to stick out of your head
+/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent, datum/wound/old_wound, smited)
+ if(L.body_zone == BODY_ZONE_HEAD)
+ occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood"
+ examine_desc = "has an unsettling indent, with bits of skull poking out"
+ . = ..()
+
+/// if someone is using bone gel on our wound
+/datum/wound/blunt/proc/gel(obj/item/stack/medical/bone_gel/I, mob/user)
+ if(gelled)
+ to_chat(user, "[user == victim ? "Your" : "[victim]'s"] [limb.name] is already coated with bone gel!")
+ return
+
+ user.visible_message("[user] begins hastily applying [I] to [victim]'s' [limb.name]...", "You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name], disregarding the warning label...")
+
+ if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists)))
+ return
+
+ I.use(1)
+ victim.emote("scream")
+ if(user != victim)
+ user.visible_message("[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!", "You finish applying [I] to [victim]'s [limb.name]!", ignored_mobs=victim)
+ to_chat(victim, "[user] finishes applying [I] to your [limb.name], and you can feel the bones exploding with pain as they begin melting and reforming!")
+ else
+ var/painkiller_bonus = 0
+ if(victim.drunkenness)
+ painkiller_bonus += 5
+ if(victim.reagents?.has_reagent(/datum/reagent/medicine/morphine))
+ painkiller_bonus += 10
+ if(victim.reagents?.has_reagent(/datum/reagent/determination))
+ painkiller_bonus += 5
+
+ if(prob(25 + (20 * severity - 2) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by painkillers
+ victim.visible_message("[victim] fails to finish applying [I] to [victim.p_their()] [limb.name], passing out from the pain!", "You black out from the pain of applying [I] to your [limb.name] before you can finish!")
+ victim.AdjustUnconscious(5 SECONDS)
+ return
+ victim.visible_message("[victim] finishes applying [I] to [victim.p_their()] [limb.name], grimacing from the pain!", "You finish applying [I] to your [limb.name], and your bones explode in pain!")
+
+ limb.receive_damage(30, stamina=100, wound_bonus=CANT_WOUND)
+ if(!gelled)
+ gelled = TRUE
+
+/// if someone is using surgical tape on our wound
+/datum/wound/blunt/proc/tape(obj/item/stack/sticky_tape/surgical/I, mob/user)
+ if(!gelled)
+ to_chat(user, "[user == victim ? "Your" : "[victim]'s"] [limb.name] must be coated with bone gel to perform this emergency operation!")
+ return
+ if(taped)
+ to_chat(user, "[user == victim ? "Your" : "[victim]'s"] [limb.name] is already wrapped in [I.name] and reforming!")
+ return
+
+ user.visible_message("[user] begins applying [I] to [victim]'s' [limb.name]...", "You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")
+
+ if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists)))
+ return
+
+ regen_points_current = 0
+ regen_points_needed = 30 SECONDS * (user == victim ? 1.5 : 1) * (severity - 1)
+ I.use(1)
+ if(user != victim)
+ user.visible_message("[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!", "You finish applying [I] to [victim]'s [limb.name]!", ignored_mobs=victim)
+ to_chat(victim, "[user] finishes applying [I] to your [limb.name], you immediately begin to feel your bones start to reform!")
+ else
+ victim.visible_message("[victim] finishes applying [I] to [victim.p_their()] [limb.name], !", "You finish applying [I] to your [limb.name], and you immediately begin to feel your bones start to reform!")
+
+ taped = TRUE
+ processes = TRUE
+
+/datum/wound/blunt/treat(obj/item/I, mob/user)
+ if(istype(I, /obj/item/stack/medical/bone_gel))
+ gel(I, user)
+ else if(istype(I, /obj/item/stack/sticky_tape/surgical))
+ tape(I, user)
+
+/datum/wound/blunt/get_scanner_description(mob/user)
+ . = ..()
+
+ . += "
"
+
+ if(!gelled)
+ . += "Alternative Treatment: Apply bone gel directly to injured limb, then apply surgical tape to begin bone regeneration. This is both excruciatingly painful and slow, and only recommended in dire circumstances.\n"
+ else if(!taped)
+ . += "Continue Alternative Treatment: Apply surgical tape directly to injured limb to begin bone regeneration. Note, this is both excruciatingly painful and slow.\n"
+ else
+ . += "Note: Bone regeneration in effect. Bone is [round(regen_points_current*100/regen_points_needed)]% regenerated.\n"
+
+ if(limb.body_zone == BODY_ZONE_HEAD)
+ . += "Cranial Trauma Detected: Patient will suffer random bouts of [severity == WOUND_SEVERITY_SEVERE ? "mild" : "severe"] brain traumas until bone is repaired."
+ else if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume)
+ . += "Ribcage Trauma Detected: Further trauma to chest is likely to worsen internal bleeding until bone is repaired."
+ . += "
"
diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm
new file mode 100644
index 0000000000..f3e22807cf
--- /dev/null
+++ b/code/datums/wounds/burns.dm
@@ -0,0 +1,296 @@
+
+
+// TODO: well, a lot really, but specifically I want to add potential fusing of clothing/equipment on the affected area, and limb infections, though those may go in body part code
+/datum/wound/burn
+ a_or_from = "from"
+ wound_type = WOUND_BURN
+ processes = TRUE
+ sound_effect = 'sound/effects/wounds/sizzle1.ogg'
+ wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
+
+ treatable_by = list(/obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) // sterilizer and alcohol will require reagent treatments, coming soon
+
+ // Flesh damage vars
+ /// How much damage to our flesh we currently have. Once both this and infestation reach 0, the wound is considered healed
+ var/flesh_damage = 5
+ /// Our current counter for how much flesh regeneration we have stacked from regenerative mesh/synthflesh/whatever, decrements each tick and lowers flesh_damage
+ var/flesh_healing = 0
+
+ // Infestation vars (only for severe and critical)
+ /// How quickly infection breeds on this burn if we don't have disinfectant
+ var/infestation_rate = 0
+ /// Our current level of infection
+ var/infestation = 0
+ /// Our current level of sanitization/anti-infection, from disinfectants/alcohol/UV lights. While positive, totally pauses and slowly reverses infestation effects each tick
+ var/sanitization = 0
+
+ /// Once we reach infestation beyond WOUND_INFESTATION_SEPSIS, we get this many warnings before the limb is completely paralyzed (you'd have to ignore a really bad burn for a really long time for this to happen)
+ var/strikes_to_lose_limb = 3
+
+
+/datum/wound/burn/handle_process()
+ . = ..()
+ if(strikes_to_lose_limb == 0)
+ victim.adjustToxLoss(0.5)
+ if(prob(1))
+ victim.visible_message("The infection on the remnants of [victim]'s [limb.name] shift and bubble nauseatingly!", "You can feel the infection on the remnants of your [limb.name] coursing through your veins!")
+ return
+
+ if(victim.reagents)
+ if(victim.reagents.has_reagent(/datum/reagent/medicine/spaceacillin))
+ sanitization += 0.9
+ if(victim.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine/))
+ sanitization += 0.9
+ if(victim.reagents.has_reagent(/datum/reagent/medicine/mine_salve))
+ sanitization += 0.3
+ flesh_healing += 0.5
+
+ if(limb.current_gauze)
+ limb.seep_gauze(WOUND_BURN_SANITIZATION_RATE)
+
+ if(flesh_healing > 0)
+ var/bandage_factor = (limb.current_gauze ? limb.current_gauze.splint_factor : 1)
+ flesh_damage = max(0, flesh_damage - 1)
+ flesh_healing = max(0, flesh_healing - bandage_factor) // good bandages multiply the length of flesh healing
+
+ // here's the check to see if we're cleared up
+ if((flesh_damage <= 0) && (infestation <= 1))
+ to_chat(victim, "The burns on your [limb.name] have cleared up!")
+ qdel(src)
+ return
+
+ // sanitization is checked after the clearing check but before the rest, because we freeze the effects of infection while we have sanitization
+ if(sanitization > 0)
+ var/bandage_factor = (limb.current_gauze ? limb.current_gauze.splint_factor : 1)
+ infestation = max(0, infestation - WOUND_BURN_SANITIZATION_RATE)
+ sanitization = max(0, sanitization - (WOUND_BURN_SANITIZATION_RATE * bandage_factor))
+ return
+
+ infestation += infestation_rate
+
+ switch(infestation)
+ if(0 to WOUND_INFECTION_MODERATE)
+ if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
+ if(prob(30))
+ victim.adjustToxLoss(0.2)
+ if(prob(6))
+ to_chat(victim, "The blisters on your [limb.name] ooze a strange pus...")
+ if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
+ if(!disabling && prob(2))
+ to_chat(victim, "Your [limb.name] completely locks up, as you struggle for control against the infection!")
+ disabling = TRUE
+ else if(disabling && prob(8))
+ to_chat(victim, "You regain sensation in your [limb.name], but it's still in terrible shape!")
+ disabling = FALSE
+ else if(prob(20))
+ victim.adjustToxLoss(0.5)
+ if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
+ if(!disabling && prob(3))
+ to_chat(victim, "You suddenly lose all sensation of the festering infection in your [limb.name]!")
+ disabling = TRUE
+ else if(disabling && prob(3))
+ to_chat(victim, "You can barely feel your [limb.name] again, and you have to strain to retain motor control!")
+ disabling = FALSE
+ else if(prob(1))
+ to_chat(victim, "You contemplate life without your [limb.name]...")
+ victim.adjustToxLoss(0.75)
+ else if(prob(4))
+ victim.adjustToxLoss(1)
+ if(WOUND_INFECTION_SEPTIC to INFINITY)
+ if(prob(infestation))
+ switch(strikes_to_lose_limb)
+ if(3 to INFINITY)
+ to_chat(victim, "The skin on your [limb.name] is literally dripping off, you feel awful!")
+ if(2)
+ to_chat(victim, "The infection in your [limb.name] is literally dripping off, you feel horrible!")
+ if(1)
+ to_chat(victim, "Infection has just about completely claimed your [limb.name]!")
+ if(0)
+ to_chat(victim, "The last of the nerve endings in your [limb.name] wither away, as the infection completely paralyzes your joint connector.")
+ threshold_penalty = 120 // piss easy to destroy
+ var/datum/brain_trauma/severe/paralysis/sepsis = new (limb.body_zone)
+ victim.gain_trauma(sepsis)
+ strikes_to_lose_limb--
+
+/datum/wound/burn/get_examine_description(mob/user)
+ if(strikes_to_lose_limb <= 0)
+ return "[victim.p_their(TRUE)] [limb.name] is completely dead and unrecognizable as organic."
+
+ var/list/condition = list("[victim.p_their(TRUE)] [limb.name] [examine_desc]")
+ if(limb.current_gauze)
+ var/bandage_condition
+ switch(limb.current_gauze.absorption_capacity)
+ if(0 to 1.25)
+ bandage_condition = "nearly ruined "
+ if(1.25 to 2.75)
+ bandage_condition = "badly worn "
+ if(2.75 to 4)
+ bandage_condition = "slightly pus-stained "
+ if(4 to INFINITY)
+ bandage_condition = "clean "
+
+ condition += " underneath a dressing of [bandage_condition] [limb.current_gauze.name]"
+ else
+ switch(infestation)
+ if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
+ condition += ", with small spots of discoloration along the nearby veins!"
+ if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
+ condition += ", with dark clouds spreading outwards under the skin!"
+ if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
+ condition += ", with streaks of rotten infection pulsating outward!"
+ if(WOUND_INFECTION_SEPTIC to INFINITY)
+ return "[victim.p_their(TRUE)] [limb.name] is a mess of char and rot, skin literally dripping off the bone with infection!"
+ else
+ condition += "!"
+
+ return "[condition.Join()]"
+
+/datum/wound/burn/get_scanner_description(mob/user)
+ if(strikes_to_lose_limb == 0)
+ var/oopsie = "Type: [name]\nSeverity: [severity_text()]"
+ oopsie += "
Infection Level: The infection is total. The bodypart is lost. Amputate or augment limb immediately.
"
+ return oopsie
+
+ . = ..()
+ . += "
"
+
+ if(infestation <= sanitization && flesh_damage <= flesh_healing)
+ . += "No further treatment required: Burns will heal shortly."
+ else
+ switch(infestation)
+ if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
+ . += "Infection Level: Moderate\n"
+ if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
+ . += "Infection Level: Severe\n"
+ if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
+ . += "Infection Level: CRITICAL\n"
+ if(WOUND_INFECTION_SEPTIC to INFINITY)
+ . += "Infection Level: LOSS IMMINENT\n"
+ if(infestation > sanitization)
+ . += "\tSurgical debridement, antiobiotics/sterilizers, or regenerative mesh will rid infection. Paramedic UV penlights are also effective.\n"
+
+ if(flesh_damage > 0)
+ . += "Flesh damage detected: Please apply ointment or regenerative mesh to allow recovery.\n"
+ . += "
"
+
+/*
+ new burn common procs
+*/
+
+/// if someone is using ointment on our burns
+/datum/wound/burn/proc/ointment(obj/item/stack/medical/ointment/I, mob/user)
+ user.visible_message("[user] begins applying [I] to [victim]'s [limb.name]...", "You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")
+ if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+
+ limb.heal_damage(I.heal_brute, I.heal_burn)
+ user.visible_message("[user] applies [I] to [victim].", "You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.name].")
+ I.use(1)
+ sanitization += I.sanitization
+ flesh_healing += I.flesh_regeneration
+
+ if((infestation <= 0 || sanitization >= infestation) && (flesh_damage <= 0 || flesh_healing > flesh_damage))
+ to_chat(user, "You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.name] to recover.")
+ else
+ try_treating(I, user)
+
+/// if someone is using mesh on our burns
+/datum/wound/burn/proc/mesh(obj/item/stack/medical/mesh/I, mob/user)
+ user.visible_message("[user] begins wrapping [victim]'s [limb.name] with [I]...", "You begin wrapping [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")
+ if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+
+ limb.heal_damage(I.heal_brute, I.heal_burn)
+ user.visible_message("[user] applies [I] to [victim].", "You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.name].")
+ I.use(1)
+ sanitization += I.sanitization
+ flesh_healing += I.flesh_regeneration
+
+ if(sanitization >= infestation && flesh_healing > flesh_damage)
+ to_chat(user, "You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.name] to recover.")
+ else
+ try_treating(I, user)
+
+/// Paramedic UV penlights
+/datum/wound/burn/proc/uv(obj/item/flashlight/pen/paramedic/I, mob/user)
+ if(!COOLDOWN_FINISHED(I, uv_cooldown))
+ to_chat(user, "[I] is still recharging!")
+ return
+ if(infestation <= 0 || infestation < sanitization)
+ to_chat(user, "There's no infection to treat on [victim]'s [limb.name]!")
+ return
+
+ user.visible_message("[user] flashes the burns on [victim]'s [limb] with [I].", "You flash the burns on [user == victim ? "your" : "[victim]'s"] [limb.name] with [I].", vision_distance=COMBAT_MESSAGE_RANGE)
+ sanitization += I.uv_power
+ COOLDOWN_START(I, uv_cooldown, I.uv_cooldown_length)
+
+/datum/wound/burn/treat(obj/item/I, mob/user)
+ if(istype(I, /obj/item/stack/medical/ointment))
+ ointment(I, user)
+ else if(istype(I, /obj/item/stack/medical/mesh))
+ mesh(I, user)
+ else if(istype(I, /obj/item/flashlight/pen/paramedic))
+ uv(I, user)
+
+// people complained about burns not healing on stasis beds, so in addition to checking if it's cured, they also get the special ability to very slowly heal on stasis beds if they have the healing effects stored
+/datum/wound/burn/on_stasis()
+ . = ..()
+ if(flesh_healing > 0)
+ flesh_damage = max(0, flesh_damage - 0.2)
+ if((flesh_damage <= 0) && (infestation <= 1))
+ to_chat(victim, "The burns on your [limb.name] have cleared up!")
+ qdel(src)
+ return
+ if(sanitization > 0)
+ infestation = max(0, infestation - WOUND_BURN_SANITIZATION_RATE * 0.2)
+
+/datum/wound/burn/on_synthflesh(amount)
+ flesh_healing += amount * 0.5 // 20u patch will heal 10 flesh standard
+
+// we don't even care about first degree burns, straight to second
+/datum/wound/burn/moderate
+ name = "Second Degree Burns"
+ desc = "Patient is suffering considerable burns with mild skin penetration, weakening limb integrity and increased burning sensations."
+ treat_text = "Recommended application of topical ointment or regenerative mesh to affected region."
+ examine_desc = "is badly burned and breaking out in blisters"
+ occur_text = "breaks out with violent red burns"
+ severity = WOUND_SEVERITY_MODERATE
+ damage_mulitplier_penalty = 1.05
+ threshold_minimum = 50
+ threshold_penalty = 30 // burns cause significant decrease in limb integrity compared to other wounds
+ status_effect_type = /datum/status_effect/wound/burn/moderate
+ flesh_damage = 5
+ scar_keyword = "burnmoderate"
+
+/datum/wound/burn/severe
+ name = "Third Degree Burns"
+ desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity."
+ treat_text = "Recommended immediate disinfection and excision of any infected skin, followed by bandaging and ointment."
+ examine_desc = "appears seriously charred, with aggressive red splotches"
+ occur_text = "chars rapidly, exposing ruined tissue and spreading angry red burns"
+ severity = WOUND_SEVERITY_SEVERE
+ damage_mulitplier_penalty = 1.1
+ threshold_minimum = 90
+ threshold_penalty = 40
+ status_effect_type = /datum/status_effect/wound/burn/severe
+ treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
+ infestation_rate = 0.05 // appx 13 minutes to reach sepsis without any treatment
+ flesh_damage = 12.5
+ scar_keyword = "burnsevere"
+
+/datum/wound/burn/critical
+ name = "Catastrophic Burns"
+ desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity."
+ treat_text = "Immediate surgical debriding of any infected skin, followed by potent tissue regeneration formula and bandaging."
+ examine_desc = "is a ruined mess of blanched bone, melted fat, and charred tissue"
+ occur_text = "vaporizes as flesh, bone, and fat melt together in a horrifying mess"
+ severity = WOUND_SEVERITY_CRITICAL
+ damage_mulitplier_penalty = 1.15
+ sound_effect = 'sound/effects/wounds/sizzle2.ogg'
+ threshold_minimum = 150
+ threshold_penalty = 80
+ status_effect_type = /datum/status_effect/wound/burn/critical
+ treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
+ infestation_rate = 0.15 // appx 4.33 minutes to reach sepsis without any treatment
+ flesh_damage = 20
+ scar_keyword = "burncritical"
diff --git a/code/datums/wounds/loss.dm b/code/datums/wounds/loss.dm
new file mode 100644
index 0000000000..6c5e536fb2
--- /dev/null
+++ b/code/datums/wounds/loss.dm
@@ -0,0 +1,41 @@
+/datum/wound/loss
+ name = "Dismembered"
+ desc = "oof ouch!!"
+
+ sound_effect = 'sound/effects/dismember.ogg'
+ severity = WOUND_SEVERITY_LOSS
+ threshold_minimum = 180
+ status_effect_type = null
+ scar_keyword = "dismember"
+ wound_flags = null
+
+/// Our special proc for our special dismembering, the wounding type only matters for what text we have
+/datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type=WOUND_SLASH)
+ if(!istype(dismembered_part) || !dismembered_part.owner || !(dismembered_part.body_zone in viable_zones) || isalien(dismembered_part.owner) || !dismembered_part.can_dismember())
+ qdel(src)
+ return
+
+ already_scarred = TRUE // so we don't scar a limb we don't have. If I add different levels of amputation desc, do it here
+
+ switch(wounding_type)
+ if(WOUND_BLUNT)
+ occur_text = "is shattered through the last bone holding it together, severing it completely!"
+ if(WOUND_SLASH)
+ occur_text = "is slashed through the last tissue holding it together, severing it completely!"
+ if(WOUND_PIERCE)
+ occur_text = "is pierced through the last tissue holding it together, severing it completely!"
+ if(WOUND_BURN)
+ occur_text = "is completely incinerated, falling to dust!"
+
+ victim = dismembered_part.owner
+
+ var/msg = "[victim]'s [dismembered_part.name] [occur_text]!"
+
+ victim.visible_message(msg, "Your [dismembered_part.name] [occur_text]!")
+
+ limb = dismembered_part
+ severity = WOUND_SEVERITY_LOSS
+ second_wind()
+ log_wound(victim, src)
+ dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE)
+ qdel(src)
diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm
new file mode 100644
index 0000000000..56c60b31d7
--- /dev/null
+++ b/code/datums/wounds/pierce.dm
@@ -0,0 +1,170 @@
+/*
+ Pierce
+*/
+
+/datum/wound/pierce
+ sound_effect = 'sound/weapons/slice.ogg'
+ processes = TRUE
+ wound_type = WOUND_PIERCE
+ treatable_by = list(/obj/item/stack/medical/suture)
+ treatable_tool = TOOL_CAUTERY
+ base_treat_time = 3 SECONDS
+ wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
+
+ /// How much blood we start losing when this wound is first applied
+ var/initial_flow
+ /// If gauzed, what percent of the internal bleeding actually clots of the total absorption rate
+ var/gauzed_clot_rate
+
+ /// When hit on this bodypart, we have this chance of losing some blood + the incoming damage
+ var/internal_bleeding_chance
+ /// If we let off blood when hit, the max blood lost is this * the incoming damage
+ var/internal_bleeding_coefficient
+
+/datum/wound/pierce/wound_injury(datum/wound/old_wound)
+ blood_flow = initial_flow
+
+/datum/wound/pierce/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ if(victim.stat == DEAD || wounding_dmg < 5)
+ return
+ if(victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg))
+ if(limb.current_gauze && limb.current_gauze.splint_factor)
+ wounding_dmg *= (1 - limb.current_gauze.splint_factor)
+ var/blood_bled = rand(1, wounding_dmg * internal_bleeding_coefficient) // 12 brute toolbox can cause up to 15/18/21 bloodloss on mod/sev/crit
+ switch(blood_bled)
+ if(1 to 6)
+ victim.bleed(blood_bled, TRUE)
+ if(7 to 13)
+ victim.visible_message("Blood droplets fly from the hole in [victim]'s [limb.name].", "You cough up a bit of blood from the blow to your [limb.name].", vision_distance=COMBAT_MESSAGE_RANGE)
+ victim.bleed(blood_bled, TRUE)
+ if(14 to 19)
+ victim.visible_message("A small stream of blood spurts from the hole in [victim]'s [limb.name]!", "You spit out a string of blood from the blow to your [limb.name]!", vision_distance=COMBAT_MESSAGE_RANGE)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
+ victim.bleed(blood_bled)
+ if(20 to INFINITY)
+ victim.visible_message("A spray of blood streams from the gash in [victim]'s [limb.name]!", "You choke up on a spray of blood from the blow to your [limb.name]!", vision_distance=COMBAT_MESSAGE_RANGE)
+ victim.bleed(blood_bled)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
+ victim.add_splatter_floor(get_step(victim.loc, victim.dir))
+
+/datum/wound/pierce/handle_process()
+ blood_flow = min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)
+
+ if(victim.bodytemperature < (BODYTEMP_NORMAL - 10))
+ blood_flow -= 0.2
+ if(prob(5))
+ to_chat(victim, "You feel the [lowertext(name)] in your [limb.name] firming up from the cold!")
+
+ if(victim.reagents?.has_reagent(/datum/reagent/toxin/heparin))
+ blood_flow += 0.5 // old herapin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first
+
+ if(limb.current_gauze)
+ blood_flow -= limb.current_gauze.absorption_rate * gauzed_clot_rate
+ limb.current_gauze.absorption_capacity -= limb.current_gauze.absorption_rate
+
+ if(blood_flow <= 0)
+ qdel(src)
+
+/datum/wound/pierce/on_stasis()
+ . = ..()
+ if(blood_flow <= 0)
+ qdel(src)
+
+/datum/wound/pierce/treat(obj/item/I, mob/user)
+ if(istype(I, /obj/item/stack/medical/suture))
+ suture(I, user)
+ else if(I.tool_behaviour == TOOL_CAUTERY || I.get_temperature() > 300)
+ tool_cauterize(I, user)
+
+/datum/wound/pierce/on_xadone(power)
+ . = ..()
+ blood_flow -= 0.03 * power // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
+
+/datum/wound/pierce/on_synthflesh(power)
+ . = ..()
+ blood_flow -= 0.05 * power // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates
+
+/// If someone is using a suture to close this cut
+/datum/wound/pierce/proc/suture(obj/item/stack/medical/suture/I, mob/user)
+ var/self_penalty_mult = (user == victim ? 1.4 : 1)
+ user.visible_message("[user] begins stitching [victim]'s [limb.name] with [I]...", "You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")
+ if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+ user.visible_message("[user] stitches up some of the bleeding on [victim].", "You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].")
+ var/blood_sutured = I.stop_bleeding / self_penalty_mult * 0.5
+ blood_flow -= blood_sutured
+ limb.heal_damage(I.heal_brute, I.heal_burn)
+
+ if(blood_flow > 0)
+ try_treating(I, user)
+ else
+ to_chat(user, "You successfully close the hole in [user == victim ? "your" : "[victim]'s"] [limb.name].")
+
+/// If someone is using either a cautery tool or something with heat to cauterize this pierce
+/datum/wound/pierce/proc/tool_cauterize(obj/item/I, mob/user)
+ var/self_penalty_mult = (user == victim ? 1.5 : 1)
+ user.visible_message("[user] begins cauterizing [victim]'s [limb.name] with [I]...", "You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")
+ if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+
+ user.visible_message("[user] cauterizes some of the bleeding on [victim].", "You cauterize some of the bleeding on [victim].")
+ limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
+ if(prob(30))
+ victim.emote("scream")
+ var/blood_cauterized = (0.6 / self_penalty_mult) * 0.5
+ blood_flow -= blood_cauterized
+
+ if(blood_flow > 0)
+ try_treating(I, user)
+
+/datum/wound/pierce/moderate
+ name = "Minor Breakage"
+ desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area."
+ treat_text = "Treat affected site with bandaging or exposure to extreme cold. In dire cases, brief exposure to vacuum may suffice." // space is cold in ss13, so it's like an ice pack!
+ examine_desc = "has a small, circular hole, gently bleeding"
+ occur_text = "spurts out a thin stream of blood"
+ sound_effect = 'sound/effects/wounds/pierce1.ogg'
+ severity = WOUND_SEVERITY_MODERATE
+ initial_flow = 1.5
+ gauzed_clot_rate = 0.8
+ internal_bleeding_chance = 30
+ internal_bleeding_coefficient = 1.25
+ threshold_minimum = 40
+ threshold_penalty = 15
+ status_effect_type = /datum/status_effect/wound/pierce/moderate
+ scar_keyword = "piercemoderate"
+
+/datum/wound/pierce/severe
+ name = "Open Puncture"
+ desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability."
+ treat_text = "Repair punctures in skin by suture or cautery, extreme cold may also work."
+ examine_desc = "is pierced clear through, with bits of tissue obscuring the open hole"
+ occur_text = "looses a violent spray of blood, revealing a pierced wound"
+ sound_effect = 'sound/effects/wounds/pierce2.ogg'
+ severity = WOUND_SEVERITY_SEVERE
+ initial_flow = 2.25
+ gauzed_clot_rate = 0.6
+ internal_bleeding_chance = 60
+ internal_bleeding_coefficient = 1.5
+ threshold_minimum = 60
+ threshold_penalty = 25
+ status_effect_type = /datum/status_effect/wound/pierce/severe
+ scar_keyword = "piercesevere"
+
+/datum/wound/pierce/critical
+ name = "Ruptured Cavity"
+ desc = "Patient's internal tissue and circulatory system is shredded, causing significant internal bleeding and damage to internal organs."
+ treat_text = "Surgical repair of puncture wound, followed by supervised resanguination."
+ examine_desc = "is ripped clear through, barely held together by exposed bone"
+ occur_text = "blasts apart, sending chunks of viscera flying in all directions"
+ sound_effect = 'sound/effects/wounds/pierce3.ogg'
+ severity = WOUND_SEVERITY_CRITICAL
+ initial_flow = 3
+ gauzed_clot_rate = 0.4
+ internal_bleeding_chance = 80
+ internal_bleeding_coefficient = 1.75
+ threshold_minimum = 110
+ threshold_penalty = 40
+ status_effect_type = /datum/status_effect/wound/pierce/critical
+ scar_keyword = "piercecritical"
+ wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm
new file mode 100644
index 0000000000..9044835272
--- /dev/null
+++ b/code/datums/wounds/slash.dm
@@ -0,0 +1,300 @@
+/*
+ Cuts
+*/
+
+/datum/wound/slash
+ sound_effect = 'sound/weapons/slice.ogg'
+ processes = TRUE
+ wound_type = WOUND_SLASH
+ treatable_by = list(/obj/item/stack/medical/suture)
+ treatable_by_grabbed = list(/obj/item/gun/energy/laser)
+ treatable_tool = TOOL_CAUTERY
+ base_treat_time = 3 SECONDS
+ wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
+
+ /// How much blood we start losing when this wound is first applied
+ var/initial_flow
+ /// When we have less than this amount of flow, either from treatment or clotting, we demote to a lower cut or are healed of the wound
+ var/minimum_flow
+ /// How fast our blood flow will naturally decrease per tick, not only do larger cuts bleed more faster, they clot slower
+ var/clot_rate
+
+ /// Once the blood flow drops below minimum_flow, we demote it to this type of wound. If there's none, we're all better
+ var/demotes_to
+
+ /// How much staunching per type (cautery, suturing, bandaging) you can have before that type is no longer effective for this cut NOT IMPLEMENTED
+ var/max_per_type
+ /// The maximum flow we've had so far
+ var/highest_flow
+
+ /// A bad system I'm using to track the worst scar we earned (since we can demote, we want the biggest our wound has been, not what it was when it was cured (probably moderate))
+ var/datum/scar/highest_scar
+
+/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null)
+ blood_flow = initial_flow
+ if(old_wound)
+ blood_flow = max(old_wound.blood_flow, initial_flow)
+ if(old_wound.severity > severity && old_wound.highest_scar)
+ highest_scar = old_wound.highest_scar
+ old_wound.highest_scar = null
+
+ if(!highest_scar)
+ highest_scar = new
+ highest_scar.generate(limb, src, add_to_scars=FALSE)
+
+/datum/wound/slash/remove_wound(ignore_limb, replaced)
+ if(!replaced && highest_scar)
+ already_scarred = TRUE
+ highest_scar.lazy_attach(limb)
+ return ..()
+
+/datum/wound/slash/get_examine_description(mob/user)
+ if(!limb.current_gauze)
+ return ..()
+
+ var/list/msg = list("The cuts on [victim.p_their()] [limb.name] are wrapped with")
+ // how much life we have left in these bandages
+ switch(limb.current_gauze.absorption_capacity)
+ if(0 to 1.25)
+ msg += "nearly ruined "
+ if(1.25 to 2.75)
+ msg += "badly worn "
+ if(2.75 to 4)
+ msg += "slightly bloodied "
+ if(4 to INFINITY)
+ msg += "clean "
+ msg += "[limb.current_gauze.name]!"
+
+ return "[msg.Join()]"
+
+/datum/wound/slash/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ if(victim.stat != DEAD && wounding_type == WOUND_SLASH) // can't stab dead bodies to make it bleed faster this way
+ blood_flow += 0.05 * wounding_dmg
+
+/datum/wound/slash/drag_bleed_amount()
+ // say we have 3 severe cuts with 3 blood flow each, pretty reasonable
+ // compare with being at 100 brute damage before, where you bled (brute/100 * 2), = 2 blood per tile
+ var/bleed_amt = min(blood_flow * 0.1, 1) // 3 * 3 * 0.1 = 0.9 blood total, less than before! the share here is .3 blood of course.
+
+ if(limb.current_gauze) // gauze stops all bleeding from dragging on this limb, but wears the gauze out quicker
+ limb.seep_gauze(bleed_amt * 0.33)
+ return
+
+ return bleed_amt
+
+/datum/wound/slash/handle_process()
+ if(victim.stat == DEAD)
+ blood_flow -= max(clot_rate, WOUND_SLASH_DEAD_CLOT_MIN)
+ if(blood_flow < minimum_flow)
+ if(demotes_to)
+ replace_wound(demotes_to)
+ return
+ qdel(src)
+ return
+
+ blood_flow = min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)
+
+ if(victim.reagents?.has_reagent(/datum/reagent/toxin/heparin))
+ blood_flow += 0.5 // old herapin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first
+
+ if(limb.current_gauze)
+ if(clot_rate > 0)
+ blood_flow -= clot_rate
+ blood_flow -= limb.current_gauze.absorption_rate
+ limb.seep_gauze(limb.current_gauze.absorption_rate)
+ else
+ blood_flow -= clot_rate
+
+ if(blood_flow > highest_flow)
+ highest_flow = blood_flow
+
+ if(blood_flow < minimum_flow)
+ if(demotes_to)
+ replace_wound(demotes_to)
+ else
+ to_chat(victim, "The cut on your [limb.name] has stopped bleeding!")
+ qdel(src)
+
+
+/datum/wound/slash/on_stasis()
+ if(blood_flow >= minimum_flow)
+ return
+ if(demotes_to)
+ replace_wound(demotes_to)
+ return
+ qdel(src)
+
+/* BEWARE, THE BELOW NONSENSE IS MADNESS. bones.dm looks more like what I have in mind and is sufficiently clean, don't pay attention to this messiness */
+
+/datum/wound/slash/check_grab_treatments(obj/item/I, mob/user)
+ if(istype(I, /obj/item/gun/energy/laser))
+ return TRUE
+
+/datum/wound/slash/treat(obj/item/I, mob/user)
+ if(istype(I, /obj/item/gun/energy/laser))
+ las_cauterize(I, user)
+ else if(I.tool_behaviour == TOOL_CAUTERY || I.get_temperature() > 300)
+ tool_cauterize(I, user)
+ else if(istype(I, /obj/item/stack/medical/suture))
+ suture(I, user)
+
+/datum/wound/slash/try_handling(mob/living/carbon/human/user)
+ if(user.pulling != victim || user.zone_selected != limb.body_zone || user.a_intent == INTENT_GRAB)
+ return FALSE
+
+ if(!iscatperson(user))
+ return FALSE
+
+ lick_wounds(user)
+ return TRUE
+
+/// if a felinid is licking this cut to reduce bleeding
+/datum/wound/slash/proc/lick_wounds(mob/living/carbon/human/user)
+ if(INTERACTING_WITH(user, victim))
+ to_chat(user, "You're already interacting with [victim]!")
+ return
+
+ if(user.is_mouth_covered())
+ to_chat(user, "Your mouth is covered, you can't lick [victim]'s wounds!")
+ return
+
+ if(!user.getorganslot(ORGAN_SLOT_TONGUE))
+ to_chat(user, "You can't lick wounds without a tongue!") // f in chat
+ return
+
+ // transmission is one way patient -> felinid since google said cat saliva is antiseptic or whatever, and also because felinids are already risking getting beaten for this even without people suspecting they're spreading a deathvirus
+ for(var/datum/disease/D in victim.diseases)
+ user.ForceContractDisease(D)
+
+ user.visible_message("[user] begins licking the wounds on [victim]'s [limb.name].", "You begin licking the wounds on [victim]'s [limb.name]...", ignored_mobs=victim)
+ to_chat(victim, "[user] begins to lick the wounds on your [limb.name].[user] licks the wounds on [victim]'s [limb.name].", "You lick some of the wounds on [victim]'s [limb.name]", ignored_mobs=victim)
+ to_chat(victim, "[user] licks the wounds on your [limb.name]! minimum_flow)
+ try_handling(user)
+ else if(demotes_to)
+ to_chat(user, "You successfully lower the severity of [victim]'s cuts.")
+
+/datum/wound/slash/on_xadone(power)
+ . = ..()
+ blood_flow -= 0.03 * power // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
+
+/datum/wound/slash/on_synthflesh(power)
+ . = ..()
+ blood_flow -= 0.075 * power // 20u * 0.075 = -1.5 blood flow, pretty good for how little effort it is
+
+/// If someone's putting a laser gun up to our cut to cauterize it
+/datum/wound/slash/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user)
+ var/self_penalty_mult = (user == victim ? 1.25 : 1)
+ user.visible_message("[user] begins aiming [lasgun] directly at [victim]'s [limb.name]...", "You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [limb.name]...")
+ if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+ var/damage = lasgun.chambered.BB.damage
+ lasgun.chambered.BB.wound_bonus -= 30
+ lasgun.chambered.BB.damage *= self_penalty_mult
+ if(!lasgun.process_fire(victim, victim, TRUE, null, limb.body_zone))
+ return
+ victim.emote("scream")
+ blood_flow -= damage / (5 * self_penalty_mult) // 20 / 5 = 4 bloodflow removed, p good
+ victim.visible_message("The cuts on [victim]'s [limb.name] scar over!")
+
+/// If someone is using either a cautery tool or something with heat to cauterize this cut
+/datum/wound/slash/proc/tool_cauterize(obj/item/I, mob/user)
+ var/self_penalty_mult = (user == victim ? 1.5 : 1)
+ user.visible_message("[user] begins cauterizing [victim]'s [limb.name] with [I]...", "You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")
+ if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+
+ user.visible_message("[user] cauterizes some of the bleeding on [victim].", "You cauterize some of the bleeding on [victim].")
+ limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
+ if(prob(30))
+ victim.emote("scream")
+ var/blood_cauterized = (0.6 / self_penalty_mult)
+ blood_flow -= blood_cauterized
+
+ if(blood_flow > minimum_flow)
+ try_treating(I, user)
+ else if(demotes_to)
+ to_chat(user, "You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts.")
+
+/// If someone is using a suture to close this cut
+/datum/wound/slash/proc/suture(obj/item/stack/medical/suture/I, mob/user)
+ var/self_penalty_mult = (user == victim ? 1.4 : 1)
+ user.visible_message("[user] begins stitching [victim]'s [limb.name] with [I]...", "You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")
+
+ if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
+ return
+ user.visible_message("[user] stitches up some of the bleeding on [victim].", "You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].")
+ var/blood_sutured = I.stop_bleeding / self_penalty_mult
+ blood_flow -= blood_sutured
+ limb.heal_damage(I.heal_brute, I.heal_burn)
+
+ if(blood_flow > minimum_flow)
+ try_treating(I, user)
+ else if(demotes_to)
+ to_chat(user, "You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts.")
+
+
+/datum/wound/slash/moderate
+ name = "Rough Abrasion"
+ desc = "Patient's skin has been badly scraped, generating moderate blood loss."
+ treat_text = "Application of clean bandages or first-aid grade sutures, followed by food and rest."
+ examine_desc = "has an open cut"
+ occur_text = "is cut open, slowly leaking blood"
+ sound_effect = 'sound/effects/wounds/blood1.ogg'
+ severity = WOUND_SEVERITY_MODERATE
+ initial_flow = 1.5
+ minimum_flow = 0.375
+ max_per_type = 3
+ clot_rate = 0.12
+ threshold_minimum = 30
+ threshold_penalty = 10
+ status_effect_type = /datum/status_effect/wound/slash/moderate
+ scar_keyword = "slashmoderate"
+
+/datum/wound/slash/severe
+ name = "Open Laceration"
+ desc = "Patient's skin is ripped clean open, allowing significant blood loss."
+ treat_text = "Speedy application of first-aid grade sutures and clean bandages, followed by vitals monitoring to ensure recovery."
+ examine_desc = "has a severe cut"
+ occur_text = "is ripped open, veins spurting blood"
+ sound_effect = 'sound/effects/wounds/blood2.ogg'
+ severity = WOUND_SEVERITY_SEVERE
+ initial_flow = 2.4375
+ minimum_flow = 2.0625
+ clot_rate = 0.07
+ max_per_type = 4
+ threshold_minimum = 60
+ threshold_penalty = 25
+ demotes_to = /datum/wound/slash/moderate
+ status_effect_type = /datum/status_effect/wound/slash/severe
+ scar_keyword = "slashsevere"
+
+/datum/wound/slash/critical
+ name = "Weeping Avulsion"
+ desc = "Patient's skin is completely torn open, along with significant loss of tissue. Extreme blood loss will lead to quick death without intervention."
+ treat_text = "Immediate bandaging and either suturing or cauterization, followed by supervised resanguination."
+ examine_desc = "is carved down to the bone, spraying blood wildly"
+ occur_text = "is torn open, spraying blood wildly"
+ sound_effect = 'sound/effects/wounds/blood3.ogg'
+ severity = WOUND_SEVERITY_CRITICAL
+ initial_flow = 3.1875
+ minimum_flow = 3
+ clot_rate = -0.05 // critical cuts actively get worse instead of better
+ max_per_type = 5
+ threshold_minimum = 90
+ threshold_penalty = 40
+ demotes_to = /datum/wound/slash/severe
+ status_effect_type = /datum/status_effect/wound/slash/critical
+ scar_keyword = "slashcritical"
+ wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index e24da67611..dfa9776489 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -70,6 +70,9 @@
/// A luminescence-shifted value of the last color calculated for chatmessage overlays
var/chat_color_darkened
+ ///Mobs that are currently do_after'ing this atom, to be cleared from on Destroy()
+ var/list/targeted_by
+
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -144,6 +147,11 @@
LAZYCLEARLIST(overlays)
LAZYCLEARLIST(priority_overlays)
+ for(var/i in targeted_by)
+ var/mob/M = i
+ LAZYREMOVE(M.do_afters, src)
+ targeted_by = null
+
QDEL_NULL(light)
return ..()
@@ -219,7 +227,7 @@
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)
if(does_attack_animation)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
log_combat(user, src, "punched", "hulk powers")
user.do_attack_animation(src, ATTACK_EFFECT_SMASH)
@@ -954,15 +962,16 @@
if(source != target)
target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE)
-/*
-Proc for attack log creation, because really why not
-1 argument is the actor performing the action
-2 argument is the target of the action
-3 is a verb describing the action (e.g. punched, throwed, kicked, etc.)
-4 is a tool with which the action was made (usually an item)
-5 is any additional text, which will be appended to the rest of the log line
-*/
-
+/**
+ * Log a combat message in the attack log
+ *
+ * Arguments:
+ * * atom/user - argument is the actor performing the action
+ * * atom/target - argument is the target of the action
+ * * what_done - is a verb describing the action (e.g. punched, throwed, kicked, etc.)
+ * * atom/object - is a tool with which the action was made (usually an item)
+ * * addition - is any additional text, which will be appended to the rest of the log line
+ */
/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null)
var/ssource = key_name(user)
var/starget = key_name(target)
@@ -986,6 +995,39 @@ Proc for attack log creation, because really why not
var/reverse_message = "has been [what_done] by [ssource][postfix]"
target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE)
+/**
+ * log_wound() is for when someone is *attacked* and suffers a wound. Note that this only captures wounds from damage, so smites/forced wounds aren't logged, as well as demotions like cuts scabbing over
+ *
+ * Note that this has no info on the attack that dealt the wound: information about where damage came from isn't passed to the bodypart's damaged proc. When in doubt, check the attack log for attacks at that same time
+ * TODO later: Add logging for healed wounds, though that will require some rewriting of healing code to prevent admin heals from spamming the logs. Not high priority
+ *
+ * Arguments:
+ * * victim- The guy who got wounded
+ * * suffered_wound- The wound, already applied, that we're logging. It has to already be attached so we can get the limb from it
+ * * dealt_damage- How much damage is associated with the attack that dealt with this wound.
+ * * dealt_wound_bonus- The wound_bonus, if one was specified, of the wounding attack
+ * * dealt_bare_wound_bonus- The bare_wound_bonus, if one was specified *and applied*, of the wounding attack. Not shown if armor was present
+ * * base_roll- Base wounding ability of an attack is a random number from 1 to (dealt_damage ** WOUND_DAMAGE_EXPONENT). This is the number that was rolled in there, before mods
+ */
+/proc/log_wound(atom/victim, datum/wound/suffered_wound, dealt_damage, dealt_wound_bonus, dealt_bare_wound_bonus, base_roll)
+ if(QDELETED(victim) || !suffered_wound)
+ return
+ var/message = "has suffered: [suffered_wound][suffered_wound.limb ? " to [suffered_wound.limb.name]" : null]"// maybe indicate if it's a promote/demote?
+
+ if(dealt_damage)
+ message += " | Damage: [dealt_damage]"
+ // The base roll is useful since it can show how lucky someone got with the given attack. For example, dealing a cut
+ if(base_roll)
+ message += " (rolled [base_roll]/[dealt_damage ** WOUND_DAMAGE_EXPONENT])"
+
+ if(dealt_wound_bonus)
+ message += " | WB: [dealt_wound_bonus]"
+
+ if(dealt_bare_wound_bonus)
+ message += " | BWB: [dealt_bare_wound_bonus]"
+
+ victim.log_message(message, LOG_ATTACK, color="blue")
+
// Filter stuff
/atom/proc/add_filter(name,priority,list/params)
LAZYINITLIST(filter_data)
diff --git a/code/game/atoms_movement.dm b/code/game/atoms_movement.dm
index 68db17f076..db9424d983 100644
--- a/code/game/atoms_movement.dm
+++ b/code/game/atoms_movement.dm
@@ -6,6 +6,7 @@
// To be removed on step_ conversion
// All this work to prevent a second bump
/atom/movable/Move(atom/newloc, direct=0)
+ set waitfor = FALSE //n o
. = FALSE
if(!newloc || newloc == loc)
return
@@ -52,6 +53,7 @@
////////////////////////////////////////
/atom/movable/Move(atom/newloc, direct)
+ set waitfor = FALSE //n o
var/atom/movable/pullee = pulling
var/turf/T = loc
if(!moving_from_pull)
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 5666f2442f..406e142a25 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -38,7 +38,8 @@ Credit where due:
5. Xhuis from /tg/ for coding the first iteration of the mode, and the new, reworked version
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release prior to its rework
7. Clockwork cult code as of now, at least the one being pulled from Citadel Station's master branch, is being, or already is, fixed by Coolgat3 and Avunia.
-
+8. Modern clockwork cult code mixed with original clockwork code, with various changes to make it less of a fustercluck, done by KeRSe. \
+ Fixes and assistance done by TimothyTeakettle, Kevinz000, and Deltafire15. -Very glad for the help they gave.
*/
///////////
@@ -133,7 +134,7 @@ Credit where due:
config_tag = "clockwork_cult"
antag_flag = ROLE_SERVANT_OF_RATVAR
false_report_weight = 10
- required_players = 35
+ required_players = 24 //Fixing this directly for now since apparently config machine for forcing modes broke.
required_enemies = 3
recommended_enemies = 5
enemy_minimum_age = 7
@@ -143,13 +144,12 @@ Credit where due:
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
Servants: Construct defenses to protect the Ark. Sabotage the station!\n\
Crew: Stop the servants before they can summon the Clockwork Justiciar."
- var/servants_to_serve = list()
+ var/list/servants_to_serve = list() //Yes this list is made out of list
var/roundstart_player_count
- var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
var/datum/team/clockcult/main_clockcult
-/datum/game_mode/clockwork_cult/pre_setup()
+/datum/game_mode/clockwork_cult/pre_setup() //Gamemode and job code is pain. Have fun codediving all of that stuff, whoever works on this next - Delta
var/list/errorList = list()
var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE)
if(errorList.len) // reebe failed to load
@@ -162,38 +162,36 @@ Credit where due:
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
- var/starter_servants = 4 //Guaranteed four servants
+ var/starter_servants = 4 //Try to go for at least four
var/number_players = num_players()
roundstart_player_count = number_players
if(number_players > 30) //plus one servant for every additional 10 players above 30
number_players -= 30
starter_servants += round(number_players / 10)
- starter_servants = min(starter_servants, 8) //max 8 servants (that sould only happen with a ton of players)
- GLOB.clockwork_vitality += 50 * starter_servants //some starter Vitality to help recover from initial fuck ups
+ starter_servants = min(starter_servants, 8) //max 8 servants (that sould only happen with a ton of players)
while(starter_servants)
+ if(!antag_candidates.len)
+ break //Skip setup, DO NOT RUNTIME
var/datum/mind/servant = antag_pick(antag_candidates)
servants_to_serve += servant
antag_candidates -= servant
- servant.assigned_role = ROLE_SERVANT_OF_RATVAR
servant.special_role = ROLE_SERVANT_OF_RATVAR
+ servant.restricted_roles = restricted_jobs
starter_servants--
- ark_time = 30 + round((roundstart_player_count / 5)) //In minutes, how long the Ark will wait before activation
- ark_time = min(ark_time, 35) //35 minute maximum for the activation timer
- return 1
+ if(!servants_to_serve.len) //Uh oh, something went wrong
+ setup_error = "There are no clockcult candidates! (Or something went very wrong)"
+ return FALSE
+ GLOB.clockwork_vitality += 50 * servants_to_serve.len //some starter Vitality to help recover from initial fuck ups
+ return TRUE //Haha yes it works time to not touch it any more than that.
/datum/game_mode/clockwork_cult/post_setup()
for(var/S in servants_to_serve)
var/datum/mind/servant = S
log_game("[key_name(servant)] was made an initial servant of Ratvar")
var/mob/living/L = servant.current
- var/turf/T = pick(GLOB.servant_spawns)
- L.forceMove(T)
- GLOB.servant_spawns -= T
greet_servant(L)
equip_servant(L)
add_servant_of_ratvar(L, TRUE)
- var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful
- G.final_countdown(ark_time)
..()
return 1
@@ -201,22 +199,23 @@ Credit where due:
if(!M)
return 0
to_chat(M, "You are a servant of Ratvar, the Clockwork Justiciar!")
- to_chat(M, "You have approximately [ark_time] minutes until the Ark activates.")
- to_chat(M, "Unlock Script scripture by converting a new servant.")
- to_chat(M, "Application scripture will be unlocked halfway until the Ark's activation.")
+ to_chat(M, "Unlock Script scripture by converting a new servant or when 35kw of power is reached.")
+ to_chat(M, "Application scripture will be unlocked when 50kw of power is reached.")
M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
return 1
-/datum/game_mode/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component
+/datum/game_mode/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob
if(!M || !ishuman(M))
return FALSE
var/mob/living/carbon/human/L = M
- L.equipOutfit(/datum/outfit/servant_of_ratvar)
var/obj/item/clockwork/slab/S = new
var/slot = "At your feet"
- var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK, "On your belt" = SLOT_BELT)
+ var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK)
if(ishuman(L))
var/mob/living/carbon/human/H = L
+ var/obj/item/clockwork/replica_fabricator/F = new
+ if(H.equip_to_slot_or_del(F, SLOT_IN_BACKPACK))
+ to_chat(H, "You have been equipped with a replica fabricator, an advanced tool that can convert objects like doors, tables or even coats into clockwork equivalents.")
slot = H.equip_in_one_of_slots(S, slots)
if(slot == "In your backpack")
slot = "In your [H.back.name]"
@@ -224,7 +223,6 @@ Credit where due:
if(!S.forceMove(get_turf(L)))
qdel(S)
if(S && !QDELETED(S))
- to_chat(L, "There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.")
to_chat(L, "[slot] is a clockwork slab, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
as a servant, you can find a concise tutorial in the Recollection category of its interface.")
to_chat(L, "If you want more information, you can read the wiki page to learn more.")
@@ -278,7 +276,7 @@ Credit where due:
gloves = /obj/item/clothing/gloves/color/yellow
belt = /obj/item/storage/belt/utility/servant
backpack_contents = list(/obj/item/storage/box/engineer = 1, \
- /obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1, /obj/item/reagent_containers/food/drinks/bottle/holyoil = 1)
+ /obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/reagent_containers/food/drinks/bottle/holyoil = 1)
id = /obj/item/pda
var/plasmaman //We use this to determine if we should activate internals in post_equip()
@@ -305,54 +303,3 @@ Credit where due:
PDA.update_label()
PDA.id_check(H, W)
H.sec_hud_set_ID()
-
-
-//This paper serves as a quick run-down to the cult as well as a changelog to refer to.
-//Check strings/clockwork_cult_changelog.txt for the changelog, and update it when you can!
-/obj/item/paper/servant_primer
- name = "The Ark And You: A Primer On Servitude"
- color = "#DAAA18"
- info = "DON'T PANIC.
\
- Here's a quick primer on what you should know here.\
-
\
-
You're in a place called Reebe right now. The crew can't get here normally.
\
-
In the north is your base camp, with supplies, consoles, and the Ark. In the south is an inaccessible area that the crew can walk between \
- once they arrive (more on that later.) Everything between that space is an open area.
\
-
Your job as a servant is to build fortifications and defenses to protect the Ark and your base once the Ark activates. You can do this \
- however you like, but work with your allies and coordinate your efforts.
\
-
Once the Ark activates, the station will be alerted. Portals to Reebe will open up in nearly every room. When they take these portals, \
- the crewmembers will arrive in the area that you can't access, but can get through it freely - whereas you can't. Treat this as the \"spawn\" of the \
- crew and defend it accordingly.
\
- \
- \
- Here is the layout of Reebe, from left to right:\
-
\
-
Dressing Room: Contains clothing, a dresser, and a mirror. There are spare slabs and absconders here.
\
-
Listening Station: Contains intercoms, a telecomms relay, and a list of frequencies.
\
-
Ark Chamber: Houses the Ark.
\
-
Observation Room: Contains five camera observers. These can be used to watch the station through its cameras, as well as to teleport down \
- to most areas. To do this, use the Warp action while hovering over the tile you want to warp to.
\
-
Infirmary: Contains sleepers and basic medical supplies for superficial wounds. The sleepers can consume Vitality to heal any occupants. \
- This room is generally more useful during the preparation phase; when defending the Ark, scripture is more useful.
"
- return output
-
-/obj/machinery/mecha_part_fabricator/proc/check_clearance(datum/design/D)
- if(!(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z)) && !ISINRANGE(GLOB.security_level, D.min_security_level, D.max_security_level))
- return FALSE
- return TRUE
-
-/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D)
- var/clearance = !(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z))
- var/sec_text = ""
- if(clearance && (D.min_security_level > SEC_LEVEL_GREEN || D.max_security_level < SEC_LEVEL_DELTA))
- sec_text = " (Allowed security levels: "
- for(var/n in D.min_security_level to D.max_security_level)
- sec_text += NUM2SECLEVEL(n)
- if(n + 1 <= D.max_security_level)
- sec_text += ", "
- sec_text += ") "
- var/output = "[initial(D.name)] (Cost: [output_part_cost(D)]) [sec_text][get_construction_time_w_coeff(D)/10]sec"
- return output
-
-/obj/machinery/mecha_part_fabricator/proc/output_part_cost(datum/design/D)
- var/i = 0
- var/output
+/**
+ * Generates an info list for a given part.
+ *
+ * Returns a list of part information.
+ * * D - Design datum to get information on.
+ * * categories - Boolean, whether or not to parse snowflake categories into the part information list.
+ */
+/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, categories = FALSE)
+ var/cost = list()
for(var/c in D.materials)
var/datum/material/M = c
- output += "[i?" | ":null][get_resource_cost_w_coeff(D, M)] [M.name]"
- i++
- return output
+ cost[M.name] = get_resource_cost_w_coeff(D, M)
+ var/obj/built_item = D.build_path
+
+ var/list/category_override = null
+ var/list/sub_category = null
+
+ if(categories)
+ // Handle some special cases to build up sub-categories for the fab interface.
+ // Start with checking if this design builds a cyborg module.
+ if(built_item in typesof(/obj/item/borg/upgrade))
+ var/obj/item/borg/upgrade/U = built_item
+ var/module_types = initial(U.module_flags)
+ sub_category = list()
+ if(module_types)
+ if(module_types & BORG_MODULE_SECURITY)
+ sub_category += "Security"
+ if(module_types & BORG_MODULE_MINER)
+ sub_category += "Mining"
+ if(module_types & BORG_MODULE_JANITOR)
+ sub_category += "Janitor"
+ if(module_types & BORG_MODULE_MEDICAL)
+ sub_category += "Medical"
+ if(module_types & BORG_MODULE_ENGINEERING)
+ sub_category += "Engineering"
+ else
+ sub_category += "All Cyborgs"
+ // Else check if this design builds a piece of exosuit equipment.
+ else if(built_item in typesof(/obj/item/mecha_parts/mecha_equipment))
+ var/obj/item/mecha_parts/mecha_equipment/E = built_item
+ var/mech_types = initial(E.mech_flags)
+ sub_category = "Equipment"
+ if(mech_types)
+ category_override = list()
+ if(mech_types & EXOSUIT_MODULE_RIPLEY)
+ category_override += "Ripley"
+ if(mech_types & EXOSUIT_MODULE_FIREFIGHTER)
+ category_override += "Firefighter"
+ if(mech_types & EXOSUIT_MODULE_ODYSSEUS)
+ category_override += "Odysseus"
+ // if(mech_types & EXOSUIT_MODULE_CLARKE)
+ // category_override += "Clarke"
+ if(mech_types & EXOSUIT_MODULE_GYGAX_MED)
+ category_override += "Medical-Spec Gygax"
+ if(mech_types & EXOSUIT_MODULE_GYGAX)
+ category_override += "Gygax"
+ if(mech_types & EXOSUIT_MODULE_DURAND)
+ category_override += "Durand"
+ if(mech_types & EXOSUIT_MODULE_HONK)
+ category_override += "H.O.N.K"
+ if(mech_types & EXOSUIT_MODULE_PHAZON)
+ category_override += "Phazon"
+
+
+ var/list/part = list(
+ "name" = D.name,
+ "desc" = initial(built_item.desc),
+ "printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10,
+ "cost" = cost,
+ "id" = D.id,
+ "subCategory" = sub_category,
+ "categoryOverride" = category_override,
+ "searchMeta" = "UNKNOWN"//D.search_metadata
+ )
+
+ return part
+
+/**
+ * Generates a list of resources / materials available to this Exosuit Fab
+ *
+ * Returns null if there is no material container available.
+ * List format is list(material_name = list(amount = ..., ref = ..., etc.))
+ */
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
- var/output
- var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
- for(var/mat_id in materials.materials)
- var/datum/material/M = mat_id
- var/amount = materials.materials[mat_id]
- output += "[M.name]: [amount] cm³"
- if(amount >= MINERAL_MATERIAL_AMOUNT)
- output += "- Remove \[1\]"
- if(amount >= (MINERAL_MATERIAL_AMOUNT * 10))
- output += " | \[10\]"
- output += " | \[All\]"
- output += " "
- return output
+ var/datum/component/material_container/materials = rmat.mat_container
+ var/list/material_data = list()
+
+ if(materials)
+ for(var/mat_id in materials.materials)
+ var/datum/material/M = mat_id
+ var/list/material_info = list()
+ var/amount = materials.materials[mat_id]
+
+ material_info = list(
+ "name" = M.name,
+ "ref" = REF(M),
+ "amount" = amount,
+ "sheets" = round(amount / MINERAL_MATERIAL_AMOUNT),
+ "removable" = amount >= MINERAL_MATERIAL_AMOUNT
+ )
+
+ material_data += list(material_info)
+
+ return material_data
+
+ return null
+
+/**
+ * Intended to be called when an item starts printing.
+ *
+ * Adds the overlay to show the fab working and sets active power usage settings.
+ */
+/obj/machinery/mecha_part_fabricator/proc/on_start_printing()
+ add_overlay("fab-active")
+ use_power = ACTIVE_POWER_USE
+
+/**
+ * Intended to be called when the exofab has stopped working and is no longer printing items.
+ *
+ * Removes the overlay to show the fab working and sets idle power usage settings. Additionally resets the description and turns off queue processing.
+ */
+/obj/machinery/mecha_part_fabricator/proc/on_finish_printing()
+ cut_overlay("fab-active")
+ use_power = IDLE_POWER_USE
+ desc = initial(desc)
+ process_queue = FALSE
+
+/**
+ * Calculates resource/material costs for printing an item based on the machine's resource coefficient.
+ *
+ * Returns a list of k,v resources with their amounts.
+ * * D - Design datum to calculate the modified resource cost of.
+ */
/obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D)
var/list/resources = list()
for(var/R in D.materials)
@@ -164,294 +247,419 @@
resources[M] = get_resource_cost_w_coeff(D, M)
return resources
+/**
+ * Checks if the Exofab has enough resources to print a given item.
+ *
+ * Returns FALSE if the design has no reagents used in its construction (?) or if there are insufficient resources.
+ * Returns TRUE if there are sufficient resources to print the item.
+ * * D - Design datum to calculate the modified resource cost of.
+ */
/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D)
- if(D.reagents_list.len) // No reagents storage - no reagent designs.
+ if(length(D.reagents_list)) // No reagents storage - no reagent designs.
return FALSE
- var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
+ var/datum/component/material_container/materials = rmat.mat_container
if(materials.has_materials(get_resources_w_coeff(D)))
return TRUE
return FALSE
-/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D)
+/**
+ * Attempts to build the next item in the build queue.
+ *
+ * Returns FALSE if either there are no more parts to build or the next part is not buildable.
+ * Returns TRUE if the next part has started building.
+ * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build.
+ */
+/obj/machinery/mecha_part_fabricator/proc/build_next_in_queue(verbose = TRUE)
+ if(!length(queue))
+ return FALSE
+
+ var/datum/design/D = queue[1]
+ if(build_part(D, verbose))
+ remove_from_queue(1)
+ return TRUE
+
+ return FALSE
+
+/**
+ * Starts the build process for a given design datum.
+ *
+ * Returns FALSE if the procedure fails. Returns TRUE when being_built is set.
+ * Uses materials.
+ * * D - Design datum to attempt to print.
+ * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build.
+ */
+/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D, verbose = TRUE)
+ if(!D)
+ return FALSE
+
+ var/datum/component/material_container/materials = rmat.mat_container
+ if (!materials)
+ if(verbose)
+ say("No access to material storage, please contact the quartermaster.")
+ return FALSE
+ if (rmat.on_hold())
+ if(verbose)
+ say("Mineral access is on hold, please contact the quartermaster.")
+ return FALSE
+ if(!check_resources(D))
+ if(verbose)
+ say("Not enough resources. Processing stopped.")
+ return FALSE
+
+ build_materials = get_resources_w_coeff(D)
+
+ materials.use_materials(build_materials)
being_built = D
- desc = "It's building \a [initial(D.name)]."
- var/list/res_coef = get_resources_w_coeff(D)
+ build_finish = world.time + get_construction_time_w_coeff(initial(D.construction_time))
+ build_start = world.time
+ desc = "It's building \a [D.name]."
- var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
- materials.use_materials(res_coef)
- add_overlay("fab-active")
- use_power = ACTIVE_POWER_USE
- updateUsrDialog()
- sleep(get_construction_time_w_coeff(D))
- use_power = IDLE_POWER_USE
- cut_overlay("fab-active")
- desc = initial(desc)
+ rmat.silo_log(src, "built", -1, "[D.name]", build_materials)
- var/location = get_step(src,(dir))
- var/obj/item/I = new D.build_path(location)
- I.set_custom_materials(res_coef)
- say("\The [I] is complete.")
- being_built = null
-
- updateUsrDialog()
return TRUE
-/obj/machinery/mecha_part_fabricator/proc/update_queue_on_page()
- send_byjax(usr,"mecha_fabricator.browser","queue",list_queue())
- return
+/obj/machinery/mecha_part_fabricator/process()
+ // If there's a stored part to dispense due to an obstruction, try to dispense it.
+ if(stored_part)
+ var/turf/exit = get_step(src,(dir))
+ if(exit.density)
+ return TRUE
-/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(set_name)
- if(set_name in part_sets)
- for(var/v in stored_research.researched_designs)
- var/datum/design/D = SSresearch.techweb_design_by_id(v)
- if(D.build_type & MECHFAB)
- if(set_name in D.category)
- add_to_queue(D)
+ say("Obstruction cleared. \The [stored_part] is complete.")
+ stored_part.forceMove(exit)
+ stored_part = null
-/obj/machinery/mecha_part_fabricator/proc/add_to_queue(D)
+ // If there's nothing being built, try to build something
+ if(!being_built)
+ // If we're not processing the queue anymore or there's nothing to build, end processing.
+ if(!process_queue || !build_next_in_queue())
+ on_finish_printing()
+ STOP_PROCESSING(SSfastprocess, src)
+ //end_processing()
+ return TRUE
+ on_start_printing()
+
+ // If there's an item being built, check if it is complete.
+ if(being_built && (build_finish < world.time))
+ // Then attempt to dispense it and if appropriate build the next item.
+ dispense_built_part(being_built)
+ if(process_queue)
+ build_next_in_queue(FALSE)
+ return TRUE
+
+/**
+ * Dispenses a part to the tile infront of the Exosuit Fab.
+ *
+ * Returns FALSE is the machine cannot dispense the part on the appropriate turf.
+ * Return TRUE if the part was successfully dispensed.
+ * * D - Design datum to attempt to dispense.
+ */
+/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/D)
+ var/obj/item/I = new D.build_path(src)
+ // I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this.
+ I.set_custom_materials(build_materials)
+
+ being_built = null
+
+ var/turf/exit = get_step(src,(dir))
+ if(exit.density)
+ say("Error! Part outlet is obstructed.")
+ desc = "It's trying to dispense \a [D.name], but the part outlet is obstructed."
+ stored_part = I
+ return FALSE
+
+ say("\The [I] is complete.")
+ I.forceMove(exit)
+ return TRUE
+
+/**
+ * Adds a list of datum designs to the build queue.
+ *
+ * Will only add designs that are in this machine's stored techweb.
+ * Does final checks for datum IDs and makes sure this machine can build the designs.
+ * * part_list - List of datum design ids for designs to add to the queue.
+ */
+/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(list/part_list)
+ for(var/v in stored_research.researched_designs)
+ var/datum/design/D = SSresearch.techweb_design_by_id(v)
+ if((D.build_type & MECHFAB) && (D.id in part_list))
+ add_to_queue(D)
+
+/**
+ * Adds a datum design to the build queue.
+ *
+ * Returns TRUE if successful and FALSE if the design was not added to the queue.
+ * * D - Datum design to add to the queue.
+ */
+/obj/machinery/mecha_part_fabricator/proc/add_to_queue(datum/design/D)
if(!istype(queue))
queue = list()
if(D)
queue[++queue.len] = D
- return queue.len
+ return TRUE
+ return FALSE
+/**
+ * Removes datum design from the build queue based on index.
+ *
+ * Returns TRUE if successful and FALSE if a design was not removed from the queue.
+ * * index - Index in the build queue of the element to remove.
+ */
/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index)
- if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>queue.len))
+ if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>length(queue)))
return FALSE
queue.Cut(index,++index)
return TRUE
-/obj/machinery/mecha_part_fabricator/proc/process_queue()
- var/datum/design/D = queue[1]
- if(!D)
- remove_from_queue(1)
- if(queue.len)
- return process_queue()
- else
- return
- temp = null
- while(D)
- if(stat&(NOPOWER|BROKEN))
- return FALSE
- if(!check_clearance(D))
- say("Security level not met. Queue processing stopped.")
- temp = {"Security level not met to build next part.
- Try again | Return"}
- return FALSE
- if(!check_resources(D))
- say("Not enough resources. Queue processing stopped.")
- temp = {"Not enough resources to build next part.
- Try again | Return"}
- return FALSE
- remove_from_queue(1)
- build_part(D)
- D = listgetindex(queue, 1)
- say("Queue processing finished successfully.")
-
+/**
+ * Generates a list of parts formatted for tgui based on the current build queue.
+ *
+ * Returns a formatted list of lists containing formatted part information for every part in the build queue.
+ */
/obj/machinery/mecha_part_fabricator/proc/list_queue()
- var/output = "Queue contains:"
- if(!istype(queue) || !queue.len)
- output += " Nothing"
- else
- output += ""
- var/i = 0
- for(var/datum/design/D in queue)
- i++
- var/obj/part = D.build_path
- output += "
\n" // less lines than in woundscan() so we don't overload people trying to get basic med info
+ msg += "\n"
for(var/thing in M.diseases)
var/datum/disease/D = thing
@@ -414,7 +436,7 @@ GENETICS SCANNER
var/blood_typepath = C.get_blood_id()
if(blood_typepath)
if(ishuman(C))
- if(H.bleed_rate)
+ if(H.is_bleeding())
msg += "Subject is bleeding!\n"
var/blood_percent = round((C.scan_blood_volume() / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100)
var/blood_type = C.dna.blood_type
@@ -505,6 +527,67 @@ GENETICS SCANNER
desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
advanced = TRUE
+/// Displays wounds with extended information on their status vs medscanners
+/proc/woundscan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/wound/scanner)
+ if(!istype(patient))
+ return
+
+ var/render_list = ""
+ for(var/i in patient.get_wounded_bodyparts())
+ var/obj/item/bodypart/wounded_part = i
+ render_list += "Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.name]"
+ for(var/k in wounded_part.wounds)
+ var/datum/wound/W = k
+ render_list += "
[W.get_scanner_description()]
\n"
+ render_list += ""
+
+ if(render_list == "")
+ if(istype(scanner))
+ // Only emit the cheerful scanner message if this scan came from a scanner
+ playsound(scanner, 'sound/machines/ping.ogg', 50, FALSE)
+ to_chat(user, "\The [scanner] makes a happy ping and briefly displays a smiley face with several exclamation points! It's really excited to report that [patient] has no wounds!")
+ else
+ to_chat(user, "No wounds detected in subject.")
+ else
+ to_chat(user, jointext(render_list, ""))
+
+/obj/item/healthanalyzer/wound
+ name = "first aid analyzer"
+ icon_state = "adv_spectrometer"
+ desc = "A prototype MeLo-Tech medical scanner used to diagnose injuries and recommend treatment for serious wounds, but offers no further insight into the patient's health. You hope the final version is less annoying to read!"
+ var/next_encouragement
+ var/greedy
+
+/obj/item/healthanalyzer/wound/attack_self(mob/user)
+ if(next_encouragement < world.time)
+ playsound(src, 'sound/machines/ping.ogg', 50, FALSE)
+ var/list/encouragements = list("briefly displays a happy face, gazing emptily at you", "briefly displays a spinning cartoon heart", "displays an encouraging message about eating healthy and exercising", \
+ "reminds you that everyone is doing their best", "displays a message wishing you well", "displays a sincere thank-you for your interest in first-aid", "formally absolves you of all your sins")
+ to_chat(user, "\The [src] makes a happy ping and [pick(encouragements)]!")
+ next_encouragement = world.time + 10 SECONDS
+ greedy = FALSE
+ else if(!greedy)
+ to_chat(user, "\The [src] displays an eerily high-definition frowny face, chastizing you for asking it for too much encouragement.")
+ greedy = TRUE
+ else
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
+ if(isliving(user))
+ var/mob/living/L = user
+ to_chat(L, "\The [src] makes a disappointed buzz and pricks your finger for being greedy. Ow!")
+ L.adjustBruteLoss(4)
+ L.dropItemToGround(src)
+
+/obj/item/healthanalyzer/wound/attack(mob/living/carbon/patient, mob/living/carbon/human/user)
+ add_fingerprint(user)
+ user.visible_message("[user] scans [patient] for serious injuries.", "You scan [patient] for serious injuries.")
+
+ if(!istype(patient))
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
+ to_chat(user, "\The [src] makes a sad buzz and briefly displays a frowny face, indicating it can't scan [patient].")
+ return
+
+ woundscan(user, patient, src)
+
/obj/item/analyzer
desc = "A hand-held environmental scanner which reports current gas levels. Alt-Click to use the built in barometer function."
name = "analyzer"
@@ -541,54 +624,13 @@ GENETICS SCANNER
if (user.stat || user.eye_blind)
return
- var/turf/location = user.loc
+ //Functionality moved down to proc/scan_turf()
+ var/turf/location = get_turf(user)
if(!istype(location))
return
-
- var/datum/gas_mixture/environment = location.return_air()
-
- var/pressure = environment.return_pressure()
- var/total_moles = environment.total_moles()
-
- to_chat(user, "Results:")
- if(abs(pressure - ONE_ATMOSPHERE) < 10)
- to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
- else
- to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
- if(total_moles)
-
- var/o2_concentration = environment.get_moles(/datum/gas/oxygen)/total_moles
- var/n2_concentration = environment.get_moles(/datum/gas/nitrogen)/total_moles
- var/co2_concentration = environment.get_moles(/datum/gas/carbon_dioxide)/total_moles
- var/plasma_concentration = environment.get_moles(/datum/gas/plasma)/total_moles
-
- if(abs(n2_concentration - N2STANDARD) < 20)
- to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/nitrogen), 0.01)] mol)")
- else
- to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/nitrogen), 0.01)] mol)")
-
- if(abs(o2_concentration - O2STANDARD) < 2)
- to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/oxygen), 0.01)] mol)")
- else
- to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/oxygen), 0.01)] mol)")
-
- if(co2_concentration > 0.01)
- to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/carbon_dioxide), 0.01)] mol)")
- else
- to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/carbon_dioxide), 0.01)] mol)")
-
- if(plasma_concentration > 0.005)
- to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/plasma), 0.01)] mol)")
- else
- to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/plasma), 0.01)] mol)")
-
- for(var/id in environment.get_gases())
- if(id in GLOB.hardcoded_gases)
- continue
- var/gas_concentration = environment.get_moles(id)/total_moles
- to_chat(user, "[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(environment.get_moles(id), 0.01)] mol)")
- to_chat(user, "Temperature: [round(environment.return_temperature()-T0C, 0.01)] °C ([round(environment.return_temperature(), 0.01)] K)")
-
+
+ scan_turf(user, location)
+
/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens
. = ..()
@@ -666,7 +708,7 @@ GENETICS SCANNER
var/total_moles = air_contents.total_moles()
var/pressure = air_contents.return_pressure()
- var/volume = air_contents.return_volume()
+ var/volume = air_contents.return_volume() //could just do mixture.volume... but safety, I guess?
var/temperature = air_contents.return_temperature()
var/cached_scan_results = air_contents.analyzer_results
@@ -693,6 +735,73 @@ GENETICS SCANNER
to_chat(user, "Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.")
return
+/obj/item/analyzer/proc/scan_turf(mob/user, turf/location)
+
+ var/datum/gas_mixture/environment = location.return_air()
+
+ var/pressure = environment.return_pressure()
+ var/total_moles = environment.total_moles()
+ var/cached_scan_results = environment.analyzer_results
+
+ to_chat(user, "Results:")
+ if(abs(pressure - ONE_ATMOSPHERE) < 10)
+ to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
+ else
+ to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
+ if(total_moles)
+
+ var/o2_concentration = environment.get_moles(/datum/gas/oxygen)/total_moles
+ var/n2_concentration = environment.get_moles(/datum/gas/nitrogen)/total_moles
+ var/co2_concentration = environment.get_moles(/datum/gas/carbon_dioxide)/total_moles
+ var/plasma_concentration = environment.get_moles(/datum/gas/plasma)/total_moles
+
+ if(abs(n2_concentration - N2STANDARD) < 20)
+ to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/nitrogen), 0.01)] mol)")
+ else
+ to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/nitrogen), 0.01)] mol)")
+
+ if(abs(o2_concentration - O2STANDARD) < 2)
+ to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/oxygen), 0.01)] mol)")
+ else
+ to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/oxygen), 0.01)] mol)")
+
+ if(co2_concentration > 0.01)
+ to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/carbon_dioxide), 0.01)] mol)")
+ else
+ to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/carbon_dioxide), 0.01)] mol)")
+
+ if(plasma_concentration > 0.005)
+ to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/plasma), 0.01)] mol)")
+ else
+ to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(environment.get_moles(/datum/gas/plasma), 0.01)] mol)")
+
+ for(var/id in environment.get_gases())
+ if(id in GLOB.hardcoded_gases)
+ continue
+ var/gas_concentration = environment.get_moles(id)/total_moles
+ to_chat(user, "[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(environment.get_moles(id), 0.01)] mol)")
+ to_chat(user, "Temperature: [round(environment.return_temperature()-T0C, 0.01)] °C ([round(environment.return_temperature(), 0.01)] K)")
+
+ if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
+ var/fusion_power = round(cached_scan_results["fusion"], 0.01)
+ var/tier = fusionpower2text(fusion_power)
+ to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.")
+ to_chat(user, "Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.")
+
+/obj/item/analyzer/ranged
+ desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function."
+ name = "long-range analyzer"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "ranged_analyzer"
+
+/obj/item/analyzer/ranged/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ . = ..()
+ if(target.tool_act(user, src, tool_behaviour))
+ return
+ // Tool act didn't scan it, so let's get it's turf.
+ var/turf/location = get_turf(target)
+ scan_turf(user, location)
+
//slime scanner
/obj/item/slime_scanner
@@ -878,3 +987,9 @@ GENETICS SCANNER
return "[HM.name] ([HM.alias])"
else
return HM.alias
+
+#undef SCANMODE_HEALTH
+#undef SCANMODE_CHEMICAL
+#undef SCANMODE_WOUND
+#undef SCANNER_CONDENSED
+#undef SCANNER_VERBOSE
\ No newline at end of file
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 5765ac71f1..cef06bfde8 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -54,8 +54,7 @@
mytape.ruin() //Fires destroy the tape
..()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/taperecorder/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/taperecorder/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(loc == user)
if(mytape)
if(!user.is_holding(src))
diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm
index 4d255fd339..eb444cdb12 100644
--- a/code/game/objects/items/devices/traitordevices.dm
+++ b/code/game/objects/items/devices/traitordevices.dm
@@ -86,98 +86,102 @@ effective or pretty fucking useless.
return
if(!used)
log_combat(user, M, "irradiated", src)
- var/cooldown = GetCooldown()
- used = 1
+ var/cooldown = get_cooldown()
+ used = TRUE
icon_state = "health1"
- handle_cooldown(cooldown) // splits off to handle the cooldown while handling wavelength
+ addtimer(VARSET_CALLBACK(src, used, FALSE), cooldown)
+ addtimer(VARSET_CALLBACK(src, icon_state, "health"), cooldown)
to_chat(user, "Successfully irradiated [M].")
- spawn((wavelength+(intensity*4))*5)
- if(M)
- if(intensity >= 5)
- M.apply_effect(round(intensity/0.075), EFFECT_UNCONSCIOUS)
- M.rad_act(intensity*10)
+ addtimer(CALLBACK(src, .proc/radiation_aftereffect, M), (wavelength+(intensity*4))*5)
else
to_chat(user, "The radioactive microlaser is still recharging.")
-/obj/item/healthanalyzer/rad_laser/proc/handle_cooldown(cooldown)
- spawn(cooldown)
- used = 0
- icon_state = "health"
+/obj/item/healthanalyzer/rad_laser/proc/radiation_aftereffect(mob/living/M)
+ if(QDELETED(M))
+ return
+ if(intensity >= 5)
+ M.apply_effect(round(intensity/0.075), EFFECT_UNCONSCIOUS)
+ M.rad_act(intensity*10)
+
+/obj/item/healthanalyzer/rad_laser/proc/get_cooldown()
+ return round(max(10, (stealth*30 + intensity*5 - wavelength/4)))
/obj/item/healthanalyzer/rad_laser/attack_self(mob/user)
interact(user)
-/obj/item/healthanalyzer/rad_laser/proc/GetCooldown()
- return round(max(10, (stealth*30 + intensity*5 - wavelength/4)))
-
/obj/item/healthanalyzer/rad_laser/interact(mob/user)
ui_interact(user)
-/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user)
-/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/healthanalyzer/rad_laser/ui_state(mob/user)
+ return GLOB.hands_state
+
+/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "RadioactiveMicrolaser", "Radioactive Microlaser", ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "RadioactiveMicrolaser")
ui.open()
- var/dat = "Irradiation: [irradiate ? "On" : "Off"] "
- dat += "Stealth Mode (NOTE: Deactivates automatically while Irradiation is off): [stealth ? "On" : "Off"] "
- dat += "Scan Mode: "
- if(!scanmode)
- dat += "Scan Health"
- else if(scanmode == 1)
- dat += "Scan Reagents"
- else
- dat += "Disabled"
- dat += "
"
+/obj/item/healthanalyzer/rad_laser/ui_data(mob/user)
+ var/list/data = list()
+ data["irradiate"] = irradiate
+ data["stealth"] = stealth
+ data["scanmode"] = scanmode
+ data["intensity"] = intensity
+ data["wavelength"] = wavelength
+ data["on_cooldown"] = used
+ data["cooldown"] = DisplayTimeText(get_cooldown())
+ return data
- dat += {"
- Radiation Intensity:
- --
- [intensity]
- ++
+/obj/item/healthanalyzer/rad_laser/ui_act(action, params)
+ if(..())
+ return
- Radiation Wavelength:
- --
- [(wavelength+(intensity*4))]
- ++
- Laser Cooldown: [DisplayTimeText(GetCooldown())]
- "}
-
- var/datum/browser/popup = new(user, "radlaser", "Radioactive Microlaser Interface", 400, 240)
- popup.set_content(dat)
- popup.open()
-
-/obj/item/healthanalyzer/rad_laser/Topic(href, href_list)
- if(!usr.canUseTopic(src))
- return 1
-
- usr.set_machine(src)
- if(href_list["rad"])
- irradiate = !irradiate
-
- else if(href_list["stealthy"])
- stealth = !stealth
-
- else if(href_list["mode"])
- scanmode += 1
- if(scanmode > 2)
- scanmode = 0
-
- else if(href_list["radint"])
- var/amount = text2num(href_list["radint"])
- amount += intensity
- intensity = max(1,(min(20,amount)))
-
- else if(href_list["radwav"])
- var/amount = text2num(href_list["radwav"])
- amount += wavelength
- wavelength = max(0,(min(120,amount)))
-
- attack_self(usr)
- add_fingerprint(usr)
- return
+ switch(action)
+ if("irradiate")
+ irradiate = !irradiate
+ . = TRUE
+ if("stealth")
+ stealth = !stealth
+ . = TRUE
+ if("scanmode")
+ scanmode = !scanmode
+ . = TRUE
+ if("radintensity")
+ var/target = params["target"]
+ var/adjust = text2num(params["adjust"])
+ if(target == "min")
+ target = 1
+ . = TRUE
+ else if(target == "max")
+ target = 20
+ . = TRUE
+ else if(adjust)
+ target = intensity + adjust
+ . = TRUE
+ else if(text2num(target) != null)
+ target = text2num(target)
+ . = TRUE
+ if(.)
+ target = round(target)
+ intensity = clamp(target, 1, 20)
+ if("radwavelength")
+ var/target = params["target"]
+ var/adjust = text2num(params["adjust"])
+ if(target == "min")
+ target = 0
+ . = TRUE
+ else if(target == "max")
+ target = 120
+ . = TRUE
+ else if(adjust)
+ target = wavelength + adjust
+ . = TRUE
+ else if(text2num(target) != null)
+ target = text2num(target)
+ . = TRUE
+ if(.)
+ target = round(target)
+ wavelength = clamp(target, 0, 120)
/obj/item/shadowcloak
name = "cloaker belt"
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index ccf9dcd253..32d9c02a27 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -79,7 +79,7 @@
if(attached_device)
attached_device.Crossed(AM)
-/obj/item/transfer_valve/attack_hand()//Triggers mousetraps
+/obj/item/transfer_valve/on_attack_hand()//Triggers mousetraps
. = ..()
if(.)
return
@@ -188,11 +188,10 @@
tank_one.air_contents.merge(temp)
tank_two.air_contents.set_volume(tank_two.air_contents.return_volume() - tank_one.air_contents.return_volume())
- /*
+/*
Exadv1: I know this isn't how it's going to work, but this was just to check
it explodes properly when it gets a signal (and it does).
- */
-
+*/
/obj/item/transfer_valve/proc/toggle_valve()
if(!valve_open && tank_one && tank_two)
valve_open = TRUE
@@ -233,16 +232,20 @@
valve_open = FALSE
update_icon()
-// this doesn't do anything but the timer etc. expects it to be here
-// eventually maybe have it update icon to show state (timer, prox etc.) like old bombs
+/*
+ This doesn't do anything but the timer etc. expects it to be here
+ eventually maybe have it update icon to show state (timer, prox etc.) like old bombs
+*/
/obj/item/transfer_valve/proc/c_state()
return
-/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/transfer_valve/ui_state(mob/user)
+ return GLOB.hands_state
+
+/obj/item/transfer_valve/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "TransferValve", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "TransferValve", name)
ui.open()
/obj/item/transfer_valve/ui_data(mob/user)
diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm
index 8c7049c713..9db9449fcb 100644
--- a/code/game/objects/items/dualsaber.dm
+++ b/code/game/objects/items/dualsaber.dm
@@ -23,6 +23,8 @@
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
resistance_flags = FIRE_PROOF
+ wound_bonus = -110
+ bare_wound_bonus = 20
block_parry_data = /datum/block_parry_data/dual_esword
var/hacked = FALSE
/// Can this reflect all energy projectiles?
@@ -103,7 +105,7 @@
to_chat(user, "You lack the grace to wield this!")
return COMPONENT_TWOHANDED_BLOCK_WIELD
wielded = TRUE
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
w_class = w_class_on
total_mass = total_mass_on
hitsound = 'sound/weapons/blade1.ogg'
diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm
index 837f57ceb5..0d5c9a22aa 100644
--- a/code/game/objects/items/eightball.dm
+++ b/code/game/objects/items/eightball.dm
@@ -192,11 +192,13 @@
return top_vote
-/obj/item/toy/eightball/haunted/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state = GLOB.always_state)
+/obj/item/toy/eightball/haunted/ui_state(mob/user)
+ return GLOB.observer_state
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/toy/eightball/haunted/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "EightBallVote", name, 400, 600, master_ui, state)
+ ui = new(user, src, "EightBallVote", name)
ui.open()
/obj/item/toy/eightball/haunted/ui_data(mob/user)
@@ -229,4 +231,4 @@
else
votes[selected_answer] += 1
voted[user.ckey] = selected_answer
- . = TRUE
\ No newline at end of file
+ . = TRUE
diff --git a/code/game/objects/items/electrostaff.dm b/code/game/objects/items/electrostaff.dm
index 8d1fe4ebd1..9750994c87 100644
--- a/code/game/objects/items/electrostaff.dm
+++ b/code/game/objects/items/electrostaff.dm
@@ -15,6 +15,7 @@
attack_verb = list("struck", "beaten", "thwacked", "pulped")
total_mass = 5 //yeah this is a heavy thing, beating people with it while it's off is not going to do you any favors. (to curb stun-kill rampaging without it being on)
block_parry_data = /datum/block_parry_data/electrostaff
+ attack_speed = CLICK_CD_MELEE
var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high
var/on = FALSE
var/can_block_projectiles = FALSE //can't block guns
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index 2d9d0b61c2..b1f51f608d 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -110,7 +110,7 @@
. += "The safety is [safety ? "on" : "off"]."
if(reagents.total_volume)
- . += "You can loose its screws to empty it."
+ . += "Alt-click to empty it."
/obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user)
if(istype(target, tanktype) && target.Adjacent(user))
@@ -230,7 +230,7 @@
repetition++
addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection, repetition), timer_seconds)
-/obj/item/extinguisher/screwdriver_act(mob/user, obj/item/tool)
+/obj/item/extinguisher/AltClick(mob/user)
if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
EmptyExtinguisher(user)
@@ -244,7 +244,7 @@
var/turf/open/theturf = T
theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
- user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by loosing the release valve's screws.")
+ user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by using its release valve.")
//firebot assembly
/obj/item/extinguisher/attackby(obj/O, mob/user, params)
diff --git a/code/game/objects/items/fireaxe.dm b/code/game/objects/items/fireaxe.dm
index 41c1cbe915..6fb7b89262 100644
--- a/code/game/objects/items/fireaxe.dm
+++ b/code/game/objects/items/fireaxe.dm
@@ -13,10 +13,12 @@
slot_flags = ITEM_SLOT_BACK
attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
resistance_flags = FIRE_PROOF
+ wound_bonus = -15
+ bare_wound_bonus = 20
var/wielded = FALSE // track wielded status on item
/obj/item/fireaxe/Initialize()
diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm
index f293e6579a..515f5715dd 100644
--- a/code/game/objects/items/flamethrower.dm
+++ b/code/game/objects/items/flamethrower.dm
@@ -131,6 +131,7 @@
/obj/item/flamethrower/analyzer_act(mob/living/user, obj/item/I)
if(ptank)
ptank.analyzer_act(user, I)
+ return TRUE
/obj/item/flamethrower/attack_self(mob/user)
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index 4ad71f7c46..609cc3b719 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -79,7 +79,7 @@
ADD_TRAIT(user, granted_trait, BOOK_TRAIT)
/obj/item/book/granter/trait/rifleman
- name = "\proper the Neo-Russian Rifleman\'s Primer"
+ name = "The Neo-Russian Rifleman\'s Primer"
desc = "A book with stains of vodka and...blood? The back is hard to read, but says something about bolt-actions. Or pump-actions. Both, maybe."
oneuse = FALSE
granted_trait = TRAIT_FAST_PUMP
@@ -477,6 +477,23 @@
name = "empty scroll"
icon_state = "blankscroll"
+/obj/item/book/granter/martial/krav_maga
+ martial = /datum/martial_art/krav_maga
+ name = "parchment scroll"
+ martialname = "krav maga"
+ desc = "A worn parchment scrap written in an ancient language. Somehow you can still understand the lessons!"
+ greet = "You have learned the ancient martial art of Krav Maga. You have special attacks with which to take down your foes."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state ="scroll2"
+ remarks = list("Sweep the legs...", "Chop the throat...", "Punch the lungs...", "Get the gold...", "Where are my sick gloves..?")
+
+/obj/item/book/granter/martial/krav_maga/onlearned(mob/living/carbon/user)
+ . = ..()
+ if(oneuse == TRUE)
+ desc = "It's completely blank."
+ name = "empty scroll"
+ icon_state = "blankscroll"
+
// I did not include mushpunch's grant, it is not a book and the item does it just fine.
diff --git a/code/game/objects/items/grenades/flashbang.dm b/code/game/objects/items/grenades/flashbang.dm
index f51db9fa4c..bf9fab5f04 100644
--- a/code/game/objects/items/grenades/flashbang.dm
+++ b/code/game/objects/items/grenades/flashbang.dm
@@ -60,6 +60,14 @@
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball/mega
shrapnel_radius = 12
+/obj/item/grenade/stingbang/breaker
+ name = "breakbang"
+ shrapnel_type = /obj/item/projectile/bullet/pellet/stingball/breaker
+
+/obj/item/grenade/stingbang/shred
+ name = "shredbang"
+ shrapnel_type = /obj/item/projectile/bullet/pellet/stingball/shred
+
/obj/item/grenade/stingbang/prime(mob/living/lanced_by)
if(iscarbon(loc))
var/mob/living/carbon/C = loc
@@ -116,9 +124,11 @@
/obj/item/grenade/primer/attack_self(mob/user)
. = ..()
if(active)
+ if(!user.CheckActionCooldown())
+ return
user.playsound_local(user, 'sound/misc/box_deploy.ogg', 50, TRUE)
rots++
- user.changeNext_move(CLICK_CD_RAPID)
+ user.DelayNextAction(CLICK_CD_RAPID)
/obj/item/grenade/primer/prime(mob/living/lanced_by)
shrapnel_radius = round(rots / rots_per_mag)
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index e3388b12eb..4c9ea06620 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -320,7 +320,7 @@
do_sparks(1, TRUE, src)
qdel(src)
-/obj/item/restraints/legcuffs/beartrap/energy/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/restraints/legcuffs/beartrap/energy/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
Crossed(user) //honk
. = ..()
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index d6396f9902..58146be20f 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -225,6 +225,7 @@
throwforce = 10
w_class = WEIGHT_CLASS_TINY
obj_flags = UNIQUE_RENAME
+ wound_bonus = -10
var/chaplain_spawnable = TRUE
total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
@@ -351,7 +352,7 @@
w_class = WEIGHT_CLASS_HUGE
slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
block_chance = 30
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
@@ -451,7 +452,7 @@
w_class = WEIGHT_CLASS_BULKY
armour_penetration = 35
slot_flags = ITEM_SLOT_BACK
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("chopped", "sliced", "cut", "reaped")
/obj/item/nullrod/scythe/Initialize()
@@ -574,7 +575,7 @@
righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi'
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
total_mass = TOTAL_MASS_HAND_REPLACEMENT
@@ -593,7 +594,7 @@
name = "clown dagger"
desc = "Used for absolutely hilarious sacrifices."
hitsound = 'sound/items/bikehorn.ogg'
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
/obj/item/nullrod/pride_hammer
@@ -644,7 +645,7 @@
throw_speed = 4
throw_range = 7
throwforce = 30
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("enlightened", "redpilled")
/obj/item/nullrod/armblade
@@ -656,7 +657,9 @@
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
item_flags = ABSTRACT
w_class = WEIGHT_CLASS_HUGE
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
+ wound_bonus = -20
+ bare_wound_bonus = 25
total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/nullrod/armblade/Initialize()
@@ -696,7 +699,7 @@
force = 15
block_chance = 40
slot_flags = ITEM_SLOT_BACK
- sharpness = IS_BLUNT
+ sharpness = SHARP_NONE
hitsound = "swing_hit"
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
icon = 'icons/obj/items_and_weapons.dmi'
@@ -751,7 +754,7 @@
name = "arrhythmic knife"
w_class = WEIGHT_CLASS_HUGE
desc = "They say fear is the true mind killer, but stabbing them in the head works too. Honour compels you to not sheathe it once drawn."
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
slot_flags = null
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
@@ -779,7 +782,7 @@
desc = "Holding this makes you look absolutely devilish."
attack_verb = list("poked", "impaled", "pierced", "jabbed")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
/obj/item/nullrod/egyptian
name = "egyptian staff"
diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm
index 6cdc5ee824..897cb9b750 100644
--- a/code/game/objects/items/implants/implant_misc.dm
+++ b/code/game/objects/items/implants/implant_misc.dm
@@ -38,6 +38,23 @@
if(!uses)
qdel(src)
+/obj/item/implant/warp
+ name = "warp implant"
+ desc = "Saves your position somewhere, and then warps you back to it after five seconds."
+ icon_state = "warp"
+ uses = 15
+
+/obj/item/implant/warp/activate()
+ . = ..()
+ uses--
+ imp_in.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/fermi/eigenstate = 1.2), "You feel an internal prick as as the bluespace starts ramping up!")
+ to_chat(imp_in, "You feel an internal prick as as the bluespace starts ramping up!")
+ if(!uses)
+ qdel(src)
+
+/obj/item/implanter/warp
+ name = "implanter (warp)"
+ imp_type = /obj/item/implant/warp
/obj/item/implant/emp
name = "emp implant"
diff --git a/code/game/objects/items/implants/implant_radio.dm b/code/game/objects/items/implants/implant_radio.dm
index 5d3d579a4e..6f42547004 100644
--- a/code/game/objects/items/implants/implant_radio.dm
+++ b/code/game/objects/items/implants/implant_radio.dm
@@ -10,7 +10,7 @@
/obj/item/implant/radio/activate()
. = ..()
// needs to be GLOB.deep_inventory_state otherwise it won't open
- radio.ui_interact(usr, "main", null, FALSE, null, GLOB.deep_inventory_state)
+ radio.ui_interact(usr, state = GLOB.deep_inventory_state)
/obj/item/implant/radio/implant(mob/living/target, mob/user, silent = FALSE)
. = ..()
diff --git a/code/game/objects/items/implants/implantchair.dm b/code/game/objects/items/implants/implantchair.dm
index 3ea27c84bb..7b05cf302e 100644
--- a/code/game/objects/items/implants/implantchair.dm
+++ b/code/game/objects/items/implants/implantchair.dm
@@ -26,14 +26,15 @@
open_machine()
update_icon()
+/obj/machinery/implantchair/ui_state(mob/user)
+ return GLOB.notcontained_state
-/obj/machinery/implantchair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/implantchair/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "implantchair", name, 375, 280, master_ui, state)
+ ui = new(user, src, "ImplantChair", name)
ui.open()
-
/obj/machinery/implantchair/ui_data()
var/list/data = list()
data["occupied"] = occupant ? 1 : 0
@@ -121,8 +122,6 @@
update_icon()
/obj/machinery/implantchair/container_resist(mob/living/user)
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the door of [src]!", \
"You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
@@ -191,4 +190,4 @@
brainwash(C, objective)
message_admins("[ADMIN_LOOKUPFLW(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
log_game("[key_name(user)] brainwashed [key_name(C)] with objective '[objective]'.")
- return TRUE
\ No newline at end of file
+ return TRUE
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index 2c00265ce8..e7cf8defc9 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -18,7 +18,7 @@
name = "fork"
desc = "Pointy."
icon_state = "fork"
- force = 5
+ force = 4
w_class = WEIGHT_CLASS_TINY
throwforce = 0
throw_speed = 3
@@ -28,6 +28,7 @@
attack_verb = list("attacked", "stabbed", "poked")
hitsound = 'sound/weapons/bladeslice.ogg'
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
+ sharpness = SHARP_POINTY
var/datum/reagent/forkload //used to eat omelette
/obj/item/kitchen/fork/suicide_act(mob/living/carbon/user)
@@ -61,7 +62,7 @@
throw_speed = 4
throw_range = 6
embedding = list("pain_mult" = 2, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15)
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
/obj/item/kitchen/knife
name = "kitchen knife"
@@ -76,9 +77,11 @@
throw_range = 6
custom_materials = list(/datum/material/iron=12000)
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- sharpness = IS_SHARP_ACCURATE
+ sharpness = SHARP_POINTY
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/bayonet = FALSE //Can this be attached to a gun?
+ wound_bonus = -5
+ bare_wound_bonus = 10
custom_price = PRICE_NORMAL
/obj/item/kitchen/knife/Initialize()
diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm
index ef5b7b6cba..b2f8b4bee2 100644
--- a/code/game/objects/items/latexballoon.dm
+++ b/code/game/objects/items/latexballoon.dm
@@ -54,5 +54,5 @@
var/obj/item/tank/T = W
blow(T, user)
return
- if (W.get_sharpness() || W.get_temperature() || is_pointed(W))
+ if (W.get_sharpness() || W.get_temperature())
burst()
diff --git a/code/game/objects/items/manuals.dm b/code/game/objects/items/manuals.dm
index 6c01e68a48..0673e1d489 100644
--- a/code/game/objects/items/manuals.dm
+++ b/code/game/objects/items/manuals.dm
@@ -506,7 +506,9 @@
if(prob(50))
step(W, pick(GLOB.alldirs))
ADD_TRAIT(H, TRAIT_DISFIGURED, TRAIT_GENERIC)
- H.bleed_rate = 5
+ for(var/i in H.bodyparts)
+ var/obj/item/bodypart/BP = i
+ BP.generic_bleedstacks += 5
H.gib_animation()
sleep(3)
H.adjustBruteLoss(1000) //to make the body super-bloody
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index 20960da7c6..679491aeb6 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -102,7 +102,7 @@
attack_verb_off = list("tapped", "poked")
throw_speed = 3
throw_range = 5
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
embedding = list("embed_chance" = 75, "impact_pain_mult" = 10)
armour_penetration = 35
item_flags = NEEDS_PERMIT | ITEM_CAN_PARRY
@@ -147,6 +147,12 @@
return NONE
return ..()
+/obj/item/melee/transforming/energy/sword/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
+ . = ..()
+ if(parry_efficiency >= 80) // perfect parry
+ block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_RETURN_TO_SENDER
+ . |= BLOCK_SHOULD_REDIRECT
+
/obj/item/melee/transforming/energy/sword/cyborg
sword_color = "red"
light_color = "#ff0000"
@@ -174,7 +180,7 @@
sword_color = null //stops icon from breaking when turned on.
hitcost = 75 //Costs more than a standard cyborg esword
w_class = WEIGHT_CLASS_NORMAL
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
light_color = "#40ceff"
tool_behaviour = TOOL_SAW
toolspeed = 0.7
@@ -249,7 +255,7 @@
throw_range = 1
w_class = WEIGHT_CLASS_BULKY//So you can't hide it in your pocket or some such.
var/datum/effect_system/spark_spread/spark_system
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
//Most of the other special functions are handled in their own files. aka special snowflake code so kewl
/obj/item/melee/transforming/energy/blade/Initialize()
@@ -285,7 +291,7 @@
attack_verb_off = list("tapped", "poked")
throw_speed = 3
throw_range = 5
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
embedding = list("embedded_pain_multiplier" = 6, "embed_chance" = 20, "embedded_fall_chance" = 60)
armour_penetration = 10
block_chance = 35
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index b2e463e89e..01d2924a90 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -19,6 +19,8 @@
slot_flags = ITEM_SLOT_BELT
force = 14
throwforce = 10
+ wound_bonus = 15
+ bare_wound_bonus = 10
reach = 2
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("flogged", "whipped", "lashed", "disciplined")
@@ -42,7 +44,7 @@
throwforce = 10
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "impaled", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/melee/synthetic_arm_blade/Initialize()
@@ -62,7 +64,7 @@
throwforce = 15
w_class = WEIGHT_CLASS_BULKY
armour_penetration = 75
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("slashed", "cut")
hitsound = 'sound/weapons/rapierhit.ogg'
custom_materials = list(/datum/material/iron = 1000)
@@ -166,7 +168,7 @@
flags_1 = CONDUCT_1
obj_flags = UNIQUE_RENAME
w_class = WEIGHT_CLASS_BULKY
- sharpness = IS_SHARP_ACCURATE //It cant be sharpend cook -_-
+ sharpness = SHARP_POINTY //It cant be sharpend cook -_-
attack_verb = list("stabs", "punctures", "pierces", "pokes")
hitsound = 'sound/weapons/rapierhit.ogg'
total_mass = 0.4
@@ -268,6 +270,8 @@
var/force_off // Damage when off - not stunning
var/weight_class_on // What is the new size class when turned on
+ wound_bonus = 15
+
/obj/item/melee/classic_baton/Initialize()
. = ..()
@@ -371,6 +375,7 @@
var/wait_desc = get_wait_description()
if(wait_desc)
to_chat(user, wait_desc)
+ return DISCARD_LAST_ACTION
/obj/item/melee/classic_baton/telescopic
name = "telescopic baton"
@@ -393,6 +398,7 @@
force_off = 0
weight_class_on = WEIGHT_CLASS_BULKY
total_mass = TOTAL_MASS_NORMAL_ITEM
+ bare_wound_bonus = 5
/obj/item/melee/classic_baton/telescopic/suicide_act(mob/user)
var/mob/living/carbon/human/H = user
@@ -621,7 +627,7 @@
to_chat(user, "[target] doesn't seem to want to get on [src]!")
update_icon()
-/obj/item/melee/roastingstick/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/melee/roastingstick/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
..()
if (held_sausage)
user.put_in_hands(held_sausage)
diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm
index 386a6e9acc..8c44a15cd4 100644
--- a/code/game/objects/items/melee/transforming.dm
+++ b/code/game/objects/items/melee/transforming.dm
@@ -1,5 +1,5 @@
/obj/item/melee/transforming
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
var/active = FALSE
var/force_on = 30 //force when active
var/faction_bonus_force = 0 //Bonus force dealt against certain factions
@@ -84,4 +84,4 @@
/obj/item/melee/transforming/proc/clumsy_transform_effect(mob/living/user)
if(clumsy_check && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
to_chat(user, "You accidentally cut yourself with [src], like a doofus!")
- user.take_bodypart_damage(5,5)
\ No newline at end of file
+ user.take_bodypart_damage(5,5)
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 3a06c7d7fe..b420bfc002 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -58,7 +58,7 @@
if(T)
user.visible_message("[user] cleans \the [T] with [src].", "You clean \the [T] with [src].")
clean(T)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
user.do_attack_animation(T, used_item = src)
if(istype(L))
L.adjustStaminaLossBuffered(stamusage)
@@ -128,4 +128,4 @@
return ..()
/obj/item/mop/advanced/cyborg
- insertable = FALSE
\ No newline at end of file
+ insertable = FALSE
diff --git a/code/game/objects/items/pet_carrier.dm b/code/game/objects/items/pet_carrier.dm
index a60aa02ce1..c6b5a7e224 100644
--- a/code/game/objects/items/pet_carrier.dm
+++ b/code/game/objects/items/pet_carrier.dm
@@ -24,6 +24,7 @@
var/max_occupant_weight = MOB_SIZE_SMALL //This is calculated from the mob sizes of occupants
var/entrance_name = "door" //name of the entrance to the item
var/escape_time = 200 //how long it takes for mobs above small sizes to escape (for small sizes, its randomly 1.5 to 2x this)
+ var/alternate_escape_time = 0 //how long it takes for mobs to escape when the entrance is open
var/load_time = 30 //how long it takes for mobs to be loaded into the pet carrier
var/has_lock_sprites = TRUE //whether to load the lock overlays or not
var/allows_hostiles = FALSE //does the pet carrier allow hostile entities to be held within it?
@@ -106,8 +107,9 @@
if(user == target)
to_chat(user, "Why would you ever do that?")
return
- if(ishostile(target) && (!allows_hostiles || istype(target, /mob/living/simple_animal/hostile/carp/cayenne)) || target.move_resist < MOVE_FORCE_VERY_STRONG) //don't allow goliaths into pet carriers, but let cayenne in!
+ if((ishostile(target) && (!allows_hostiles || !istype(target, /mob/living/simple_animal/hostile/carp/cayenne))) || target.move_resist >= MOVE_FORCE_VERY_STRONG) //don't allow goliaths into pet carriers, but let cayenne in!
to_chat(user, "You have a feeling you shouldn't keep this as a pet.")
+ return
load_occupant(user, target)
/obj/item/pet_carrier/relaymove(mob/living/user, direction)
@@ -128,13 +130,18 @@
/obj/item/pet_carrier/container_resist(mob/living/user)
//don't do the whole resist timer thing if it's open!
if(open)
- loc.visible_message("[user] climbs out of [src]!", \
- "[user] jumps out of [src]!")
- remove_occupant(user)
- return
+ if(alternate_escape_time > 0)
+ loc.visible_message("The [src] begins to shake!")
+ if(do_after(user, alternate_escape_time, target = user))
+ loc.visible_message("[user] jumps out of [src]")
+ remove_occupant(user)
+ return
+ else //instant escape, different message
+ loc.visible_message("[user] climbs out of [src]!", \
+ "[user] jumps out of [src]!")
+ remove_occupant(user)
+ return
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
if(user.mob_size <= MOB_SIZE_SMALL)
to_chat(user, "You begin to try escaping the [src] and start fumbling for the lock switch... (This will take some time.)")
to_chat(loc, "You see [user] attempting to unlock the [src]!")
@@ -147,7 +154,7 @@
update_icon()
else
loc.visible_message("[src] starts rattling as something pushes against the [entrance_name]!", null, null, null, user)
- to_chat(user, "You start pushing out of [src]... (This will take about 20 seconds.)")
+ to_chat(user, "You start pushing out of [src]... (This will take about [escape_time/10] seconds.)")
if(!do_after(user, escape_time, target = user) || open || !locked || !(user in occupants))
return
loc.visible_message("[user] shoves out of [src]!", null, null, null, user)
@@ -180,21 +187,22 @@
/obj/item/pet_carrier/proc/load_occupant(mob/living/user, mob/living/target)
if(pet_carrier_full(src))
to_chat(user, "[src] is already carrying too much!")
- return
+ return FALSE
user.visible_message("[user] starts loading [target] into [src].", \
"You start loading [target] into [src]...", null, null, target)
to_chat(target, "[user] starts loading you into [user.p_their()] [name]!")
if(!do_mob(user, target, load_time))
- return
+ return FALSE
if(target in occupants)
- return
+ return FALSE
if(pet_carrier_full(src)) //Run the checks again, just in case
to_chat(user, "[src] is already carrying too much!")
- return
+ return FALSE
user.visible_message("[user] loads [target] into [src]!", \
"You load [target] into [src].", null, null, target)
to_chat(target, "[user] loads you into [user.p_their()] [name]!")
add_occupant(target)
+ return TRUE
/obj/item/pet_carrier/proc/add_occupant(mob/living/occupant)
if(occupant in occupants || !istype(occupant))
@@ -230,7 +238,8 @@
allows_hostiles = TRUE //can fit hostile creatures, with the move resist restrictions in place, this means they still cannot take things like legions/goliaths/etc regardless
has_lock_sprites = FALSE //jar doesn't show the regular lock overlay
custom_materials = list(/datum/material/glass = 1000, /datum/material/bluespace = 600)
- escape_time = 10 //half the time of a bluespace bodybag
+ escape_time = 200 //equal to the time of a bluespace bodybag
+ alternate_escape_time = 100
var/datum/gas_mixture/occupant_gas_supply
/obj/item/pet_carrier/bluespace/update_icon_state()
@@ -271,10 +280,15 @@
REMOVE_TRAIT(occupant, TRAIT_NOBREATH, "bluespace_container_no_breath")
REMOVE_TRAIT(occupant, TRAIT_RESISTHIGHPRESSURE, "bluespace_container_resist_high_pressure")
REMOVE_TRAIT(occupant, TRAIT_RESISTLOWPRESSURE, "bluespace_container_resist_low_pressure")
+ name = initial(name)
/obj/item/pet_carrier/bluespace/return_air()
if(!occupant_gas_supply)
occupant_gas_supply = new
return occupant_gas_supply
+/obj/item/pet_carrier/bluespace/load_occupant(mob/living/user, mob/living/target)
+ if(..())
+ name = "[initial(name)] ([target])"
+
#undef pet_carrier_full
diff --git a/code/game/objects/items/pitchfork.dm b/code/game/objects/items/pitchfork.dm
index 49d0b64498..b296e2d0cb 100644
--- a/code/game/objects/items/pitchfork.dm
+++ b/code/game/objects/items/pitchfork.dm
@@ -9,7 +9,7 @@
w_class = WEIGHT_CLASS_BULKY
attack_verb = list("attacked", "impaled", "pierced")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
resistance_flags = FIRE_PROOF
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index 00a9ff22f4..44205f4884 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -8,6 +8,7 @@
resistance_flags = FLAMMABLE
var/list/squeak_override //Weighted list; If you want your plush to have different squeak sounds use this
var/stuffed = TRUE //If the plushie has stuffing in it
+ var/unstuffable = FALSE //for plushies that can't be stuffed
var/obj/item/grenade/grenade //You can remove the stuffing from a plushie and add a grenade to it for *nefarious uses*
//--love ~<3--
gender = NEUTER
@@ -174,6 +175,9 @@
/obj/item/toy/plush/attackby(obj/item/I, mob/living/user, params)
if(I.get_sharpness())
if(!grenade)
+ if(unstuffable)
+ to_chat(user, "Nothing to do here.")
+ return
if(!stuffed)
to_chat(user, "You already murdered it!")
return
@@ -187,6 +191,13 @@
grenade = null
return
if(istype(I, /obj/item/grenade))
+ if(unstuffable)
+ to_chat(user, "No... you should destroy it now!")
+ sleep(10)
+ if(QDELETED(user) || QDELETED(src))
+ return
+ SEND_SOUND(user, 'sound/weapons/armbomb.ogg')
+ return
if(stuffed)
to_chat(user, "You need to remove some stuffing first!")
return
@@ -743,3 +754,14 @@ GLOBAL_LIST_INIT(valid_plushie_paths, valid_plushie_paths())
attack_verb = list("headbutt", "scritched", "bit")
squeak_override = list('modular_citadel/sound/voice/nya.ogg' = 1)
can_random_spawn = FALSE
+
+
+/obj/item/toy/plush/hairball
+ name = "Hairball"
+ desc = "A bundle of undigested fibers and scales. Yuck."
+ icon_state = "Hairball"
+ unstuffable = TRUE
+ young = TRUE // Your own mouth-baby.
+ squeak_override = list('sound/misc/splort.ogg'=1)
+ attack_verb = list("sploshed", "splorted", "slushed")
+ can_random_spawn = FALSE
diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm
index b7e2d22d2f..2834b3b758 100644
--- a/code/game/objects/items/powerfist.dm
+++ b/code/game/objects/items/powerfist.dm
@@ -14,12 +14,11 @@
w_class = WEIGHT_CLASS_NORMAL
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 40)
resistance_flags = FIRE_PROOF
- click_delay = CLICK_CD_MELEE * 1.5
+ attack_speed = CLICK_CD_MELEE * 1.5
var/fisto_setting = 1
var/gasperfist = 3
var/obj/item/tank/internals/tank = null //Tank used for the gauntlet's piston-ram.
-
/obj/item/melee/powerfist/examine(mob/user)
. = ..()
if(!in_range(user, src))
@@ -98,7 +97,7 @@
target.visible_message("[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
"[user]'s punch strikes with force!")
return
- target.apply_damage(totalitemdamage * fisto_setting, BRUTE)
+ target.apply_damage(totalitemdamage * fisto_setting, BRUTE, wound_bonus = -25*fisto_setting**2)
target.visible_message("[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
"You cry out in pain as [user]'s punch flings you backwards!")
new /obj/effect/temp_visual/kinetic_blast(target.loc)
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index 4b2e022da7..6513b53e1d 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -747,7 +747,7 @@
/obj/item/weapon/gripper
name = "engineering gripper"
- desc = "A simple grasping tool for interacting with various engineering related items, such as circuits, gas tanks and conveyer belts. Alt click to drop instead of use."
+ desc = "A simple grasping tool for interacting with various engineering related items, such as circuits, gas tanks, conveyer belts and more. Alt click to drop instead of use."
icon = 'icons/obj/device.dmi'
icon_state = "gripper"
@@ -784,7 +784,7 @@
wrapped = null
return ..()
-/obj/item/weapon/gripper/afterattack(var/atom/target, var/mob/living/silicon/robot/user, proximity, params)
+/obj/item/weapon/gripper/pre_attack(var/atom/target, var/mob/living/silicon/robot/user, proximity, params)
if(!proximity)
return
@@ -839,6 +839,19 @@
/obj/item/survivalcapsule
)
+/obj/item/weapon/gripper/medical
+ name = "medical gripper"
+ desc = "A simple grasping tool for interacting with medical equipment, such as beakers, blood bags, chem bags and more. Alt click to drop instead of use."
+ icon_state = "gripper_medical"
+ can_hold = list(
+ /obj/item/storage/bag/bio,
+ /obj/item/storage/bag/chemistry,
+ /obj/item/storage/pill_bottle,
+ /obj/item/reagent_containers/glass,
+ /obj/item/reagent_containers/pill,
+ /obj/item/reagent_containers/blood
+ )
+
/obj/item/gun/energy/plasmacutter/cyborg
name = "cyborg plasma cutter"
desc = "A basic variation of the plasma cutter, compressed into a cyborg chassis. Less effective than normal plasma cutters."
@@ -921,6 +934,9 @@
icon_state = "data_1"
+/**********************************************************************
+ Dogborg stuff
+***********************************************************************/
///Mere cosmetic dogborg items, remnants of what were once the most annoying cyborg modules.
/obj/item/dogborg_tongue
name = "synthetic tongue"
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 9fbedb33cd..80fd177d84 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -6,21 +6,24 @@
desc = "Protected by FRM."
icon = 'icons/obj/module.dmi'
icon_state = "cyborg_upgrade"
+ w_class = WEIGHT_CLASS_SMALL
var/locked = FALSE
var/installed = 0
var/require_module = 0
var/list/module_type
+ /// Bitflags listing module compatibility. Used in the exosuit fabricator for creating sub-categories.
+ var/module_flags = NONE
// if true, is not stored in the robot to be ejected
// if module is reset
var/one_use = FALSE
/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R, user = usr)
if(R.stat == DEAD)
- to_chat(user, "[src] will not function on a deceased cyborg.")
+ to_chat(user, "[src] will not function on a deceased cyborg.")
return FALSE
if(module_type && !is_type_in_list(R.module, module_type))
- to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
- to_chat(user, "There's no mounting point for the module!")
+ to_chat(R, "Upgrade mounting error! No suitable hardpoint detected.")
+ to_chat(user, "There's no mounting point for the module!")
return FALSE
return TRUE
@@ -37,7 +40,7 @@
one_use = TRUE
/obj/item/borg/upgrade/rename/attack_self(mob/user)
- heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
+ heldname = sanitize_name(stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN))
/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
. = ..()
@@ -95,6 +98,7 @@
desc = "Used to cool a mounted energy-based firearm, increasing the potential current in it and thus its recharge rate."
icon_state = "cyborg_upgrade3"
require_module = 1
+ module_flags = BORG_MODULE_SECURITY
/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -147,6 +151,7 @@
icon_state = "cyborg_upgrade3"
require_module = 1
module_type = list(/obj/item/robot_module/miner)
+ module_flags = BORG_MODULE_MINER
/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -207,6 +212,7 @@
icon_state = "cyborg_upgrade3"
require_module = 1
module_type = list(/obj/item/robot_module/butler)
+ module_flags = BORG_MODULE_JANITOR
/obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R)
. = ..()
@@ -234,6 +240,7 @@
icon_state = "cyborg_upgrade3"
require_module = 1
module_type = list(/obj/item/robot_module/butler)
+ module_flags = BORG_MODULE_JANITOR
/obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R)
. = ..()
@@ -241,9 +248,9 @@
for(var/obj/item/mop/cyborg/M in R.module.modules)
R.module.remove_module(M, TRUE)
- var/obj/item/mop/advanced/cyborg/A = new /obj/item/mop/advanced/cyborg(R.module)
- R.module.basic_modules += A
- R.module.add_module(A, FALSE, TRUE)
+ var/obj/item/mop/advanced/cyborg/A = new /obj/item/mop/advanced/cyborg(R.module)
+ R.module.basic_modules += A
+ R.module.add_module(A, FALSE, TRUE)
/obj/item/borg/upgrade/amop/deactivate(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -283,6 +290,7 @@
resistance_flags = LAVA_PROOF | FIRE_PROOF
require_module = 1
module_type = list(/obj/item/robot_module/miner)
+ module_flags = BORG_MODULE_MINER
/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -402,6 +410,7 @@
module_type = list(/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical)
var/list/additional_reagents = list()
+ module_flags = BORG_MODULE_MEDICAL
/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -471,6 +480,7 @@
require_module = 1
module_type = list(/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical)
+ module_flags = BORG_MODULE_MEDICAL
/obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -578,6 +588,7 @@
icon_state = "borg_BS_RPED"
require_module = TRUE
module_type = list(/obj/item/robot_module/engineering, /obj/item/robot_module/saboteur)
+ module_flags = BORG_MODULE_ENGINEERING
/obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -612,8 +623,8 @@
icon = 'icons/obj/device.dmi'
icon_state = "pinpointer_crew"
require_module = TRUE
- module_type = list(/obj/item/robot_module/medical,
- /obj/item/robot_module/syndicate_medical)
+ module_type = list(/obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical)
+ module_flags = BORG_MODULE_MEDICAL
/obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr)
. = ..()
diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm
index 6bf0b27fb4..fc19e61cd6 100644
--- a/code/game/objects/items/sharpener.dm
+++ b/code/game/objects/items/sharpener.dm
@@ -39,7 +39,7 @@
I.force = clamp(I.force + increment, 0, max)
user.visible_message("[user] sharpens [I] with [src]!", "You sharpen [I], making it much more deadly than before.")
- I.sharpness = IS_SHARP_ACCURATE
+ I.sharpness = SHARP_POINTY
I.throwforce = clamp(I.throwforce + increment, 0, max)
I.name = "[prefix] [I.name]"
name = "worn out [name]"
diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm
index 992c173d3b..4952c93928 100644
--- a/code/game/objects/items/shields.dm
+++ b/code/game/objects/items/shields.dm
@@ -106,8 +106,8 @@
var/disarming = (target_downed && (shield_flags & SHIELD_BASH_GROUND_SLAM_DISARM)) || (shield_flags & SHIELD_BASH_ALWAYS_DISARM) || (wallhit && (shield_flags & SHIELD_BASH_WALL_DISARM))
var/knockdown = !target_downed && ((shield_flags & SHIELD_BASH_ALWAYS_KNOCKDOWN) || (wallhit && (shield_flags & SHIELD_BASH_WALL_KNOCKDOWN)))
if(shieldbash_stagger_duration || knockdown)
- target.visible_message("[target] is knocked [knockdown? "to the floor" : "off balanace"]!",
- "You are knocked [knockdown? "to the floor" : "off balanace"]!")
+ target.visible_message("[target] is knocked [knockdown? "to the floor" : "off balance"]!",
+ "You are knocked [knockdown? "to the floor" : "off balance"]!")
if(knockdown)
target.KnockToFloor(disarming)
else if(disarming)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 7fd37053b1..ced0ee3160 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -31,10 +31,7 @@
to_chat(user, "You slice off [src]'s uneven chunks of aluminium and scorch marks.")
return TRUE
-/obj/item/target/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/item/target/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(pinnedLoc)
pinnedLoc.removeTarget(user)
diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm
index 7108080ecc..5904cb6c0b 100644
--- a/code/game/objects/items/shrapnel.dm
+++ b/code/game/objects/items/shrapnel.dm
@@ -7,11 +7,13 @@
icon_state = "large"
w_class = WEIGHT_CLASS_TINY
item_flags = DROPDEL
+ sharpness = SHARP_EDGED
/obj/item/shrapnel/stingball // stingbang grenades
name = "stingball"
embedding = list(embed_chance=90, fall_chance=3, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.7, pain_mult=5, jostle_pain_mult=6, rip_time=15, embed_chance_turf_mod=-100)
icon_state = "tiny"
+ sharpness = SHARP_NONE
/obj/item/shrapnel/bullet // bullets
name = "bullet"
@@ -28,21 +30,24 @@
/obj/item/projectile/bullet/shrapnel
name = "flying shrapnel shard"
- damage = 9
- range = 10
+ damage = 14
+ range = 20
armour_penetration = -30
dismemberment = 5
ricochets_max = 2
- ricochet_chance = 40
+ ricochet_chance = 70
shrapnel_type = /obj/item/shrapnel
ricochet_incidence_leeway = 60
+ sharpness = SHARP_EDGED
+ wound_bonus = 40
/obj/item/projectile/bullet/shrapnel/mega
name = "flying shrapnel hunk"
- range = 25
- dismemberment = 10
- ricochets_max = 4
- ricochet_chance = 90
+ range = 45
+ dismemberment = 15
+ ricochets_max = 6
+ ricochet_chance = 130
+ ricochet_incidence_leeway = 0
ricochet_decay_chance = 0.9
/obj/item/projectile/bullet/pellet/stingball
@@ -62,3 +67,15 @@
name = "megastingball pellet"
ricochets_max = 6
ricochet_chance = 110
+
+/obj/item/projectile/bullet/pellet/stingball/breaker
+ name = "breakbang pellet"
+ damage = 10
+ wound_bonus = 40
+ sharpness = SHARP_NONE
+
+/obj/item/projectile/bullet/pellet/stingball/shred
+ name = "shredbang pellet"
+ damage = 10
+ wound_bonus = 30
+ sharpness = SHARP_EDGED
diff --git a/code/game/objects/items/signs.dm b/code/game/objects/items/signs.dm
index cf7373b700..67bc28b2ea 100644
--- a/code/game/objects/items/signs.dm
+++ b/code/game/objects/items/signs.dm
@@ -40,4 +40,3 @@
user.visible_message("[user] waves around \the \"[label]\" sign.")
else
user.visible_message("[user] waves around blank sign.")
- user.changeNext_move(CLICK_CD_MELEE)
\ No newline at end of file
diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm
index 376362d7c3..f40c774551 100644
--- a/code/game/objects/items/spear.dm
+++ b/code/game/objects/items/spear.dm
@@ -15,13 +15,15 @@
custom_materials = list(/datum/material/iron=1150, /datum/material/glass=2075)
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "poked", "jabbed", "torn", "gored")
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
var/obj/item/grenade/explosive = null
var/war_cry = "AAAAARGH!!!"
var/icon_prefix = "spearglass"
var/wielded = FALSE // track wielded status on item
+ wound_bonus = -15
+ bare_wound_bonus = 15
/obj/item/spear/Initialize()
. = ..()
@@ -177,7 +179,7 @@
custom_materials = null
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "poked", "jabbed", "torn", "gored")
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
icon_prefix = "bone_spear"
/obj/item/spear/bonespear/ComponentInitialize()
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index c142db6530..3b4be37cee 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -74,8 +74,7 @@
/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
to_chat(user, "You cannot crush the polycrystal in-hand, try breaking one off.")
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/stack/sheet/bluespace_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/stack/sheet/bluespace_crystal/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.get_inactive_held_item() == src)
if(zero_amount())
return
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index e4b67d4da5..11df83230c 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -15,11 +15,20 @@
var/self_delay = 50
var/other_delay = 0
var/repeating = FALSE
+ /// How much brute we heal per application
+ var/heal_brute
+ /// How much burn we heal per application
+ var/heal_burn
+ /// How much we reduce bleeding per application on cut wounds
+ var/stop_bleeding
+ /// How much sanitization to apply to burns on application
+ var/sanitization
+ /// How much we add to flesh_healing for burn wounds on application
+ var/flesh_regeneration
/obj/item/stack/medical/attack(mob/living/M, mob/user)
. = ..()
- try_heal(M, user)
-
+ INVOKE_ASYNC(src, .proc/try_heal, M, user)
/obj/item/stack/medical/proc/try_heal(mob/living/M, mob/user, silent = FALSE)
if(!M.can_inject(user, TRUE))
@@ -70,8 +79,9 @@
icon_state = "brutepack"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- var/heal_brute = 20
- self_delay = 20
+ heal_brute = 40
+ self_delay = 40
+ other_delay = 20
grind_results = list(/datum/reagent/medicine/styptic_powder = 10)
/obj/item/stack/medical/bruise_pack/one
@@ -95,7 +105,8 @@
M.heal_bodypart_damage((heal_brute/2))
return TRUE
if(iscarbon(M))
- return heal_carbon(M, user, heal_brute, 0)
+ return heal_carbon(M, user, heal_brute, heal_burn)
+ to_chat(user, "You can't heal [M] with \the [src]!")
to_chat(user, "You can't heal [M] with the \the [src]!")
/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
@@ -104,24 +115,51 @@
/obj/item/stack/medical/gauze
name = "medical gauze"
- desc = "A roll of elastic cloth that is extremely effective at stopping bleeding, heals minor wounds."
+ desc = "A roll of elastic cloth, perfect for stabilizing all kinds of wounds, from cuts and burns to broken bones."
gender = PLURAL
singular_name = "medical gauze"
icon_state = "gauze"
- var/stop_bleeding = 1800
- var/heal_brute = 5
- self_delay = 10
+ heal_brute = 5
+ self_delay = 50
+ other_delay = 20
+ amount = 10
+ max_amount = 10
+ absorption_rate = 0.25
+ absorption_capacity = 5
+ splint_factor = 0.35
custom_price = PRICE_REALLY_CHEAP
-/obj/item/stack/medical/gauze/heal(mob/living/M, mob/user)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.bleedsuppress && H.bleed_rate) //so you can't stack bleed suppression
- H.suppress_bloodloss(stop_bleeding)
- to_chat(user, "You stop the bleeding of [M]!")
- H.adjustBruteLoss(-(heal_brute))
- return TRUE
- to_chat(user, "You can not use \the [src] on [M]!")
+// gauze is only relevant for wounds, which are handled in the wounds themselves
+/obj/item/stack/medical/gauze/try_heal(mob/living/M, mob/user, silent)
+ var/obj/item/bodypart/limb = M.get_bodypart(check_zone(user.zone_selected))
+ if(!limb)
+ to_chat(user, "There's nothing there to bandage!")
+ return
+ if(!LAZYLEN(limb.wounds))
+ to_chat(user, "There's no wounds that require bandaging on [user==M ? "your" : "[M]'s"] [limb.name]!") // good problem to have imo
+ return
+
+ var/gauzeable_wound = FALSE
+ for(var/i in limb.wounds)
+ var/datum/wound/woundies = i
+ if(woundies.wound_flags & ACCEPTS_GAUZE)
+ gauzeable_wound = TRUE
+ break
+ if(!gauzeable_wound)
+ to_chat(user, "There's no wounds that require bandaging on [user==M ? "your" : "[M]'s"] [limb.name]!") // good problem to have imo
+ return
+
+ if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 0.8 > absorption_capacity)) // ignore if our new wrap is < 20% better than the current one, so someone doesn't bandage it 5 times in a row
+ to_chat(user, "The bandage currently on [user==M ? "your" : "[M]'s"] [limb.name] is still in good condition!")
+ return
+
+ user.visible_message("[user] begins wrapping the wounds on [M]'s [limb.name] with [src]...", "You begin wrapping the wounds on [user == M ? "your" : "[M]'s"] [limb.name] with [src]...")
+
+ if(!do_after(user, (user == M ? self_delay : other_delay), target=M))
+ return
+
+ user.visible_message("[user] applies [src] to [M]'s [limb.name].", "You bandage the wounds on [user == M ? "yourself" : "[M]'s"] [limb.name].")
+ limb.apply_gauze(src)
/obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_WIRECUTTER || I.get_sharpness())
@@ -133,6 +171,14 @@
"You cut [src] into pieces of cloth with [I].", \
"You hear cutting.")
use(2)
+ else if(I.is_drainable() && I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine))
+ if(!I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine, 10))
+ to_chat(user, "There's not enough sterilizine in [I] to sterilize [src]!")
+ return
+ user.visible_message("[user] pours the contents of [I] onto [src], sterilizing it.", "You pour the contents of [I] onto [src], sterilizing it.")
+ I.reagents.remove_reagent(/datum/reagent/space_cleaner/sterilizine, 10)
+ new /obj/item/stack/medical/gauze/adv/one(user.drop_location())
+ use(1)
else
return ..()
@@ -143,15 +189,22 @@
/obj/item/stack/medical/gauze/improvised
name = "improvised gauze"
singular_name = "improvised gauze"
- desc = "A roll of cloth roughly cut from something that can stop bleeding, but does not heal wounds."
- stop_bleeding = 900
heal_brute = 0
+ desc = "A roll of cloth roughly cut from something that does a decent job of stabilizing wounds, but less efficiently than real medical gauze."
+ self_delay = 60
+ other_delay = 30
+ absorption_rate = 0.15
+ absorption_capacity = 4
/obj/item/stack/medical/gauze/adv
name = "sterilized medical gauze"
- desc = "A roll of elastic sterilized cloth that is extremely effective at stopping bleeding, heals minor wounds and cleans them."
singular_name = "sterilized medical gauze"
- self_delay = 5
+ desc = "A roll of elastic sterilized cloth that is extremely effective at stopping bleeding and covering burns."
+ heal_brute = 6
+ self_delay = 45
+ other_delay = 15
+ absorption_rate = 0.4
+ absorption_capacity = 6
/obj/item/stack/medical/gauze/adv/one
amount = 1
@@ -161,38 +214,9 @@
is_cyborg = 1
cost = 250
-/obj/item/stack/medical/ointment
- name = "ointment"
- desc = "Used to treat those nasty burn wounds."
- gender = PLURAL
- singular_name = "ointment"
- icon_state = "ointment"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- var/heal_burn = 20
- self_delay = 20
- grind_results = list(/datum/reagent/medicine/silver_sulfadiazine = 10)
-
-/obj/item/stack/medical/ointment/one
- amount = 1
-
-/obj/item/stack/medical/ointment/heal(mob/living/M, mob/user)
- if(M.stat == DEAD)
- to_chat(user, " [M] is dead. You can not help [M.p_them()]!")
- return
- if(iscarbon(M))
- return heal_carbon(M, user, 0, heal_burn)
- if(AmBloodsucker(M))
- return
- to_chat(user, "You can't heal [M] with the \the [src]!")
-
-/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
- user.visible_message("[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?")
- return TOXLOSS
-
/obj/item/stack/medical/suture
name = "suture"
- desc = "Sterile sutures used to seal up cuts and lacerations."
+ desc = "Basic sterile sutures used to seal up cuts and lacerations and stop bleeding."
gender = PLURAL
singular_name = "suture"
icon_state = "suture"
@@ -201,9 +225,17 @@
amount = 15
max_amount = 15
repeating = TRUE
- var/heal_brute = 10
+ heal_brute = 10
+ stop_bleeding = 0.6
grind_results = list(/datum/reagent/medicine/spaceacillin = 2)
+/obj/item/stack/medical/suture/emergency
+ name = "emergency suture"
+ desc = "A value pack of cheap sutures, not very good at repairing damage, but still decent at stopping bleeding."
+ heal_brute = 5
+ amount = 5
+ max_amount = 5
+
/obj/item/stack/medical/suture/one
amount = 1
@@ -233,10 +265,39 @@
to_chat(user, "[M] is at full health.")
return FALSE
user.visible_message("[user] applies \the [src] on [M].", "You apply \the [src] on [M].")
- M.heal_bodypart_damage(heal_brute)
- return TRUE
+ return heal_carbon(M, user, heal_brute, heal_burn)
- to_chat(user, "You can't heal [M] with the \the [src]!")
+ to_chat(user, "You can't heal [M] with \the [src]!")
+
+/obj/item/stack/medical/ointment
+ name = "ointment"
+ desc = "Basic burn ointment, rated effective for second degree burns with proper bandaging, though it's still an effective stabilizer for worse burns. Not terribly good at outright healing burns though."
+ gender = PLURAL
+ singular_name = "ointment"
+ icon_state = "ointment"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ amount = 12
+ max_amount = 12
+ self_delay = 40
+ other_delay = 20
+
+ heal_burn = 5
+ flesh_regeneration = 2.5
+ sanitization = 0.3
+ grind_results = list(/datum/reagent/medicine/kelotane = 10)
+
+/obj/item/stack/medical/ointment/heal(mob/living/M, mob/user)
+ if(M.stat == DEAD)
+ to_chat(user, "[M] is dead! You can not help [M.p_them()].")
+ return
+ if(iscarbon(M))
+ return heal_carbon(M, user, heal_brute, heal_burn)
+ to_chat(user, "You can't heal [M] with \the [src]!")
+
+/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
+ user.visible_message("[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?")
+ return TOXLOSS
/obj/item/stack/medical/mesh
name = "regenerative mesh"
@@ -248,8 +309,10 @@
other_delay = 10
amount = 15
max_amount = 15
+ heal_burn = 10
repeating = TRUE
- var/heal_burn = 10
+ sanitization = 0.75
+ flesh_regeneration = 3
var/is_open = TRUE ///This var determines if the sterile packaging of the mesh has been opened.
grind_results = list(/datum/reagent/medicine/spaceacillin = 2)
@@ -292,8 +355,8 @@
to_chat(user, "[M] is dead! You can not help [M.p_them()].")
return
if(iscarbon(M))
- return heal_carbon(M, user, 0, heal_burn)
- to_chat(user, "You can't heal [M] with the \the [src]!")
+ return heal_carbon(M, user, heal_brute, heal_burn)
+ to_chat(user, "You can't heal [M] with \the [src]!")
/obj/item/stack/medical/mesh/try_heal(mob/living/M, mob/user, silent = FALSE)
@@ -308,7 +371,7 @@
return
. = ..()
-/obj/item/stack/medical/mesh/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/stack/medical/mesh/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!is_open & user.get_inactive_held_item() == src)
to_chat(user, "You need to open [src] first.")
return
@@ -323,6 +386,52 @@
return
. = ..()
+/obj/item/stack/medical/bone_gel
+ name = "bone gel"
+ singular_name = "bone gel"
+ desc = "A potent medical gel that, when applied to a damaged bone in a proper surgical setting, triggers an intense melding reaction to repair the wound. Can be directly applied alongside surgical sticky tape to a broken bone in dire circumstances, though this is very harmful to the patient and not recommended."
+
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "bone-gel"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+
+ amount = 4
+ self_delay = 20
+ grind_results = list(/datum/reagent/medicine/bicaridine = 10)
+ novariants = TRUE
+
+/obj/item/stack/medical/bone_gel/attack(mob/living/M, mob/user)
+ to_chat(user, "Bone gel can only be used on fractured limbs while aggressively holding someone!")
+ return
+
+/obj/item/stack/medical/bone_gel/suicide_act(mob/user)
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.visible_message("[C] is squirting all of \the [src] into [C.p_their()] mouth! That's not proper procedure! It looks like [C.p_theyre()] trying to commit suicide!")
+ if(do_after(C, 2 SECONDS))
+ C.emote("scream")
+ for(var/i in C.bodyparts)
+ var/obj/item/bodypart/bone = i
+ var/datum/wound/blunt/severe/oof_ouch = new
+ oof_ouch.apply_wound(bone)
+ var/datum/wound/blunt/critical/oof_OUCH = new
+ oof_OUCH.apply_wound(bone)
+
+ for(var/i in C.bodyparts)
+ var/obj/item/bodypart/bone = i
+ bone.receive_damage(brute=60)
+ use(1)
+ return (BRUTELOSS)
+ else
+ C.visible_message("[C] screws up like an idiot and still dies anyway!")
+ return (BRUTELOSS)
+
+/obj/item/stack/medical/bone_gel/cyborg
+ custom_materials = null
+ is_cyborg = 1
+ cost = 250
+
/obj/item/stack/medical/aloe
name = "aloe cream"
desc = "A healing paste you can apply on wounds."
@@ -355,4 +464,4 @@
M.heal_bodypart_damage(heal, heal)
return TRUE
- to_chat(user, "You can't heal [M] with the \the [src]!")
\ No newline at end of file
+ to_chat(user, "You can't heal [M] with the \the [src]!")
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index d4baea2487..29b4dea6d8 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -289,7 +289,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
resistance_flags = ACID_PROOF
armor = list("melee" = 100, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 100)
max_integrity = 40
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
var/icon_prefix
embedding = list("embed_chance" = 65)
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 4e5ffab1e0..44906a7179 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -184,13 +184,13 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
new /datum/stack_recipe("trash cart", /obj/structure/closet/crate/trashcart, 5, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("medical crate", /obj/structure/closet/crate/medical, 5, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("freezer crate", /obj/structure/closet/crate/freezer, 8, time = 50, one_per_turf = 1, on_floor = 1), \
- new /datum/stack_recipe("blood bag crate", /obj/structure/closet/crate/freezer/blood, 8, time = 50, one_per_turf = 1, on_floor = 1), \
- new /datum/stack_recipe("surplus limbs crate", /obj/structure/closet/crate/freezer/surplus_limbs, 8, time = 50, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blood bag crate", /obj/structure/closet/crate/freezer/blood/fake, 8, time = 50, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("surplus limbs crate", /obj/structure/closet/crate/freezer/surplus_limbs/fake, 8, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("radiation containment crate", /obj/structure/closet/crate/radiation, 8, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("hydroponics crate", /obj/structure/closet/crate/hydroponics, 5, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("engineering crate", /obj/structure/closet/crate/engineering, 5, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("eletrical crate", /obj/structure/closet/crate/engineering/electrical, 5, time = 50, one_per_turf = 1, on_floor = 1), \
- new /datum/stack_recipe("RCD storage crate", /obj/structure/closet/crate/rcd, 5, time = 50, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("RCD storage crate", /obj/structure/closet/crate/rcd/fake, 5, time = 50, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("science crate", /obj/structure/closet/crate/science, 5, time = 50, one_per_turf = 1, on_floor = 1), \
)), \
new /datum/stack_recipe_list("airlock assemblies", list( \
@@ -247,6 +247,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 15),\
+ new/datum/stack_recipe("training bokken", /obj/item/melee/bokken, 10, time = 15),\
null, \
new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index df9807b524..3e2bb675fa 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -25,9 +25,18 @@
var/list/mats_per_unit //list that tells you how much is in a single unit.
///Datum material type that this stack is made of
var/material_type
+ max_integrity = 100
//NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
var/obj/structure/table/tableVariant // we tables now (stores table variant to be built from this stack)
+ // The following are all for medical treatment, they're here instead of /stack/medical because sticky tape can be used as a makeshift bandage or splint
+ /// If set and this used as a splint for a broken bone wound, this is used as a multiplier for applicable slowdowns (lower = better) (also for speeding up burn recoveries)
+ var/splint_factor
+ /// How much blood flow this stack can absorb if used as a bandage on a cut wound, note that absorption is how much we lower the flow rate, not the raw amount of blood we suck up
+ var/absorption_capacity
+ /// How quickly we lower the blood flow on a cut wound we're bandaging. Expected lifetime of this bandage in ticks is thus absorption_capacity/absorption_rate, or until the cut heals, whichever comes first
+ var/absorption_rate
+
/obj/item/stack/on_grind()
for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists
grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size
@@ -224,7 +233,7 @@
return
T.PlaceOnTop(R.result_type, flags = CHANGETURF_INHERIT_AIR)
else
- O = new R.result_type(usr.drop_location())
+ O = new R.result_type(get_turf(usr))
if(O)
O.setDir(usr.dir)
log_craft("[O] crafted by [usr] at [loc_name(O.loc)]")
@@ -389,8 +398,7 @@
merge(AM)
. = ..()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/stack/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/stack/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.get_inactive_held_item() == src)
if(zero_amount())
return
diff --git a/code/game/objects/items/stacks/tape.dm b/code/game/objects/items/stacks/tape.dm
index b66d053807..bbfee8dece 100644
--- a/code/game/objects/items/stacks/tape.dm
+++ b/code/game/objects/items/stacks/tape.dm
@@ -7,10 +7,13 @@
icon = 'icons/obj/tapes.dmi'
icon_state = "tape_w"
var/prefix = "sticky"
+ w_class = WEIGHT_CLASS_TINY
+ full_w_class = WEIGHT_CLASS_TINY
item_flags = NOBLUDGEON
amount = 5
max_amount = 5
resistance_flags = FLAMMABLE
+ splint_factor = 0.8
grind_results = list(/datum/reagent/cellulose = 5)
var/list/conferred_embed = EMBED_HARMLESS
@@ -54,6 +57,7 @@
icon_state = "tape_y"
prefix = "super sticky"
conferred_embed = EMBED_HARMLESS_SUPERIOR
+ splint_factor = 0.6
/obj/item/stack/sticky_tape/pointy
name = "pointy tape"
@@ -69,4 +73,14 @@
desc = "You didn't know tape could look so sinister. Welcome to Space Station 13."
icon_state = "tape_spikes"
prefix = "super pointy"
- conferred_embed = EMBED_POINTY_SUPERIOR
\ No newline at end of file
+ conferred_embed = EMBED_POINTY_SUPERIOR
+
+/obj/item/stack/sticky_tape/surgical
+ name = "surgical tape"
+ singular_name = "surgical tape"
+ desc = "Made for patching broken bones back together alongside bone gel, not for playing pranks."
+ //icon_state = "tape_spikes"
+ prefix = "surgical"
+ conferred_embed = list("embed_chance" = 30, "pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE)
+ splint_factor = 0.4
+ custom_price = 500
diff --git a/code/game/objects/items/storage/_storage.dm b/code/game/objects/items/storage/_storage.dm
index fd4cc793ab..2fc1b6484d 100644
--- a/code/game/objects/items/storage/_storage.dm
+++ b/code/game/objects/items/storage/_storage.dm
@@ -19,8 +19,9 @@
return TRUE
/obj/item/storage/contents_explosion(severity, target)
+ var/in_storage = istype(loc, /obj/item/storage)? (max(0, severity - 1)) : (severity)
for(var/atom/A in contents)
- A.ex_act(severity, target)
+ A.ex_act(in_storage, target)
CHECK_TICK
//Cyberboss says: "USE THIS TO FILL IT, NOT INITIALIZE OR NEW"
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 99dbde2364..f15588a7f1 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -369,6 +369,7 @@
new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src)
+ new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src)
new /obj/item/clothing/mask/surgical(src)
new /obj/item/reagent_containers/medspray/sterilizine(src)
@@ -391,6 +392,7 @@
new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src)
+ new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src)
new /obj/item/clothing/mask/surgical(src)
new /obj/item/reagent_containers/medspray/sterilizine(src)
@@ -485,6 +487,7 @@
new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src)
+ new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src)
new /obj/item/clothing/suit/straight_jacket(src)
new /obj/item/clothing/mask/muzzle(src)
@@ -501,6 +504,7 @@
new /obj/item/scalpel/advanced(src)
new /obj/item/retractor/advanced(src)
new /obj/item/surgicaldrill/advanced(src)
+ new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src)
new /obj/item/clothing/suit/straight_jacket(src)
new /obj/item/clothing/mask/muzzle(src)
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 4fa742df46..3c554aa58e 100755
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -83,7 +83,7 @@
new /obj/item/multitool(src)
new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
new /obj/item/extinguisher/mini(src)
- new /obj/item/analyzer(src)
+ new /obj/item/analyzer/ranged(src)
//much roomier now that we've managed to remove two tools
/obj/item/storage/belt/utility/full/PopulateContents()
@@ -120,7 +120,7 @@
new /obj/item/wrench/brass(src)
new /obj/item/crowbar/brass(src)
new /obj/item/weldingtool/experimental/brass(src)
- new /obj/item/multitool(src)
+ new /obj/item/multitool/advanced/brass(src)
new /obj/item/stack/cable_coil(src, 30, "yellow")
/obj/item/storage/belt/medical
@@ -162,6 +162,7 @@
/obj/item/surgical_drapes, //for true paramedics
/obj/item/scalpel,
/obj/item/circular_saw,
+ /obj/item/bonesetter,
/obj/item/surgicaldrill,
/obj/item/retractor,
/obj/item/cautery,
@@ -181,7 +182,8 @@
/obj/item/implant,
/obj/item/implanter,
/obj/item/pinpointer/crew,
- /obj/item/reagent_containers/chem_pack
+ /obj/item/reagent_containers/chem_pack,
+ /obj/item/stack/sticky_tape //surgical tape
))
/obj/item/storage/belt/medical/surgery_belt_adv
@@ -444,10 +446,11 @@
/obj/item/storage/belt/durathread
name = "durathread toolbelt"
- desc = "A toolbelt made out of durathread, it seems resistant enough to hold even big tools like an RCD, it also has higher capacity."
+ desc = "A toolbelt made out of durathread, it seems robust enough to hold bigger tools like RCDs or RPDs, with enough pouches to hold more gear than a normal belt."
icon_state = "webbing-durathread"
item_state = "webbing-durathread"
resistance_flags = FIRE_PROOF
+ rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //If normal belts get this, the upgraded version should too
/obj/item/storage/belt/durathread/ComponentInitialize()
. = ..()
@@ -467,7 +470,7 @@
/obj/item/t_scanner,
/obj/item/analyzer,
/obj/item/geiger_counter,
- /obj/item/extinguisher/mini,
+ /obj/item/extinguisher,
/obj/item/radio,
/obj/item/clothing/gloves,
/obj/item/holosign_creator,
@@ -488,7 +491,8 @@
desc = "A belt for holding grenades."
icon_state = "grenadebeltnew"
item_state = "security"
-
+ rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
+
/obj/item/storage/belt/grenade/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
@@ -811,4 +815,3 @@
attack_verb = list("bashed", "slashes", "prods", "pokes")
fitting_swords = list(/obj/item/melee/rapier)
starting_sword = /obj/item/melee/rapier
-
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index 5d5f0eaa24..7532aacbfa 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -104,7 +104,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing)
return 1
-/obj/item/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE)
+/obj/item/storage/book/bible/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1, heal_mode = TRUE)
if (!user.IsAdvancedToolUser())
to_chat(user, "You don't have the dexterity to do this!")
@@ -238,11 +238,10 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
var/ownername = H.real_name
desc += "The name [ownername] is written in blood inside the cover."
-/obj/item/storage/book/bible/syndicate/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE)
- if (user.a_intent == INTENT_HELP)
- return ..()
- else
- return ..(M,user,heal_mode = FALSE)
+/obj/item/storage/book/bible/syndicate/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1, heal_mode = TRUE)
+ if(user.a_intent != INTENT_HELP)
+ heal_mode = FALSE //args pass over
+ return ..() // to ..()
/obj/item/storage/book/bible/syndicate/add_blood_DNA(list/blood_dna)
return FALSE
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 02ae867240..975621ead1 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -726,9 +726,9 @@ obj/item/storage/box/stingbangs
return (BRUTELOSS)
/obj/item/storage/box/hug/attack_self(mob/user)
- ..()
- user.changeNext_move(CLICK_CD_MELEE)
- playsound(loc, "rustle", 50, 1, -5)
+ . = ..()
+ user.DelayNextAction(CLICK_CD_MELEE)
+ playsound(src, "rustle", 50, 1, -5)
user.visible_message("[user] hugs \the [src].","You hug \the [src].")
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT,"hugbox", /datum/mood_event/hugbox)
@@ -1423,4 +1423,4 @@ obj/item/storage/box/stingbangs
/obj/item/storage/box/strange_seeds_5pack/PopulateContents()
for(var/i in 1 to 5)
- new /obj/item/seeds/random(src)
\ No newline at end of file
+ new /obj/item/seeds/random(src)
diff --git a/code/game/objects/items/storage/dakis.dm b/code/game/objects/items/storage/dakis.dm
index 1939593c8e..29f12df4c4 100644
--- a/code/game/objects/items/storage/dakis.dm
+++ b/code/game/objects/items/storage/dakis.dm
@@ -47,6 +47,6 @@
if(INTENT_HARM)
user.visible_message("[user] punches the [name]!")
playsound(src, 'sound/effects/shieldbash.ogg', 50, 1)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
////////////////////////////
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index 927a29407c..cde6f5bd5a 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -168,13 +168,19 @@
. += "There's a coupon on the back of the pack! You can tear it off once it's empty."
/obj/item/storage/fancy/cigarettes/AltClick(mob/living/carbon/user)
+ . = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
- var/obj/item/clothing/mask/cigarette/W = locate(/obj/item/clothing/mask/cigarette) in contents
+ var/obj/item/lighter/L = locate() in contents
+ if(L)
+ SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, L, user)
+ user.put_in_hands(L)
+ to_chat(user, "You take \a [L] out of the pack.")
+ return TRUE
+ var/obj/item/clothing/mask/cigarette/W = locate() in contents
if(W && contents.len > 0)
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, W, user)
user.put_in_hands(W)
- contents -= W
to_chat(user, "You take \a [W] out of the pack.")
else
to_chat(user, "There are no [icon_type]s left in the pack.")
@@ -398,6 +404,20 @@
STR.max_items = 6
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/nugget))
+/obj/item/storage/fancy/cracker_pack
+ name = "cracker pack"
+ desc = "A pack of delicious crackers. Keep away from parrots!"
+ icon = 'icons/obj/food/containers.dmi'
+ icon_state = "crackerbox"
+ icon_type = "cracker"
+ spawn_type = /obj/item/reagent_containers/food/snacks/cracker
+
+/obj/item/storage/fancy/cracker_pack/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_items = 6
+ STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/cracker))
+
/*
* Ring Box
*/
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index ea88f80304..480e1966e9 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -41,9 +41,25 @@
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/mesh(src)
new /obj/item/stack/medical/mesh(src)
- new /obj/item/reagent_containers/hypospray/medipen(src)
+ new /obj/item/reagent_containers/hypospray/medipen/ekit(src)
new /obj/item/healthanalyzer(src)
+/obj/item/storage/firstaid/emergency
+ icon_state = "medbriefcase"
+ name = "emergency first-aid kit"
+ desc = "A very simple first aid kit meant to secure and stabilize serious wounds for later treatment."
+
+/obj/item/storage/firstaid/emergency/PopulateContents()
+ if(empty)
+ return
+ var/static/items_inside = list(
+ /obj/item/healthanalyzer/wound = 1,
+ /obj/item/stack/medical/gauze = 1,
+ /obj/item/stack/medical/suture/emergency = 1,
+ /obj/item/stack/medical/ointment = 1,
+ /obj/item/reagent_containers/hypospray/medipen/ekit = 2)
+ generate_items_inside(items_inside,src)
+
/obj/item/storage/firstaid/ancient
icon_state = "firstaid"
desc = "A first aid kit with the ability to heal common types of injuries."
@@ -435,6 +451,7 @@
/obj/item/retractor,
/obj/item/cautery,
/obj/item/surgical_drapes,
+ /obj/item/bonesetter,
/obj/item/autosurgeon,
/obj/item/organ,
/obj/item/implant,
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index 6061feb893..4e6a0b3463 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -205,10 +205,7 @@
new /obj/item/paper(src)
new /obj/item/pen(src)
-/obj/item/storage/secure/safe/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/item/storage/secure/safe/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
return attack_self(user)
/obj/item/storage/secure/safe/HoS
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index fd50bd022f..ed0ee8ad07 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -20,6 +20,8 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
var/has_latches = TRUE
var/can_rubberify = TRUE
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //very protecc too
+ wound_bonus = -10
+ bare_wound_bonus = 5
/obj/item/storage/toolbox/greyscale
icon_state = "toolbox_default"
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 3b66e32d0a..442228ef31 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -169,6 +169,14 @@
O.imp = new /obj/item/implant/freedom(O)
O.update_icon()
+/obj/item/storage/box/syndie_kit/imp_warp
+ name = "boxed warp implant (with injector)"
+
+/obj/item/storage/box/syndie_kit/imp_warp/PopulateContents()
+ var/obj/item/implanter/O = new(src)
+ O.imp = new /obj/item/implant/warp(O)
+ O.update_icon()
+
/obj/item/storage/box/syndie_kit/imp_microbomb
name = "Microbomb Implant (with injector)"
@@ -327,6 +335,7 @@
new /obj/item/reagent_containers/glass/bottle/romerol(src)
new /obj/item/reagent_containers/syringe(src)
new /obj/item/reagent_containers/dropper(src)
+ new /obj/item/paper/guides/antag/romerol_instructions(src)
/obj/item/storage/box/syndie_kit/ez_clean/PopulateContents()
for(var/i in 1 to 3)
@@ -401,7 +410,7 @@
/obj/item/storage/box/syndie_kit/revolver
/obj/item/storage/box/syndie_kit/revolver/PopulateContents()
- new /obj/item/gun/ballistic/revolver(src)
+ new /obj/item/gun/ballistic/revolver/syndicate(src)
new /obj/item/ammo_box/a357(src)
/obj/item/storage/box/syndie_kit/pistol
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index fa0c9ba693..1a84b85a1a 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -14,6 +14,7 @@
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("beaten")
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
+ attack_speed = CLICK_CD_MELEE
var/stamforce = 35
var/turned_on = FALSE
@@ -144,8 +145,9 @@
return ..()
/obj/item/melee/baton/alt_pre_attack(atom/A, mob/living/user, params)
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
. = common_baton_melee(A, user, TRUE) //return true (attackchain interrupt) if this also returns true. no harm-disarming.
- user.changeNext_move(CLICK_CD_MELEE)
//return TRUE to interrupt attack chain.
/obj/item/melee/baton/proc/common_baton_melee(mob/M, mob/living/user, disarming = FALSE)
@@ -156,6 +158,7 @@
if(IS_STAMCRIT(user)) //CIT CHANGE - makes it impossible to baton in stamina softcrit
to_chat(user, "You're too exhausted to use [src] properly.")
return TRUE
+ user.DelayNextAction()
if(ishuman(M))
var/mob/living/carbon/human/L = M
if(check_martial_counter(L, user))
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index b601e4310e..08b91332ef 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -123,6 +123,7 @@
/obj/item/tank/analyzer_act(mob/living/user, obj/item/I)
atmosanalyzer_scan(air_contents, user, src)
+ return TRUE
/obj/item/tank/deconstruct(disassembled = TRUE)
if(!disassembled)
@@ -143,7 +144,6 @@
if(prob(50))
step(W, pick(GLOB.alldirs))
ADD_TRAIT(H, TRAIT_DISFIGURED, TRAIT_GENERIC)
- H.bleed_rate = 5
H.gib_animation()
sleep(3)
H.adjustBruteLoss(1000) //to make the body super-bloody
@@ -164,11 +164,13 @@
else
. = ..()
-/obj/item/tank/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/tank/ui_state(mob/user)
+ return GLOB.hands_state
+
+/obj/item/tank/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Tank", name, 400, 120, master_ui, state)
+ ui = new(user, src, "Tank", name)
ui.open()
/obj/item/tank/ui_data(mob/user)
@@ -205,10 +207,6 @@
else if(pressure == "max")
pressure = TANK_MAX_RELEASE_PRESSURE
. = TRUE
- else if(pressure == "input")
- pressure = input("New release pressure ([TANK_MIN_RELEASE_PRESSURE]-[TANK_MAX_RELEASE_PRESSURE] kPa):", name, distribute_pressure) as num|null
- if(!isnull(pressure) && !..())
- . = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 0a7eefb786..16a91b6358 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -72,7 +72,7 @@
QDEL_NULL(noz)
return ..()
-/obj/item/watertank/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/watertank/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if (user.get_item_by_slot(user.getBackSlot()) == src)
toggle_mister(user)
else
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index 881e4d5f1a..939b9e4905 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -1,4 +1,3 @@
-
#define SOURCE_PORTAL 1
#define DESTINATION_PORTAL 2
@@ -25,90 +24,72 @@
throw_speed = 3
throw_range = 7
custom_materials = list(/datum/material/iron=400)
+ var/tracking_range = 20
-/obj/item/locator/attack_self(mob/user)
- user.set_machine(src)
- var/dat
- if (temp)
- dat = "[temp]
Clear"
- else
- dat = {"
-Persistent Signal Locator
-Refresh"}
- user << browse(dat, "window=radio")
- onclose(user, "radio")
- return
+/obj/item/locator/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "BluespaceLocator", name)
+ ui.open()
-/obj/item/locator/Topic(href, href_list)
- ..()
- if (usr.stat || usr.restrained())
- return
- var/turf/current_location = get_turf(usr)//What turf is the user on?
- if(!current_location || is_centcom_level(current_location.z))//If turf was not found or they're on CentCom
- to_chat(usr, "[src] is malfunctioning.")
- return
- if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)))
- usr.set_machine(src)
- if (href_list["refresh"])
- temp = "Persistent Signal Locator"
- var/turf/sr = get_turf(src)
+/obj/item/locator/ui_data(mob/user)
+ var/list/data = list()
- if (sr)
- temp += "Beacon Signals: "
- for(var/obj/item/beacon/W in GLOB.teleportbeacons)
- if (!W.renamed)
- continue
- var/turf/tr = get_turf(W)
- if (tr.z == sr.z && tr)
- var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
- if (direct < 5)
- direct = "very strong"
- else
- if (direct < 10)
- direct = "strong"
- else
- if (direct < 20)
- direct = "weak"
- else
- direct = "very weak"
- temp += "[W.name]-[dir2text(get_dir(sr, tr))]-[direct] "
+ data["trackingrange"] = tracking_range
- temp += "Implant Signals: "
- for (var/obj/item/implant/tracking/W in GLOB.tracked_implants)
- if (!isliving(W.imp_in))
- continue
- var/mob/living/M = W.imp_in
- if (M.stat == DEAD)
- if (M.timeofdeath + W.lifespan_postmortem < world.time)
- continue
+ // Get our current turf location.
+ var/turf/sr = get_turf(src)
- var/turf/tr = get_turf(M)
- if (tr.z == sr.z && tr)
- var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
- if (direct < 20)
- if (direct < 5)
- direct = "very strong"
- else
- if (direct < 10)
- direct = "strong"
- else
- direct = "weak"
- temp += "[W.imp_in.name]-[dir2text(get_dir(sr, tr))]-[direct] "
+ if (sr)
+ // Check every teleport beacon.
+ var/list/tele_beacons = list()
+ for(var/obj/item/beacon/W in GLOB.teleportbeacons)
- temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.
Refresh "
+ // Get the tracking beacon's turf location.
+ var/turf/tr = get_turf(W)
+
+ // Make sure it's on a turf and that its Z-level matches the tracker's Z-level
+ if (tr && tr.z == sr.z)
+ // Get the distance between the beacon's turf and our turf
+ var/distance = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
+
+ // If the target is too far away, skip over this beacon.
+ if(distance > tracking_range)
+ continue
+
+ var/beacon_name
+
+ if(W.renamed)
+ beacon_name = W.name
+ else
+ var/area/A = get_area(W)
+ beacon_name = A.name
+
+ var/D = dir2text(get_dir(sr, tr))
+ tele_beacons += list(list(name = beacon_name, direction = D, distance = distance))
+
+ data["telebeacons"] = tele_beacons
+
+ var/list/track_implants = list()
+
+ for (var/obj/item/implant/tracking/W in GLOB.tracked_implants)
+ if (!W.imp_in || !isliving(W.loc))
+ continue
else
- temp += "Processing Error: Unable to locate orbital position. "
- else
- if (href_list["temp"])
- temp = null
- if (ismob(src.loc))
- attack_self(src.loc)
- else
- for(var/mob/M in fov_viewers(1, src))
- if (M.client)
- src.attack_self(M)
- return
+ var/mob/living/M = W.loc
+ if (M.stat == DEAD)
+ if (M.timeofdeath + W.lifespan_postmortem < world.time)
+ continue
+ var/turf/tr = get_turf(W)
+ var/distance = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
+ if(distance > tracking_range)
+ continue
+
+ var/D = dir2text(get_dir(sr, tr))
+ track_implants += list(list(name = W.imp_in.name, direction = D, distance = distance))
+ data["trackimplants"] = track_implants
+ return data
/*
* Hand-tele
@@ -141,14 +122,11 @@
return TRUE
return ..()
-/obj/item/hand_tele/proc/try_dispel_portal(atom/target, mob/user, delay = 30)
- var/datum/beam/B = user.Beam(target, icon_state = "rped_upgrade", maxdistance = 50)
- if(is_parent_of_portal(target) && (!delay || do_after(user, delay, target = target)))
+/obj/item/hand_tele/proc/try_dispel_portal(atom/target, mob/user)
+ if(is_parent_of_portal(target))
qdel(target)
to_chat(user, "You dispel [target] with \the [src]!")
- qdel(B)
return TRUE
- qdel(B)
return FALSE
/obj/item/hand_tele/afterattack(atom/target, mob/user)
@@ -190,13 +168,8 @@
user.show_message("\The [src] is recharging!")
return
var/atom/T = L[t1]
- var/implantcheckmate = FALSE
- if(isliving(T))
- var/mob/living/M = T
- if(!locate(/obj/item/implant/tracking) in M.implants) //The user was too slow and let the target mob's tracking implant expire or get removed.
- implantcheckmate = TRUE
var/area/A = get_area(T)
- if(A.noteleport || implantcheckmate)
+ if(A.noteleport)
to_chat(user, "\The [src] is malfunctioning.")
return
current_location = get_turf(user) //Recheck.
@@ -205,10 +178,12 @@
to_chat(user, "\The [src] is malfunctioning.")
return
user.show_message("Locked In.", MSG_AUDIBLE)
- var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), src, 300, 1, null, atmos_link_override)
+ var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), 300, 1, null, atmos_link_override)
if(!(LAZYLEN(created) == 2))
return
- try_move_adjacent(created[1])
+ RegisterSignal(created[1], COMSIG_PARENT_QDELETING, .proc/on_portal_destroy) //Gosh darn it kevinz.
+ RegisterSignal(created[2], COMSIG_PARENT_QDELETING, .proc/on_portal_destroy)
+ try_move_adjacent(created[1], user.dir)
active_portal_pairs[created[1]] = created[2]
var/obj/effect/portal/c1 = created[1]
var/obj/effect/portal/c2 = created[2]
diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm
index 91e8c49e5a..6159ab7ba0 100644
--- a/code/game/objects/items/tools/crowbar.dm
+++ b/code/game/objects/items/tools/crowbar.dm
@@ -18,6 +18,9 @@
toolspeed = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
+ wound_bonus = -10
+ bare_wound_bonus = 5
+
/obj/item/crowbar/suicide_act(mob/user)
user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1)
@@ -90,6 +93,7 @@
/obj/item/crowbar/power/attack_self(mob/user)
playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1)
var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power(drop_location())
+ cutjaws.name = name
to_chat(user, "You attach the cutting jaws to [src].")
qdel(src)
user.put_in_active_hand(cutjaws)
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index e9f517a9f1..86c223606d 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -31,6 +31,9 @@
"yellow" = rgb(255, 165, 0)
)
+ wound_bonus = -10
+ bare_wound_bonus = 5
+
/obj/item/screwdriver/suicide_act(mob/user)
user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!")
return(BRUTELOSS)
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 9560f7fab3..2e12a2ab8c 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -33,6 +33,8 @@
heat = 3800
tool_behaviour = TOOL_WELDER
toolspeed = 1
+ wound_bonus = 0
+ bare_wound_bonus = 5
/obj/item/weldingtool/Initialize()
. = ..()
diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm
index ac5a02b9fc..53a578a45d 100644
--- a/code/game/objects/items/tools/wirecutters.dm
+++ b/code/game/objects/items/tools/wirecutters.dm
@@ -117,6 +117,7 @@
/obj/item/wirecutters/power/attack_self(mob/user)
playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1)
var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power(drop_location())
+ pryjaws.name = name
to_chat(user, "You attach the pry jaws to [src].")
qdel(src)
user.put_in_active_hand(pryjaws)
diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm
index 678096db28..e1c09f394e 100644
--- a/code/game/objects/items/tools/wrench.dm
+++ b/code/game/objects/items/tools/wrench.dm
@@ -18,6 +18,9 @@
toolspeed = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
+ wound_bonus = -10
+ bare_wound_bonus = 5
+
/obj/item/wrench/suicide_act(mob/user)
user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1)
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index fe2e0df2eb..4e82df2452 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -447,7 +447,7 @@
block_parry_data = null
attack_verb = list("attacked", "struck", "hit")
total_mass_on = TOTAL_MASS_TOY_SWORD
- sharpness = IS_BLUNT
+ sharpness = SHARP_NONE
/obj/item/dualsaber/toy/ComponentInitialize()
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=0, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
@@ -466,7 +466,7 @@
attack_verb = list("attacked", "struck", "hit")
total_mass_on = TOTAL_MASS_TOY_SWORD
slowdown_wielded = 0
- sharpness = IS_BLUNT
+ sharpness = SHARP_NONE
/obj/item/dualsaber/hypereutactic/toy/ComponentInitialize()
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=0, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
@@ -574,10 +574,7 @@
else
. = ..()
-/obj/item/toy/prize/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/item/toy/prize/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(loc == user)
attack_self(user)
@@ -811,9 +808,8 @@
cards += "Ace of Clubs"
cards += "Ace of Diamonds"
-//ATTACK HAND IGNORING PARENT RETURN VALUE
//ATTACK HAND NOT CALLING PARENT
-/obj/item/toy/cards/deck/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/toy/cards/deck/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
draw_card(user)
/obj/item/toy/cards/deck/proc/draw_card(mob/user)
@@ -1234,7 +1230,7 @@
name = "steampunk watch"
desc = "A stylish steampunk watch made out of thousands of tiny cogwheels."
icon = 'icons/obj/clockwork_objects.dmi'
- icon_state = "dread_ipad"
+ icon_state = "clockwork_slab"
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
var/cooldown = 0
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index 4c6bcc08b4..2109d1038e 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -35,6 +35,10 @@
name = "syndi-cakes"
icon_state = "syndi_cakes"
+/obj/item/trash/energybar
+ name = "energybar wrapper"
+ icon_state = "energybar"
+
/obj/item/trash/waffles
name = "waffles tray"
icon_state = "waffles"
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 7170ba8be7..b1f8eac1da 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -65,7 +65,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 50
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
@@ -231,7 +231,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 50
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
@@ -249,6 +249,172 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1)
return(BRUTELOSS)
+/obj/item/katana/timestop
+ name = "temporal katana"
+ desc = "Delicately balanced, this finely-crafted blade hums with barely-restrained potential."
+ item_flags = ITEM_CAN_PARRY
+ block_parry_data = /datum/block_parry_data/bokken/quick_parry/proj
+
+/obj/item/katana/timestop/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
+ if(ishuman(owner))
+ var/mob/living/carbon/human/flynn = owner
+ flynn.emote("smirk")
+ new /obj/effect/timestop(get_turf(owner), 2, 50, list(owner))
+
+/obj/item/melee/bokken // parrying stick
+ name = "bokken"
+ desc = "A space-Japanese training sword made of wood and shaped like a katana."
+ icon_state = "bokken"
+ item_state = "bokken"
+ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
+ slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
+ w_class = WEIGHT_CLASS_BULKY
+ force = 9
+ throwforce = 10
+ damtype = STAMINA
+ attack_verb = list("whacked", "smacked", "struck")
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
+ hitsound = 'sound/weapons/grenadelaunch.ogg' // no good wood thunk sounds
+ var/harm = FALSE // TRUE = brute, FALSE = stam
+ var/reinforced = FALSE
+ var/burnt = FALSE
+ var/burned_in // text you burned in (with a welder)
+ var/quick_parry = FALSE // false = default parry, true = really small parry window
+ item_flags = ITEM_CAN_PARRY
+ block_parry_data = /datum/block_parry_data/bokken
+ bare_wound_bonus = 0
+ wound_bonus = 0
+
+/datum/block_parry_data/bokken // fucked up parry data, emphasizing quicker, shorter parries
+ parry_stamina_cost = 8 // be wise about when you parry, though, else you won't be able to fight enough to make it count
+ parry_time_windup = 0
+ parry_time_active = 10 // small parry window
+ parry_time_spindown = 0
+ // parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK // bokken users can no longer strike while parrying
+ parry_time_perfect = 1.5
+ parry_time_perfect_leeway = 1
+ parry_imperfect_falloff_percent = 7.5
+ parry_efficiency_to_counterattack = 100
+ parry_efficiency_considered_successful = 65 // VERY generous
+ parry_efficiency_perfect = 120
+ parry_efficiency_perfect_override = list(
+ TEXT_ATTACK_TYPE_PROJECTILE = 30,
+ )
+ parry_failed_stagger_duration = 3 SECONDS
+ parry_data = list(
+ PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25
+ )
+
+/datum/block_parry_data/bokken/quick_parry // emphasizing REALLY SHORT PARRIES
+ parry_stamina_cost = 6 // still more costly than most parries, but less than a full bokken parry
+ parry_time_active = 5 // REALLY small parry window
+ parry_time_perfect = 2.5 // however...
+ parry_time_perfect_leeway = 2.5 // the entire time, the parry is perfect
+ parry_failed_stagger_duration = 1 SECONDS
+ parry_failed_clickcd_duration = 1 SECONDS // more forgiving punishments for missed parries
+ // still, don't fucking miss your parries or you're down stamina and staggered to shit
+
+/datum/block_parry_data/bokken/quick_parry/proj
+ parry_efficiency_perfect_override = list()
+
+/obj/item/melee/bokken/Initialize()
+ . = ..()
+ AddElement(/datum/element/sword_point)
+
+/obj/item/melee/bokken/attack_self(mob/user)
+ harm = !harm
+ if(harm)
+ force -= 2
+ damtype = BRUTE
+ attack_verb = list("bashed", "smashed", "attacked")
+ bare_wound_bonus = 15 // having your leg smacked by a wooden stick is probably not great for it if it's naked
+ wound_bonus = 0
+ else
+ force += 2
+ damtype = STAMINA
+ attack_verb = list("whacked", "smacked", "struck")
+ bare_wound_bonus = 0
+ wound_bonus = 0
+ to_chat(user, "[src] is now [harm ? "harmful" : "not quite as harmful"].")
+
+/obj/item/melee/bokken/AltClick(mob/user)
+ . = ..()
+ quick_parry = !quick_parry
+ if(quick_parry)
+ block_parry_data = /datum/block_parry_data/bokken/quick_parry
+ else
+ block_parry_data = /datum/block_parry_data/bokken
+ to_chat(user, "[src] is now [quick_parry ? "emphasizing shorter parries, forcing you to riposte or be staggered" : "emphasizing longer parries, with a shorter window to riposte but more forgiving parries"].")
+
+/obj/item/melee/bokken/attackby(obj/item/I, mob/living/user, params)
+ if(istype(I, /obj/item/pen))
+ var/new_name = stripped_input(user, "What do you wish to name [src]?", "New Name", "bokken", 30)
+ if(new_name)
+ name = new_name
+ if(I.tool_behaviour == TOOL_WELDER)
+ var/new_burn = stripped_input(user, "What do you wish to burn into [src]?", "Burnt Inscription","", 140)
+ if(new_burn)
+ burned_in = new_burn
+ if(!burnt)
+ icon_state += "_burnt"
+ item_state += "_burnt"
+ burnt = TRUE
+ update_icon()
+ update_icon_state()
+ if(istype(I, /obj/item/stack/rods))
+ var/obj/item/stack/rods/R = I
+ if(!reinforced)
+ if(R.use(1))
+ force++
+ reinforced = TRUE
+ to_chat(user, "You slide a metal rod into [src]\'s hilt. It feels a little heftier in your hands.")
+ else
+ to_chat(user, "[src] already has a weight slid into the hilt.")
+
+/obj/item/melee/bokken/examine(mob/user)
+ . = ..()
+ if(quick_parry)
+ . += " [src] is gripped in a way to emphasize quicker parries."
+ if(reinforced)
+ . += " There's a metal rod shoved into the base."
+ if(burnt)
+ . += " Burned into the \"blade\" is [burned_in]."
+
+/obj/item/melee/bokken/debug
+ name = "funny debug parrying stick"
+ desc = "if you see this you've fucked up somewhere my good man"
+ block_parry_data = /datum/block_parry_data/bokken/debug
+
+/obj/item/melee/bokken/debug/AltClick(mob/user)
+ quick_parry = !quick_parry
+ if(quick_parry)
+ block_parry_data = /datum/block_parry_data/bokken/quick_parry/debug
+ else
+ block_parry_data = /datum/block_parry_data/bokken/debug
+ to_chat(user, "[src] is now [quick_parry ? "emphasizing shorter parries, forcing you to riposte or be staggered" : "emphasizing longer parries, with a shorter window to riposte but more forgiving parries"].")
+
+/datum/block_parry_data/bokken/debug
+ parry_efficiency_perfect_override = list()
+ parry_data = list(
+ PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25
+ PARRY_DISARM_ATTACKER = TRUE,
+ PARRY_KNOCKDOWN_ATTACKER = 10,
+ PARRY_STAGGER_ATTACKER = 10,
+ PARRY_DAZE_ATTACKER = 10,
+ )
+
+/datum/block_parry_data/bokken/quick_parry/debug
+ parry_efficiency_perfect_override = list()
+ parry_data = list(
+ PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25
+ PARRY_DISARM_ATTACKER = TRUE,
+ PARRY_KNOCKDOWN_ATTACKER = 10,
+ PARRY_STAGGER_ATTACKER = 10,
+ PARRY_DAZE_ATTACKER = 10,
+ )
+
+
/obj/item/wirerod
name = "wired rod"
desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit."
@@ -260,6 +426,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
w_class = WEIGHT_CLASS_NORMAL
custom_materials = list(/datum/material/iron=1150, /datum/material/glass=75)
attack_verb = list("hit", "bludgeoned", "whacked", "bonked")
+ wound_bonus = -10
/obj/item/wirerod/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/shard))
@@ -297,13 +464,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
force = 2
- throwforce = 20 //This is never used on mobs since this has a 100% embed chance.
+ throwforce = 10 //This is never used on mobs since this has a 100% embed chance.
throw_speed = 4
embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15)
armour_penetration = 40
w_class = WEIGHT_CLASS_SMALL
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
custom_materials = list(/datum/material/iron=500, /datum/material/glass=500)
resistance_flags = FIRE_PROOF
@@ -316,7 +483,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
/obj/item/throwing_star/toy
name = "toy throwing star"
desc = "An aerodynamic disc strapped with adhesive for sticking to people, good for playing pranks and getting yourself killed by security."
- sharpness = IS_BLUNT
+ sharpness = SHARP_NONE
force = 0
throwforce = 0
embedding = list("pain_mult" = 0, "jostle_pain_mult" = 0, "embed_chance" = 100, "fall_chance" = 0)
@@ -353,7 +520,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
icon_state = extended_icon_state
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
else
force = initial(force)
w_class = WEIGHT_CLASS_SMALL
@@ -361,7 +528,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
icon_state = retracted_icon_state
attack_verb = list("stubbed", "poked")
hitsound = 'sound/weapons/genhit.ogg'
- sharpness = IS_BLUNT
+ sharpness = SHARP_NONE
/obj/item/switchblade/suicide_act(mob/user)
user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -462,7 +629,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throwforce = 0
throw_range = 0
throw_speed = 0
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
total_mass = TOTAL_MASS_HAND_REPLACEMENT
@@ -574,6 +741,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
force = 10
+ wound_bonus = -10
throwforce = 12
attack_verb = list("beat", "smacked")
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 3.5)
@@ -590,6 +758,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
obj_flags = UNIQUE_RENAME
var/chaplain_spawnable = TRUE
total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
+ wound_bonus = -5
/obj/item/melee/baseball_bat/chaplain/Initialize()
. = ..()
@@ -626,7 +795,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
homerun_ready = 0
return
else if(!target.anchored)
- target.throw_at(throw_target, rand(1,2), 7, user)
+ var/whack_speed = (prob(60) ? 1 : 4)
+ target.throw_at(throw_target, rand(1, 2), whack_speed, user) // sorry friends, 7 speed batting caused wounds to absolutely delete whoever you knocked your target into (and said target)
/obj/item/melee/baseball_bat/ablative
name = "metal baseball bat"
@@ -858,7 +1028,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
block_chance = 40
throwforce = 20
throw_speed = 4
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
attack_verb = list("cut", "sliced", "diced")
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 1203c5a1df..14017ffb2d 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -105,15 +105,19 @@
/obj/proc/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0) //used by attack_alien, attack_animal, and attack_slime
if(SEND_SIGNAL(src, COMSIG_OBJ_ATTACK_GENERIC, user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration) & COMPONENT_STOP_GENERIC_ATTACK)
return FALSE
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
user.do_attack_animation(src)
- user.changeNext_move(CLICK_CD_MELEE)
- return take_damage(damage_amount, damage_type, damage_flag, sound_effect, get_dir(src, user), armor_penetration)
+ . = take_damage(damage_amount, damage_type, damage_flag, sound_effect, get_dir(src, user), armor_penetration)
+ user.DelayNextAction()
/obj/attack_alien(mob/living/carbon/alien/humanoid/user)
if(attack_generic(user, 60, BRUTE, "melee", 0))
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
/obj/attack_animal(mob/living/simple_animal/M)
+ if(!M.CheckActionCooldown(CLICK_CD_MELEE))
+ return
if(!M.melee_damage_upper && !M.obj_damage)
M.emote("custom", message = "[M.friendly_verb_continuous] [src].")
return 0
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 85f0066e3f..1927adb477 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -10,6 +10,11 @@
var/damtype = BRUTE
var/force = 0
+ /// How good a given object is at causing wounds on carbons. Higher values equal better shots at creating serious wounds.
+ var/wound_bonus = 0
+ /// If this attacks a human with no wound armor on the affected body part, add this to the wound mod. Some attacks may be significantly worse at wounding if there's even a slight layer of armor to absorb some of it vs bare flesh
+ var/bare_wound_bonus = 0
+
var/datum/armor/armor
var/obj_integrity //defaults to max_integrity
var/max_integrity = 500
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index cce4955210..39f2d276a1 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -28,12 +28,10 @@
queue_smooth_neighbors(src)
return ..()
-/obj/structure/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
- if(.)
- return
if(structureclimber && structureclimber != user)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
user.do_attack_animation(src)
structureclimber.DefaultCombatKnockdown(40)
structureclimber.visible_message("[structureclimber] has been knocked off [src].", "You're knocked off [src]!", "You see [structureclimber] get knocked off [src].")
diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm
index a6cd8df746..ce11daec54 100644
--- a/code/game/objects/structures/aliens.dm
+++ b/code/game/objects/structures/aliens.dm
@@ -249,7 +249,7 @@
/obj/structure/alien/egg/attack_alien(mob/living/carbon/alien/user)
return attack_hand(user)
-/obj/structure/alien/egg/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/alien/egg/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
@@ -269,8 +269,7 @@
return
else
to_chat(user, "It feels slimy.")
- user.changeNext_move(CLICK_CD_MELEE)
-
+ user.DelayNextAction(CLICK_CD_MELEE)
/obj/structure/alien/egg/proc/Grow()
status = GROWN
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 827e9a7b0a..47584a1775 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -45,8 +45,6 @@
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
@@ -75,12 +73,16 @@
. = ..()
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)
+/obj/item/canvas/ui_state(mob/user)
+ if(finalized)
+ return GLOB.physical_obscured_state
+ else
+ return GLOB.default_state
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/canvas/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Canvas", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "Canvas", name)
ui.set_autoupdate(FALSE)
ui.open()
@@ -190,8 +192,6 @@
icon_state = "19x19"
width = 19
height = 19
- ui_x = 600
- ui_y = 600
pixel_x = 6
pixel_y = 9
framed_offset_x = 8
@@ -201,8 +201,6 @@
icon_state = "23x19"
width = 23
height = 19
- ui_x = 800
- ui_y = 600
pixel_x = 4
pixel_y = 10
framed_offset_x = 6
@@ -212,8 +210,6 @@
icon_state = "23x23"
width = 23
height = 23
- ui_x = 800
- ui_y = 800
pixel_x = 5
pixel_y = 9
framed_offset_x = 5
@@ -262,7 +258,7 @@
/obj/structure/sign/painting/examine(mob/user)
. = ..()
if(C)
- C.ui_interact(user,state = GLOB.physical_obscured_state)
+ C.ui_interact(user)
/obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I)
. = ..()
diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm
index 7ea678cae4..905888c904 100644
--- a/code/game/objects/structures/barsigns.dm
+++ b/code/game/objects/structures/barsigns.dm
@@ -52,10 +52,7 @@
/obj/structure/sign/barsign/attack_ai(mob/user)
return attack_hand(user)
-/obj/structure/sign/barsign/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/sign/barsign/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!allowed(user))
to_chat(user, "Access denied.")
return
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index 299ba7b659..f3c4679d21 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -319,10 +319,43 @@
throwforce = 10
throw_range = 3
hitsound = 'sound/items/trayhit1.ogg'
- block_chance = 50
custom_materials = list(/datum/material/iron = 2000)
var/break_chance = 5 //Likely hood of smashing the chair.
var/obj/structure/chair/origin_type = /obj/structure/chair
+ item_flags = ITEM_CAN_PARRY | ITEM_CAN_BLOCK
+ block_parry_data = /datum/block_parry_data/chair
+
+/obj/item/chair/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/two_handed, require_twohands = TRUE)
+
+/datum/block_parry_data/chair
+ block_damage_multiplier = 0.7
+ block_stamina_efficiency = 2
+ block_stamina_cost_per_second = 1.5
+ block_slowdown = 0.5
+ block_lock_attacking = FALSE
+ block_lock_sprinting = TRUE
+ block_start_delay = 1.5
+ block_damage_absorption = 7
+ block_damage_limit = 20
+ block_resting_stamina_penalty_multiplier = 2
+ block_projectile_mitigation = 20
+ parry_stamina_cost = 5
+ parry_time_windup = 1
+ parry_time_active = 11
+ parry_time_spindown = 2
+ parry_time_perfect = 1.5
+ parry_time_perfect_leeway = 1
+ parry_imperfect_falloff_percent = 7.5
+ parry_efficiency_to_counterattack = 100
+ parry_efficiency_considered_successful = 50
+ parry_efficiency_perfect = 120
+ parry_efficiency_perfect_override = list(
+ TEXT_ATTACK_TYPE_PROJECTILE = 30,
+ )
+ parry_failed_stagger_duration = 3.5 SECONDS
+ parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5)
/obj/item/chair/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins hitting [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index e45ddf650c..45cac650b8 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -311,10 +311,7 @@ LINEN BINS
/obj/structure/bedsheetbin/attack_paw(mob/user)
return attack_hand(user)
-/obj/structure/bedsheetbin/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/bedsheetbin/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.incapacitated())
return
if(amount >= 1)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 4b9251d8ec..043232e9e3 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -37,12 +37,13 @@
var/lock_in_use = FALSE //Someone is doing some stuff with the lock here, better not proceed further
var/eigen_teleport = FALSE //If the closet leads to Mr Tumnus.
var/obj/structure/closet/eigen_target //Where you go to.
-
+ var/should_populate_contents = TRUE
/obj/structure/closet/Initialize(mapload)
. = ..()
update_icon()
- PopulateContents()
+ if(should_populate_contents)
+ PopulateContents()
if(mapload && !opened) // if closed, any item at the crate's loc is put in the contents
addtimer(CALLBACK(src, .proc/take_contents), 0)
if(secure)
@@ -458,10 +459,7 @@
return
container_resist(user)
-/obj/structure/closet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/closet/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.lying && get_dist(src, user) > 0)
return
@@ -506,8 +504,6 @@
if(opened)
return
if(ismovable(loc))
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
var/atom/movable/AM = loc
AM.relay_container_resist(user, src)
return
@@ -516,8 +512,6 @@
return
//okay, so the closet is either welded or locked... resist!!!
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("[src] begins to shake violently!", \
"You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear banging from [src].")
diff --git a/code/game/objects/structures/crates_lockers/closets/genpop.dm b/code/game/objects/structures/crates_lockers/closets/genpop.dm
index 04c2f37b0f..7be12a4819 100644
--- a/code/game/objects/structures/crates_lockers/closets/genpop.dm
+++ b/code/game/objects/structures/crates_lockers/closets/genpop.dm
@@ -91,7 +91,7 @@
locked = TRUE
return ..()
-/obj/structure/closet/secure_closet/genpop/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/closet/secure_closet/genpop/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.lying && get_dist(src, user) > 0)
return
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 99bce305f8..ee202f9504 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -41,10 +41,8 @@
if(manifest)
. += "manifest"
-/obj/structure/closet/crate/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/closet/crate/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
- if(.)
- return
if(manifest)
tear_manifest(user)
@@ -144,6 +142,9 @@
desc = "A freezer containing packs of blood."
icon_state = "surgery"
+/obj/structure/closet/crate/freezer/blood/fake
+ should_populate_contents = FALSE
+
/obj/structure/closet/crate/freezer/blood/PopulateContents()
. = ..()
new /obj/item/reagent_containers/blood(src)
@@ -164,6 +165,9 @@
name = "surplus prosthetic limbs"
desc = "A crate containing an assortment of cheap prosthetic limbs."
+/obj/structure/closet/crate/freezer/surplus_limbs/fake
+ should_populate_contents = FALSE
+
/obj/structure/closet/crate/freezer/surplus_limbs/PopulateContents()
. = ..()
new /obj/item/bodypart/l_arm/robot/surplus(src)
@@ -198,6 +202,9 @@
name = "\improper RCD crate"
icon_state = "engi_crate"
+/obj/structure/closet/crate/rcd/fake
+ should_populate_contents = FALSE
+
/obj/structure/closet/crate/rcd/PopulateContents()
..()
for(var/i in 1 to 4)
diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm
index d8c2f7f91c..3cee96e435 100644
--- a/code/game/objects/structures/crates_lockers/crates/large.dm
+++ b/code/game/objects/structures/crates_lockers/crates/large.dm
@@ -8,7 +8,7 @@
delivery_icon = "deliverybox"
integrity_failure = 0 //Makes the crate break when integrity reaches 0, instead of opening and becoming an invisible sprite.
-/obj/structure/closet/crate/large/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/closet/crate/large/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
if(manifest)
tear_manifest(user)
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 4db889b392..19c0f0aed1 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -9,6 +9,8 @@
armor = list("melee" = 30, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 100)
max_integrity = 200
integrity_failure = 0.25
+ attack_hand_speed = CLICK_CD_MELEE
+ attack_hand_is_action = TRUE
var/obj/item/showpiece = null
var/alert = TRUE
var/open = FALSE
@@ -157,11 +159,7 @@
/obj/structure/displaycase/attack_paw(mob/user)
return attack_hand(user)
-/obj/structure/displaycase/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
- user.changeNext_move(CLICK_CD_MELEE)
+/obj/structure/displaycase/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if (showpiece && (broken || open))
to_chat(user, "You deactivate the hover field built into the case.")
log_combat(user, src, "deactivates the hover field of")
@@ -347,3 +345,212 @@
name = initial(I.name)
icon = initial(I.icon)
icon_state = initial(I.icon_state)
+/* Selling people in jars is currently disabled.
+/obj/structure/displaycase/forsale
+ name = "vend-a-tray"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "laserbox0"
+ desc = "A display case with an ID-card swiper. Use your ID to purchase the contents."
+ density = FALSE
+ max_integrity = 100
+ req_access = null
+ showpiece_type = /obj/item/reagent_containers/food
+ alert = FALSE //No, we're not calling the fire department because someone stole your cookie.
+ glass_fix = FALSE //Fixable with tools instead.
+ ///The price of the item being sold. Altered by grab intent ID use.
+ var/sale_price = 20
+ ///The Account which will receive payment for purchases. Set by the first ID to swipe the tray.
+ var/datum/bank_account/payments_acc = null
+ ///We're using the same trick as paper does in order to cache the image, and only load the UI when messed with.
+ var/list/viewing_ui = list()
+
+/obj/structure/displaycase/forsale/update_icon() //remind me to fix my shitcode later
+ var/icon/I
+ if(open)
+ I = icon('icons/obj/stationobjs.dmi',"laserboxb0")
+ else
+ I = icon('icons/obj/stationobjs.dmi',"laserbox0")
+ if(!showpiece && !open)
+ I = icon('icons/obj/stationobjs.dmi',"laserbox_open")
+ if(broken)
+ I = icon('icons/obj/stationobjs.dmi',"laserbox_broken")
+ if(showpiece)
+ var/icon/S = getFlatIcon(showpiece)
+ S.Scale(17,17)
+ I.Blend(S,ICON_UNDERLAY,8,12)
+ src.icon = I
+ return
+
+/obj/structure/displaycase/forsale/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Vendatray", name)
+ ui.set_autoupdate(FALSE)
+ viewing_ui[user] = ui
+ ui.open()
+
+/obj/structure/displaycase/forsale/ui_data(mob/user)
+ var/list/data = list()
+ var/register = FALSE
+ if(payments_acc)
+ register = TRUE
+ data["owner_name"] = payments_acc.account_holder
+ if(showpiece)
+ data["product_name"] = capitalize(showpiece.name)
+ var/base64 = icon2base64(icon(showpiece.icon, showpiece.icon_state))
+ data["product_icon"] = base64
+ data["registered"] = register
+ data["product_cost"] = sale_price
+ data["tray_open"] = open
+ return data
+
+/obj/structure/displaycase/forsale/ui_act(action, params)
+ if(..())
+ return
+ var/obj/item/card/id/potential_acc = usr.get_idcard(hand_first = TRUE)
+ switch(action)
+ if("Buy")
+ if(!showpiece)
+ to_chat(usr, "There's nothing for sale.")
+ return TRUE
+ if(broken)
+ to_chat(usr, "[src] appears to be broken.")
+ return TRUE
+ if(!payments_acc)
+ to_chat(usr, "[src] hasn't been registered yet.")
+ return TRUE
+ if(!usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ return TRUE
+ if(!potential_acc)
+ to_chat(usr, "No ID card detected.")
+ return
+ var/datum/bank_account/account = potential_acc.registered_account
+ if(!account)
+ to_chat(usr, "[potential_acc] has no account registered!")
+ return
+ if(!account.has_money(sale_price))
+ to_chat(usr, "You do not possess the funds to purchase this.")
+ return TRUE
+ else
+ account.adjust_money(-sale_price)
+ if(payments_acc)
+ payments_acc.adjust_money(sale_price)
+ usr.put_in_hands(showpiece)
+ to_chat(usr, "You purchase [showpiece] for [sale_price] credits.")
+ playsound(src, 'sound/effects/cashregister.ogg', 40, TRUE)
+ icon = 'icons/obj/stationobjs.dmi'
+ flick("laserbox_vend", src)
+ showpiece = null
+ update_icon()
+ SStgui.update_uis(src)
+ return TRUE
+ if("Open")
+ if(!payments_acc)
+ to_chat(usr, "[src] hasn't been registered yet.")
+ return TRUE
+ if(!potential_acc || !potential_acc.registered_account)
+ return
+ if(!check_access(potential_acc))
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
+ return
+ toggle_lock()
+ SStgui.update_uis(src)
+ if("Register")
+ if(payments_acc)
+ return
+ if(!potential_acc || !potential_acc.registered_account)
+ return
+ if(!check_access(potential_acc))
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
+ return
+ payments_acc = potential_acc.registered_account
+ playsound(src, 'sound/machines/click.ogg', 20, TRUE)
+ if("Adjust")
+ if(!check_access(potential_acc) || potential_acc.registered_account != payments_acc)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
+ return
+
+ var/new_price_input = input(usr,"Set the sale price for this vend-a-tray.","new price",0) as num|null
+ if(isnull(new_price_input) || (payments_acc != potential_acc.registered_account))
+ to_chat(usr, "[src] rejects your new price.")
+ return
+ if(!usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) )
+ to_chat(usr, "You need to get closer!")
+ return
+ new_price_input = clamp(round(new_price_input, 1), 10, 1000)
+ sale_price = new_price_input
+ to_chat(usr, "The cost is now set to [sale_price].")
+ SStgui.update_uis(src)
+ return TRUE
+ . = TRUE
+/obj/structure/displaycase/forsale/attackby(obj/item/I, mob/living/user, params)
+ if(isidcard(I))
+ //Card Registration
+ var/obj/item/card/id/potential_acc = I
+ if(!potential_acc.registered_account)
+ to_chat(user, "This ID card has no account registered!")
+ return
+ if(payments_acc == potential_acc.registered_account)
+ playsound(src, 'sound/machines/click.ogg', 20, TRUE)
+ toggle_lock()
+ return
+ if(istype(I, /obj/item/pda))
+ return TRUE
+ SStgui.update_uis(src)
+ . = ..()
+
+
+/obj/structure/displaycase/forsale/multitool_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(obj_integrity <= (integrity_failure * max_integrity))
+ to_chat(user, "You start recalibrating [src]'s hover field...")
+ if(do_after(user, 20, target = src))
+ broken = 0
+ obj_integrity = max_integrity
+ update_icon()
+ return TRUE
+
+/obj/structure/displaycase/forsale/wrench_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(open && user.a_intent == INTENT_HELP )
+ if(anchored)
+ to_chat(user, "You start unsecuring [src]...")
+ else
+ to_chat(user, "You start securing [src]...")
+ if(I.use_tool(src, user, 16, volume=50))
+ if(QDELETED(I))
+ return
+ if(anchored)
+ to_chat(user, "You unsecure [src].")
+ else
+ to_chat(user, "You secure [src].")
+ anchored = !anchored
+ return
+ else if(!open && user.a_intent == INTENT_HELP)
+ to_chat(user, "[src] must be open to move it.")
+ return
+
+/obj/structure/displaycase/forsale/emag_act(mob/user)
+ . = ..()
+ payments_acc = null
+ req_access = list()
+ to_chat(user, "[src]'s card reader fizzles and smokes, and the account owner is reset.")
+
+/obj/structure/displaycase/forsale/examine(mob/user)
+ . = ..()
+ if(showpiece && !open)
+ . += "[showpiece] is for sale for [sale_price] credits."
+ if(broken)
+ . += "[src] is sparking and the hover field generator seems to be overloaded. Use a multitool to fix it."
+
+/obj/structure/displaycase/forsale/obj_break(damage_flag)
+ if(!broken && !(flags_1 & NODECONSTRUCT_1))
+ broken = TRUE
+ playsound(src, "shatter", 70, TRUE)
+ update_icon()
+ trigger_alarm() //In case it's given an alarm anyway.
+
+/obj/structure/displaycase/forsale/kitchen
+ desc = "A display case with an ID-card swiper. Use your ID to purchase the contents. Meant for the bartender and chef."
+ req_one_access = list(ACCESS_KITCHEN, ACCESS_BAR)
+*/
\ No newline at end of file
diff --git a/code/game/objects/structures/divine.dm b/code/game/objects/structures/divine.dm
index 5afe97f669..f64397df09 100644
--- a/code/game/objects/structures/divine.dm
+++ b/code/game/objects/structures/divine.dm
@@ -7,7 +7,7 @@
density = FALSE
can_buckle = 1
-/obj/structure/sacrificealtar/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/sacrificealtar/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
@@ -30,7 +30,7 @@
var/time_between_uses = 1800
var/last_process = 0
-/obj/structure/healingfountain/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/healingfountain/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm
index bacb6fc92b..7fdec9b3d9 100644
--- a/code/game/objects/structures/dresser.dm
+++ b/code/game/objects/structures/dresser.dm
@@ -19,7 +19,7 @@
new /obj/item/stack/sheet/mineral/wood(drop_location(), 10)
qdel(src)
-/obj/structure/dresser/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/dresser/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(. || !ishuman(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
@@ -46,7 +46,7 @@
switch(choice)
if("Underwear")
var/new_undies = input(H, "Select your underwear", "Changing") as null|anything in GLOB.underwear_list
- if(H.underwear)
+ if(new_undies)
H.underwear = new_undies
H.saved_underwear = new_undies
var/datum/sprite_accessory/underwear/bottom/B = GLOB.underwear_list[new_undies]
diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm
index a279070e69..84926ccfb0 100644
--- a/code/game/objects/structures/extinguisher.dm
+++ b/code/game/objects/structures/extinguisher.dm
@@ -69,10 +69,7 @@
return ..()
-/obj/structure/extinguisher_cabinet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/extinguisher_cabinet/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(iscyborg(user) || isalien(user))
return
if(stored_extinguisher)
diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm
index eaa6e574cd..b654f4f5c0 100644
--- a/code/game/objects/structures/false_walls.dm
+++ b/code/game/objects/structures/false_walls.dm
@@ -41,7 +41,7 @@
new /obj/structure/falsewall/brass(loc)
qdel(src)
-/obj/structure/falsewall/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/falsewall/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(opening)
return
. = ..()
@@ -180,7 +180,7 @@
radiate()
return ..()
-/obj/structure/falsewall/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/falsewall/uranium/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
radiate()
. = ..()
diff --git a/code/game/objects/structures/femur_breaker.dm b/code/game/objects/structures/femur_breaker.dm
index 1fa21d119e..2ac56ec4fb 100644
--- a/code/game/objects/structures/femur_breaker.dm
+++ b/code/game/objects/structures/femur_breaker.dm
@@ -32,7 +32,7 @@
if (LAZYLEN(buckled_mobs))
. += "Someone appears to be strapped in. You can help them unbuckle, or activate the femur breaker."
-/obj/structure/femur_breaker/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/femur_breaker/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
// Currently being used
diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm
index 5803fb1306..f90161f587 100644
--- a/code/game/objects/structures/fence.dm
+++ b/code/game/objects/structures/fence.dm
@@ -120,7 +120,7 @@
open = TRUE
density = TRUE
-/obj/structure/fence/door/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/fence/door/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(can_open(user))
toggle(user)
diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm
index de88372b1e..412730910f 100644
--- a/code/game/objects/structures/fireaxe.dm
+++ b/code/game/objects/structures/fireaxe.dm
@@ -105,10 +105,7 @@
fireaxe = null
qdel(src)
-/obj/structure/fireaxecabinet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/fireaxecabinet/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(open || broken)
if(fireaxe)
user.put_in_hands(fireaxe)
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 6d72bb58b2..b587e57c3a 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -65,7 +65,7 @@
var/gift_type = /obj/item/a_gift/anything
var/list/ckeys_that_took = list()
-/obj/structure/flora/tree/pine/xmas/presents/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/flora/tree/pine/xmas/presents/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
diff --git a/code/game/objects/structures/fluff.dm b/code/game/objects/structures/fluff.dm
index 1dcda6eb50..bd7ddb36d5 100644
--- a/code/game/objects/structures/fluff.dm
+++ b/code/game/objects/structures/fluff.dm
@@ -110,7 +110,7 @@
desc = "Space Jesus is my copilot."
icon_state = "driverseat"
-/obj/structure/fluff/bus/passable/seat/driver/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/fluff/bus/passable/seat/driver/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
playsound(src, 'sound/items/carhorn.ogg', 50, 1)
. = ..()
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 03bcdde57c..4d500837d9 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -186,10 +186,7 @@
else
new_spawn.mind.assigned_role = "Free Golem"
-/obj/effect/mob_spawn/human/golem/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/effect/mob_spawn/human/golem/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(isgolem(user) && can_transfer)
var/transfer_choice = alert("Transfer your soul to [src]? (Warning, your old body will die!)",,"Yes","No")
if(transfer_choice != "Yes" || QDELETED(src) || uses <= 0 || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERY, NO_TK))
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index efd1b486d0..36e4f825da 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -10,6 +10,8 @@
layer = BELOW_OBJ_LAYER
armor = list("melee" = 50, "bullet" = 70, "laser" = 70, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
max_integrity = 50
+ attack_hand_is_action = TRUE
+ attack_hand_speed = 8
integrity_failure = 0.4
var/rods_type = /obj/item/stack/rods
var/rods_amount = 2
@@ -99,11 +101,10 @@
..(user, 1)
return TRUE
-/obj/structure/grille/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/grille/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
- user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src, ATTACK_EFFECT_KICK)
user.visible_message("[user] hits [src].", null, null, COMBAT_MESSAGE_RANGE)
log_combat(user, src, "hit")
@@ -111,8 +112,9 @@
take_damage(rand(5,10), BRUTE, "melee", 1)
/obj/structure/grille/attack_alien(mob/living/user)
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
user.do_attack_animation(src)
- user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] mangles [src].", null, null, COMBAT_MESSAGE_RANGE)
if(!shock(user, 70))
take_damage(20, BRUTE, "melee", 1)
@@ -134,7 +136,7 @@
. = . || (mover.pass_flags & PASSGRILLE)
/obj/structure/grille/attackby(obj/item/W, mob/user, params)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
add_fingerprint(user)
if(istype(W, /obj/item/wirecutters))
if(!shock(user, 100))
diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm
index a335906744..4773c07657 100644
--- a/code/game/objects/structures/guillotine.dm
+++ b/code/game/objects/structures/guillotine.dm
@@ -51,7 +51,7 @@
if (LAZYLEN(buckled_mobs))
. += "Someone appears to be strapped in. You can help them out, or you can harm them by activating the guillotine."
-/obj/structure/guillotine/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/guillotine/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
// Currently being used by something
@@ -108,7 +108,7 @@
if (QDELETED(head))
return
- playsound(src, 'sound/weapons/bladeslice.ogg', 100, 1)
+ playsound(src, 'sound/weapons/guillotine.ogg', 100, TRUE)
if (blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP || head.brute_dam >= 100)
head.dismember()
log_combat(user, H, "beheaded", src)
diff --git a/code/game/objects/structures/guncase.dm b/code/game/objects/structures/guncase.dm
index 1cab600fb1..e7ff9d4abf 100644
--- a/code/game/objects/structures/guncase.dm
+++ b/code/game/objects/structures/guncase.dm
@@ -53,10 +53,7 @@
else
return ..()
-/obj/structure/guncase/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/guncase/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(iscyborg(user) || isalien(user))
return
if(contents.len && open)
diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm
index 7a67387a8e..6aed11701d 100644
--- a/code/game/objects/structures/headpike.dm
+++ b/code/game/objects/structures/headpike.dm
@@ -37,10 +37,7 @@
MA.pixel_y = 12
. += H
-/obj/structure/headpike/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/headpike/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
to_chat(user, "You take down [src].")
if(victim)
victim.forceMove(drop_location())
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index 844c2ff8fd..dc5355e9d8 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -25,12 +25,12 @@
projector = null
return ..()
-/obj/structure/holosign/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/holosign/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
take_damage(5 , BRUTE, "melee", 1)
/obj/structure/holosign/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
@@ -162,7 +162,7 @@
return TRUE //nice or benign diseases!
return TRUE
-/obj/structure/holosign/barrier/medical/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/holosign/barrier/medical/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(CanPass(user) && user.a_intent == INTENT_HELP)
force_allaccess = !force_allaccess
to_chat(user, "You [force_allaccess ? "deactivate" : "activate"] the biometric scanners.") //warning spans because you can make the station sick!
@@ -182,7 +182,7 @@
/obj/structure/holosign/barrier/cyborg/hacked/proc/cooldown()
shockcd = FALSE
-/obj/structure/holosign/barrier/cyborg/hacked/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/holosign/barrier/cyborg/hacked/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index 72487ddc16..10a9f2afd4 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -91,10 +91,7 @@
else
return ..()
-/obj/structure/janitorialcart/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/janitorialcart/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
var/list/items = list()
if(mybag)
diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index 5706f79192..a23dd3a21e 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -60,8 +60,7 @@
deconstruct(TRUE)
return TRUE
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/structure/kitchenspike/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/kitchenspike/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(VIABLE_MOB_CHECK(user.pulling) && user.a_intent == INTENT_GRAB && !has_buckled_mobs())
var/mob/living/L = user.pulling
if(HAS_TRAIT(user, TRAIT_PACIFISM) && L.stat != DEAD)
diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm
index 6037183cc9..e844461952 100644
--- a/code/game/objects/structures/ladders.dm
+++ b/code/game/objects/structures/ladders.dm
@@ -122,10 +122,7 @@
return FALSE
return TRUE
-/obj/structure/ladder/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/ladder/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
use(user)
/obj/structure/ladder/attack_paw(mob/user)
diff --git a/code/game/objects/structures/life_candle.dm b/code/game/objects/structures/life_candle.dm
index ddd334a9e4..52986a44d7 100644
--- a/code/game/objects/structures/life_candle.dm
+++ b/code/game/objects/structures/life_candle.dm
@@ -24,10 +24,7 @@
var/respawn_time = 50
var/respawn_sound = 'sound/magic/staff_animation.ogg'
-/obj/structure/life_candle/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/life_candle/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!user.mind)
return
if(user.mind in linked_minds)
@@ -38,7 +35,7 @@
linked_minds |= user.mind
update_icon()
- float(linked_minds.len)
+ INVOKE_ASYNC(src, /atom/movable.proc/float, linked_minds.len)
if(linked_minds.len)
START_PROCESSING(SSobj, src)
set_light(lit_luminosity)
diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm
index 79489e4ae6..e8fbafa42b 100644
--- a/code/game/objects/structures/manned_turret.dm
+++ b/code/game/objects/structures/manned_turret.dm
@@ -198,10 +198,6 @@
/obj/item/gun_control/CanItemAutoclick()
return TRUE
-/obj/item/gun_control/attack_obj(obj/O, mob/living/user)
- user.changeNext_move(CLICK_CD_MELEE)
- O.attacked_by(src, user)
-
/obj/item/gun_control/attack(mob/living/M, mob/living/user)
M.lastattacker = user.real_name
M.lastattackerckey = user.ckey
diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index cca41b4e11..b2f1de8750 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -50,10 +50,7 @@
/obj/structure/mineral_door/attack_paw(mob/user)
return attack_hand(user)
-/obj/structure/mineral_door/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/mineral_door/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
return TryToSwitchState(user)
/obj/structure/mineral_door/CanPass(atom/movable/mover, turf/target)
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index b1829054ce..237cfdbf0b 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -15,10 +15,7 @@
if(icon_state == "mirror_broke" && !broken)
obj_break(null, mapload)
-/obj/structure/mirror/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/mirror/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(broken || !Adjacent(user))
return
@@ -118,10 +115,7 @@
choosable_races += S.id
..()
-/obj/structure/mirror/magic/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/mirror/magic/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!ishuman(user))
return
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 9639ffae51..82ca59161c 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -22,7 +22,8 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
anchored = TRUE
max_integrity = 400
- var/obj/structure/tray/connected = null
+ var/obj/structure/tray/connected
+ var/starting_tray
var/locked = FALSE
dir = SOUTH
var/message_cooldown
@@ -30,6 +31,9 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
/obj/structure/bodycontainer/Initialize()
. = ..()
+ if(starting_tray)
+ connected = new starting_tray(src)
+ connected.connected = src
GLOB.bodycontainers += src
recursive_organ_check(src)
@@ -37,8 +41,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
GLOB.bodycontainers -= src
open()
if(connected)
- qdel(connected)
- connected = null
+ QDEL_NULL(connected)
return ..()
/obj/structure/bodycontainer/on_log(login)
@@ -58,10 +61,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
/obj/structure/bodycontainer/attack_paw(mob/user)
return attack_hand(user)
-/obj/structure/bodycontainer/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/bodycontainer/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(locked)
to_chat(user, "It's locked.")
return
@@ -106,8 +106,6 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
if(!locked)
open()
return
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message(null, \
"You lean on the back of [src] and start pushing the tray open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
@@ -150,15 +148,11 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
desc = "Used to keep bodies in until someone fetches them. Now includes a high-tech alert system."
icon_state = "morgue1"
dir = EAST
+ starting_tray = /obj/structure/tray/m_tray
var/beeper = TRUE
var/beep_cooldown = 50
var/next_beep = 0
-/obj/structure/bodycontainer/morgue/New()
- connected = new/obj/structure/tray/m_tray(src)
- connected.connected = src
- ..()
-
/obj/structure/bodycontainer/morgue/examine(mob/user)
. = ..()
. += "The speaker is [beeper ? "enabled" : "disabled"]. Alt-click to toggle it."
@@ -208,6 +202,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
desc = "A human incinerator. Works well on barbecue nights."
icon_state = "crema1"
dir = SOUTH
+ starting_tray = /obj/structure/tray/c_tray
var/id = 1
/obj/structure/bodycontainer/crematorium/attack_robot(mob/user) //Borgs can't use crematoriums without help
@@ -218,17 +213,9 @@ GLOBAL_LIST_EMPTY(crematoriums)
GLOB.crematoriums.Remove(src)
return ..()
-/obj/structure/bodycontainer/crematorium/New()
- connected = new/obj/structure/tray/c_tray(src)
- connected.connected = src
-
- GLOB.crematoriums.Add(src)
- ..()
-
/obj/structure/bodycontainer/crematorium/Initialize()
. = ..()
- connected = new /obj/structure/tray/c_tray(src)
- connected.connected = src
+ GLOB.crematoriums.Add(src)
/obj/structure/bodycontainer/crematorium/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
id = "[idnum][id]"
@@ -330,10 +317,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
/obj/structure/tray/attack_paw(mob/user)
return attack_hand(user)
-/obj/structure/tray/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/tray/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if (src.connected)
connected.close()
add_fingerprint(user)
diff --git a/code/game/objects/structures/spirit_board.dm b/code/game/objects/structures/spirit_board.dm
index 3a415b84a9..1b3093e4e7 100644
--- a/code/game/objects/structures/spirit_board.dm
+++ b/code/game/objects/structures/spirit_board.dm
@@ -14,10 +14,7 @@
desc = "[initial(desc)] The planchette is sitting at \"[planchette]\"."
return ..()
-/obj/structure/spirit_board/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/spirit_board/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
spirit_board_pick_letter(user)
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index 1d7ba1d993..f8b54d04b6 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -74,7 +74,7 @@
radiate()
..()
-/obj/structure/statue/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/statue/uranium/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
radiate()
. = ..()
@@ -240,7 +240,7 @@
honk()
return ..()
-/obj/structure/statue/bananium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/statue/bananium/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
honk()
. = ..()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 589b21c6d4..a553e63b0f 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -23,6 +23,8 @@
climbable = TRUE
obj_flags = CAN_BE_HIT|SHOVABLE_ONTO
pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.")
+ attack_hand_speed = CLICK_CD_MELEE
+ attack_hand_is_action = TRUE
var/frame = /obj/structure/table_frame
var/framestack = /obj/item/stack/rods
var/buildstack = /obj/item/stack/sheet/metal
@@ -60,7 +62,7 @@
/obj/structure/table/attack_paw(mob/user)
return attack_hand(user)
-/obj/structure/table/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/table/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(Adjacent(user) && user.pulling)
if(isliving(user.pulling))
var/mob/living/pushed_mob = user.pulling
@@ -71,7 +73,10 @@
if(user.grab_state < GRAB_AGGRESSIVE)
to_chat(user, "You need a better grip to do that!")
return
- tablepush(user, pushed_mob)
+ if(user.grab_state >= GRAB_NECK)
+ tablelimbsmash(user, pushed_mob)
+ else
+ tablepush(user, pushed_mob)
if(user.a_intent == INTENT_HELP)
pushed_mob.visible_message("[user] begins to place [pushed_mob] onto [src]...", \
"[user] begins to place [pushed_mob] onto [src]...")
@@ -138,6 +143,22 @@
H.emote("nya")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table)
+/obj/structure/table/proc/tablelimbsmash(mob/living/user, mob/living/pushed_mob)
+ pushed_mob.Knockdown(30)
+ var/obj/item/bodypart/banged_limb = pushed_mob.get_bodypart(user.zone_selected) || pushed_mob.get_bodypart(BODY_ZONE_HEAD)
+ var/extra_wound = 0
+ if(HAS_TRAIT(user, TRAIT_HULK))
+ extra_wound = 20
+ banged_limb.receive_damage(30, wound_bonus = extra_wound)
+ pushed_mob.apply_damage(60, STAMINA)
+ take_damage(50)
+
+ playsound(pushed_mob, 'sound/effects/bang.ogg', 90, TRUE)
+ pushed_mob.visible_message("[user] smashes [pushed_mob]'s [banged_limb.name] against \the [src]!",
+ "[user] smashes your [banged_limb.name] against \the [src]")
+ log_combat(user, pushed_mob, "head slammed", null, "against [src]")
+ SEND_SIGNAL(pushed_mob, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table_limbsmash, banged_limb)
+
/obj/structure/table/shove_act(mob/living/target, mob/living/user)
if(CHECK_MOBILITY(target, MOBILITY_STAND))
target.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_TABLE)
@@ -191,8 +212,10 @@
return
/obj/structure/table/alt_attack_hand(mob/user)
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
+ user.DelayNextAction()
if(user && Adjacent(user) && !user.incapacitated())
- 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)
@@ -553,7 +576,7 @@
change_construction_value(-2)
return ..()
-/obj/structure/table/reinforced/brass/tablepush(mob/living/user, mob/living/pushed_mob)
+/obj/structure/table/reinforced/brass/tablelimbsmash(mob/living/user, mob/living/pushed_mob)
.= ..()
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 50, TRUE)
@@ -577,7 +600,7 @@
buildstack = /obj/item/stack/tile/bronze
canSmoothWith = list(/obj/structure/table/reinforced/brass, /obj/structure/table/bronze)
-/obj/structure/table/bronze/tablepush(mob/living/user, mob/living/pushed_mob)
+/obj/structure/table/bronze/tablelimbsmash(mob/living/user, mob/living/pushed_mob)
..()
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 50, TRUE)
@@ -606,7 +629,7 @@
computer.table = src
break
-/obj/structure/table/optable/tablepush(mob/living/user, mob/living/pushed_mob)
+/obj/structure/table/optable/tablelimbsmash(mob/living/user, mob/living/pushed_mob)
pushed_mob.forceMove(loc)
pushed_mob.set_resting(TRUE, TRUE)
visible_message("[user] has laid [pushed_mob] on [src].")
@@ -635,6 +658,8 @@
anchored = TRUE
pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.
max_integrity = 20
+ attack_hand_speed = CLICK_CD_MELEE
+ attack_hand_is_action = TRUE
/obj/structure/rack/examine(mob/user)
. = ..()
@@ -676,13 +701,12 @@
/obj/structure/rack/attack_paw(mob/living/user)
attack_hand(user)
-/obj/structure/rack/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/rack/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
if(CHECK_MULTIPLE_BITFIELDS(user.mobility_flags, MOBILITY_STAND|MOBILITY_MOVE) || user.get_num_legs() < 2)
return
- user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src, ATTACK_EFFECT_KICK)
user.visible_message("[user] kicks [src].", null, null, COMBAT_MESSAGE_RANGE)
take_damage(rand(4,8), BRUTE, "melee", 1)
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index e2298ac6c5..2a441ff0f2 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -67,15 +67,14 @@
to_chat(user, "You put [I] in [src].")
update_icon()
-/obj/structure/tank_dispenser/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)
- if(!ui)
- ui = new(user, src, ui_key, "TankDispenser", name, 275, 103, master_ui, state)
- ui.open()
+/obj/structure/tank_dispenser/ui_state(mob/user)
+ return GLOB.physical_state
-/obj/structure/tank_dispenser/attack_robot(mob/user)
- ui_interact(user)
+/obj/structure/tank_dispenser/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "TankDispenser", name)
+ ui.open()
/obj/structure/tank_dispenser/ui_data(mob/user)
var/list/data = list()
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index a08d5c95c1..c5f3a089f7 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -48,10 +48,7 @@
handle_density()
to_chat(user, "You slide the target into the stake.")
-/obj/structure/target_stake/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/target_stake/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(pinned_target)
removeTarget(user)
diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm
index 7f597857d9..3a5eb135f4 100644
--- a/code/game/objects/structures/transit_tubes/station.dm
+++ b/code/game/objects/structures/transit_tubes/station.dm
@@ -58,10 +58,7 @@
qdel(R)
-/obj/structure/transit_tube/station/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/transit_tube/station/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!pod_moving)
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
if(open_status == STATION_TUBE_OPEN)
diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
index 36539ae1e4..cf68341b2c 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
@@ -69,8 +69,6 @@
empty_pod()
return
if(!moving)
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
to_chat(user, "You start trying to escape from the pod...")
if(do_after(user, 600, target = src))
to_chat(user, "You manage to open the pod.")
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 3dacd49fc9..c52249686a 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -13,6 +13,8 @@
var/mob/living/swirlie = null //the mob being given a swirlie
var/buildstacktype = /obj/item/stack/sheet/metal //they're metal now, shut up
var/buildstackamount = 1
+ attack_hand_speed = CLICK_CD_MELEE
+ attack_hand_is_action = TRUE
/obj/structure/toilet/Initialize()
. = ..()
@@ -26,18 +28,16 @@
AM.forceMove(loc)
return ..()
-/obj/structure/toilet/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/toilet/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
if(swirlie)
- user.changeNext_move(CLICK_CD_MELEE)
playsound(src.loc, "swing_hit", 25, 1)
swirlie.visible_message("[user] slams the toilet seat onto [swirlie]'s head!", "[user] slams the toilet seat onto your head!", "You hear reverberating porcelain.")
swirlie.adjustBruteLoss(5)
else if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
- user.changeNext_move(CLICK_CD_MELEE)
var/mob/living/GM = user.pulling
if(user.grab_state >= GRAB_AGGRESSIVE)
if(GM.loc != get_turf(src))
@@ -167,6 +167,8 @@
icon_state = "urinal"
density = FALSE
anchored = TRUE
+ attack_hand_speed = CLICK_CD_MELEE
+ attack_hand_is_action = TRUE
var/exposed = 0 // can you currently put an item inside
var/obj/item/hiddenitem = null // what's in the urinal
@@ -174,17 +176,13 @@
..()
hiddenitem = new /obj/item/reagent_containers/food/urinalcake
-/obj/structure/urinal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/urinal/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/GM = user.pulling
if(user.grab_state >= GRAB_AGGRESSIVE)
if(GM.loc != get_turf(src))
to_chat(user, "[GM.name] needs to be on [src].")
return
- user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] slams [GM] into [src]!", "You slam [GM] into [src]!")
GM.adjustBruteLoss(8)
else
@@ -492,7 +490,7 @@
var/buildstacktype = /obj/item/stack/sheet/metal
var/buildstackamount = 1
-/obj/structure/sink/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/sink/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
@@ -707,8 +705,7 @@
icon_state = "puddle"
resistance_flags = UNACIDABLE
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/structure/sink/puddle/attack_hand(mob/M)
+/obj/structure/sink/puddle/on_attack_hand(mob/M)
icon_state = "puddle-splash"
. = ..()
icon_state = "puddle"
@@ -784,10 +781,7 @@
return TRUE
-/obj/structure/curtain/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/curtain/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
playsound(loc, 'sound/effects/curtain.ogg', 50, 1)
toggle()
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 38655df39e..6aae4955f1 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -40,6 +40,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
rad_flags = RAD_PROTECT_CONTENTS
flags_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.4
+ attack_hand_speed = CLICK_CD_MELEE
+ attack_hand_is_action = TRUE
/// Electrochromatic status
var/electrochromatic_status = NOT_ELECTROCHROMATIC
@@ -157,7 +159,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
return 1
/obj/structure/window/attack_tk(mob/user)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
user.visible_message("Something knocks on [src].")
add_fingerprint(user)
playsound(src, 'sound/effects/Glassknock.ogg', 50, 1)
@@ -167,18 +169,15 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
return 1
. = ..()
-/obj/structure/window/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/window/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!can_be_reached(user))
return
- user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] knocks on [src].")
add_fingerprint(user)
playsound(src, 'sound/effects/Glassknock.ogg', 50, 1)
/obj/structure/window/attack_paw(mob/user)
+ user.DelayNextAction()
return attack_hand(user)
/obj/structure/window/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) //used by attack_alien, attack_animal, and attack_slime
@@ -836,13 +835,9 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
for (var/i in 1 to rand(1,4))
. += new /obj/item/paper/natural(location)
-/obj/structure/window/paperframe/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/window/paperframe/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
if(user.a_intent != INTENT_HARM)
- user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] knocks on [src].")
playsound(src, "pageturn", 50, 1)
else
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index bdca384bd0..758f824727 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -162,7 +162,7 @@
return 0
/turf/open/floor/crowbar_act(mob/living/user, obj/item/I)
- return intact ? pry_tile(I, user) : FALSE
+ return intact ? FORCE_BOOLEAN(pry_tile(I, user)) : FALSE
/turf/open/floor/proc/try_replace_tile(obj/item/stack/tile/T, mob/user, params)
if(T.turf_type == type)
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index f940761ff8..946401ba18 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -26,7 +26,8 @@
/turf/open/floor/wood/screwdriver_act(mob/living/user, obj/item/I)
if(..())
return TRUE
- return pry_tile(I, user)
+ . = STOP_ATTACK_PROC_CHAIN
+ pry_tile(I, user)
/turf/open/floor/wood/try_replace_tile(obj/item/stack/tile/T, mob/user, params)
if(T.turf_type == type)
diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm
index 4f7aa9e492..4bca25f96c 100644
--- a/code/game/turfs/simulated/floor/light_floor.dm
+++ b/code/game/turfs/simulated/floor/light_floor.dm
@@ -52,10 +52,7 @@
set_light(0)
return ..()
-/turf/open/floor/light/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/turf/open/floor/light/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!can_modify_colour)
return
if(!on)
diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm
index 9a227d2594..8e0230a2b0 100644
--- a/code/game/turfs/simulated/floor/mineral_floor.dm
+++ b/code/game/turfs/simulated/floor/mineral_floor.dm
@@ -149,7 +149,7 @@
if(!.)
honk()
-/turf/open/floor/mineral/bananium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/turf/open/floor/mineral/bananium/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
.=..()
if(!.)
honk()
@@ -202,7 +202,7 @@
if(!.)
radiate()
-/turf/open/floor/mineral/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/turf/open/floor/mineral/uranium/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
.=..()
if(!.)
radiate()
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index f26a4b827a..ac80bddd00 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -124,7 +124,7 @@
ChangeTurf(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
else
playsound(src, 'sound/weapons/tap.ogg', 100, TRUE) //The attack sound is muffled by the foam itself
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
user.do_attack_animation(src)
if(prob(I.force * 20 - 25))
user.visible_message("[user] smashes through [src]!", \
diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm
index b050d8fb89..03045674e4 100644
--- a/code/game/turfs/simulated/floor/reinf_floor.dm
+++ b/code/game/turfs/simulated/floor/reinf_floor.dm
@@ -89,10 +89,7 @@
/turf/open/floor/engine/attack_paw(mob/user)
return attack_hand(user)
-/turf/open/floor/engine/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/turf/open/floor/engine/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
user.Move_Pulled(src)
//air filled floors; used in atmos pressure chambers
diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm
index c8afe628db..4466511acd 100644
--- a/code/game/turfs/simulated/wall/mineral_walls.dm
+++ b/code/game/turfs/simulated/wall/mineral_walls.dm
@@ -72,7 +72,7 @@
return
return
-/turf/closed/wall/mineral/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/turf/closed/wall/mineral/uranium/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
radiate()
. = ..()
diff --git a/code/game/turfs/simulated/wall/reinf_walls.dm b/code/game/turfs/simulated/wall/reinf_walls.dm
index a1d2c1757c..6b41f41763 100644
--- a/code/game/turfs/simulated/wall/reinf_walls.dm
+++ b/code/game/turfs/simulated/wall/reinf_walls.dm
@@ -36,7 +36,8 @@
new /obj/item/stack/sheet/metal(src, 2)
/turf/closed/wall/r_wall/attack_animal(mob/living/simple_animal/M)
- M.changeNext_move(CLICK_CD_MELEE)
+ if(!M.CheckActionCooldown())
+ return
M.do_attack_animation(src)
if(!M.environment_smash)
return
@@ -46,6 +47,7 @@
else
playsound(src, 'sound/effects/bang.ogg', 50, 1)
to_chat(M, "This wall is far too strong for you to destroy.")
+ M.DelayNextAction()
/turf/closed/wall/r_wall/try_destroy(obj/item/I, mob/user, turf/T)
if(istype(I, /obj/item/pickaxe/drill/jackhammer))
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index df63cf93e6..0623f2b9d2 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -9,6 +9,8 @@
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall
+ attack_hand_speed = 8
+ attack_hand_is_action = TRUE
baseturfs = /turf/open/floor/plating
@@ -113,41 +115,65 @@
return FALSE
/turf/closed/wall/attack_paw(mob/living/user)
- user.changeNext_move(CLICK_CD_MELEE)
return attack_hand(user)
-
/turf/closed/wall/attack_animal(mob/living/simple_animal/M)
- M.changeNext_move(CLICK_CD_MELEE)
+ if(!M.CheckActionCooldown(CLICK_CD_MELEE))
+ return
+ M.DelayNextAction()
M.do_attack_animation(src)
if((M.environment_smash & ENVIRONMENT_SMASH_WALLS) || (M.environment_smash & ENVIRONMENT_SMASH_RWALLS))
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
dismantle_wall(1)
return
-/turf/closed/wall/attack_hulk(mob/user, does_attack_animation = 0)
- ..(user, 1)
+/turf/closed/wall/attack_hulk(mob/living/carbon/user)
+ ..()
+ var/obj/item/bodypart/arm = user.hand_bodyparts[user.active_hand_index]
+ if(!arm)
+ return
+ if(arm.disabled)
+ return
if(prob(hardness))
- playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
+ playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
+ hulk_recoil(arm, user)
dismantle_wall(1)
+
else
- playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ playsound(src, 'sound/effects/bang.ogg', 50, TRUE)
add_dent(WALL_DENT_HIT)
- to_chat(user, text("You punch the wall."))
+ user.visible_message("[user] smashes \the [src]!", \
+ "You smash \the [src]!", \
+ "You hear a booming smash!")
return TRUE
-/turf/closed/wall/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
+/**
+ *Deals damage back to the hulk's arm.
+ *
+ *When a hulk manages to break a wall using their hulk smash, this deals back damage to the arm used.
+ *This is in its own proc just to be easily overridden by other wall types. Default allows for three
+ *smashed walls per arm. Also, we use CANT_WOUND here because wounds are random. Wounds are applied
+ *by hulk code based on arm damage and checked when we call break_an_arm().
+ *Arguments:
+ **arg1 is the arm to deal damage to.
+ **arg2 is the hulk
+ */
+/turf/closed/wall/proc/hulk_recoil(obj/item/bodypart/arm, mob/living/carbon/human/hulkman, var/damage = 20)
+ arm.receive_damage(brute = damage, blocked = 0, wound_bonus = CANT_WOUND)
+ var/datum/mutation/human/hulk/smasher = locate(/datum/mutation/human/hulk) in hulkman.dna.mutations
+ if(!smasher || !damage) //sanity check but also snow and wood walls deal no recoil damage, so no arm breaky
return
- user.changeNext_move(CLICK_CD_MELEE)
+ smasher.break_an_arm(arm)
+
+/turf/closed/wall/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
to_chat(user, "You push the wall but nothing happens!")
playsound(src, 'sound/weapons/genhit.ogg', 25, 1)
add_fingerprint(user)
/turf/closed/wall/attackby(obj/item/W, mob/user, params)
- user.changeNext_move(CLICK_CD_MELEE)
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
if (!user.IsAdvancedToolUser())
to_chat(user, "You don't have the dexterity to do this!")
return
@@ -156,6 +182,7 @@
if(!isturf(user.loc))
return //can't do this stuff whilst inside objects and such
+ user.DelayNextAction()
add_fingerprint(user)
var/turf/T = user.loc //get user's location for delay checks
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 02c12a9744..55d945535d 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -122,10 +122,7 @@
requires_activation = FALSE
..()
-/turf/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/turf/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
user.Move_Pulled(src)
/turf/proc/multiz_turf_del(turf/T, dir)
diff --git a/code/modules/NTNet/relays.dm b/code/modules/NTNet/relays.dm
index 2101a72960..8c33dd1eba 100644
--- a/code/modules/NTNet/relays.dm
+++ b/code/modules/NTNet/relays.dm
@@ -9,8 +9,6 @@
icon_state = "bus"
density = TRUE
circuit = /obj/item/circuitboard/machine/ntnet_relay
- ui_x = 400
- ui_y = 300
var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame.
var/enabled = 1 // Set to 0 if the relay was turned off
@@ -64,15 +62,12 @@
SSnetworks.station_network.add_log("Quantum relay switched from overload recovery mode to normal operation mode.")
..()
-/obj/machinery/ntnet_relay/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)
-
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
-
+/obj/machinery/ntnet_relay/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "NtnetRelay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "NtnetRelay")
ui.open()
-
/obj/machinery/ntnet_relay/ui_data(mob/user)
var/list/data = list()
data["enabled"] = enabled
@@ -81,7 +76,6 @@
data["dos_crashed"] = dos_failure
return data
-
/obj/machinery/ntnet_relay/ui_act(action, params)
if(..())
return
@@ -118,4 +112,4 @@
D.target = null
D.error = "Connection to quantum relay severed"
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm
index 9953fe4bc5..cc59fe10ab 100644
--- a/code/modules/VR/vr_sleeper.dm
+++ b/code/modules/VR/vr_sleeper.dm
@@ -78,10 +78,15 @@
close_machine(target)
ui_interact(user)
-/obj/machinery/vr_sleeper/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_contained_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/vr_sleeper/ui_state(mob/user)
+ if(user == occupant)
+ return GLOB.contained_state
+ return GLOB.default_state
+
+/obj/machinery/vr_sleeper/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "VrSleeper", "VR Sleeper", 475, 340, master_ui, state)
+ ui = new(user, src, "VrSleeper", "VR Sleeper")
ui.open()
/obj/machinery/vr_sleeper/ui_act(action, params)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index a2e2b3c122..8cfae3820a 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -40,6 +40,11 @@
if(M.client)
body += " \[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]"
+ body += "
CentCom Galactic Ban DB: "
+ if(CONFIG_GET(string/centcom_ban_db))
+ body += "Search"
+ else
+ body += "Disabled"
body += "
Show related accounts by: "
body += "\[ CID | "
body += "IP \]"
diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm
index 7664d85b7d..bab74300f5 100644
--- a/code/modules/admin/chat_commands.dm
+++ b/code/modules/admin/chat_commands.dm
@@ -150,7 +150,7 @@ GLOBAL_LIST(round_end_notifiees)
/datum/tgs_chat_command/wheelofsalt/Run(datum/tgs_chat_user/sender, params)
var/saltresult = "The wheel of salt [pick("clatters","screams","vibrates","clanks","resonates","groans","moans","squeaks","emits a[pick(" god-forsaken"," lewd"," creepy"," generic","n orgasmic"," demonic")] [pick("airhorn","bike horn","trumpet","clown","latex","vore","dog","laughing")] noise")] as it spins violently... And it seems the salt of the day is the "
- var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]"
+ var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin removal","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]"
var/saltsecondarysubject = "[pick("rework","changes","r34","ban","removal","addition","leak","proposal","fanart","introduction","tabling","ERP","bikeshedding","crossdressing","sprites","semen keg","argument","theft","nerf","screeching","salt","creampie","lewding","murder","kissing","marriage","replacement","fucking","ship","netflix adaptation","dance","remaster","system","voyeur","decoration","pre-order","bukkake","seduction","worship","gangbang","handholding")]"
if(prob(10))
saltresult += "@here for your salt, all day every day"
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 042a6e0fe9..13e8877440 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -863,7 +863,7 @@
if(jobban_isbanned(M, ROLE_TRAITOR) || isbanned_dept)
dat += "
"
+ for(var/list/ban in bans)
+ dat += "Server: [sanitize(ban["sourceName"])] "
+ dat += "RP Level: [sanitize(ban["sourceRoleplayLevel"])] "
+ dat += "Type: [sanitize(ban["type"])] "
+ dat += "Banned By: [sanitize(ban["bannedBy"])] "
+ dat += "Reason: [sanitize(ban["reason"])] "
+ dat += "Datetime: [sanitize(ban["bannedOn"])] "
+ var/expiration = ban["expires"]
+ dat += "Expires: [expiration ? "[sanitize(expiration)]" : "Permanent"] "
+ if(ban["type"] == "job")
+ dat += "Jobs: "
+ var/list/jobs = ban["jobs"]
+ dat += sanitize(jobs.Join(", "))
+ dat += " "
+ dat += ""
+
+ dat += " "
+ var/datum/browser/popup = new(usr, "centcomlookup-[ckey]", "
Central Command Galactic Ban Database
", 700, 600)
+ popup.set_content(dat.Join())
+ popup.open(0)
+
else if(href_list["modantagrep"])
if(!check_rights(R_ADMIN))
return
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 14cf0d7ee2..b93c8dabf1 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -371,8 +371,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
return
var/msg = "- AdminHelp marked as IC issue by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"]! - "
- msg += "Losing is part of the game! "
- msg += "It is also possible that your ahelp is unable to be answered properly, due to events occurring in the round."
+ msg += "Your ahelp is unable to be answered properly due to events occurring in the round. Your question probably has an IC answer, which means you should deal with it IC!"
if(initiator)
to_chat(initiator, msg)
diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm
index b3bea2201c..6f8e9e703f 100644
--- a/code/modules/admin/verbs/diagnostics.dm
+++ b/code/modules/admin/verbs/diagnostics.dm
@@ -22,37 +22,6 @@
show_air_status_to(target, usr)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Air Status") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-/client/proc/fix_next_move()
- set category = "Debug"
- set name = "Unfreeze Everyone"
- var/largest_move_time = 0
- var/largest_click_time = 0
- var/mob/largest_move_mob = null
- var/mob/largest_click_mob = null
- for(var/mob/M in world)
- if(!M.client)
- continue
- if(M.next_move >= largest_move_time)
- largest_move_mob = M
- if(M.next_move > world.time)
- largest_move_time = M.next_move - world.time
- else
- largest_move_time = 1
- if(M.next_click >= largest_click_time)
- largest_click_mob = M
- if(M.next_click > world.time)
- largest_click_time = M.next_click - world.time
- else
- largest_click_time = 0
- log_admin("DEBUG: [key_name(M)] next_move = [M.next_move] lastDblClick = [M.next_click] world.time = [world.time]")
- M.next_move = 1
- M.next_click = 0
- message_admins("[ADMIN_LOOKUPFLW(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [DisplayTimeText(largest_move_time)]!")
- message_admins("[ADMIN_LOOKUPFLW(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [DisplayTimeText(largest_click_time)]!")
- message_admins("world.time = [world.time]")
- SSblackbox.record_feedback("tally", "admin_verb", 1, "Unfreeze Everyone") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- return
-
/client/proc/radio_report()
set category = "Debug"
set name = "Radio report"
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 5027e8fe51..5997558c60 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -1280,8 +1280,12 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
ADMIN_PUNISHMENT_SUPPLYPOD,
ADMIN_PUNISHMENT_MAZING,
ADMIN_PUNISHMENT_ROD,
+ ADMIN_PUNISHMENT_SHOES,
ADMIN_PUNISHMENT_PICKLE,
- ADMIN_PUNISHMENT_FRY)
+ ADMIN_PUNISHMENT_FRY,
+ ADMIN_PUNISHMENT_CRACK,
+ ADMIN_PUNISHMENT_BLEED,
+ ADMIN_PUNISHMENT_SCARIFY)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1359,13 +1363,122 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(amount)
A.reagents.add_reagent(chosen_id, amount)
A.splat(target)
+ if(ADMIN_PUNISHMENT_CRACK)
+ if(!iscarbon(target))
+ to_chat(usr,"This must be used on a carbon mob.", confidential = TRUE)
+ return
+ var/mob/living/carbon/C = target
+ for(var/i in C.bodyparts)
+ var/obj/item/bodypart/squish_part = i
+ var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate))
+ squish_part.force_wound_upwards(type_wound, smited=TRUE)
+ if(ADMIN_PUNISHMENT_BLEED)
+ if(!iscarbon(target))
+ to_chat(usr,"This must be used on a carbon mob.", confidential = TRUE)
+ return
+ var/mob/living/carbon/C = target
+ for(var/i in C.bodyparts)
+ var/obj/item/bodypart/slice_part = i
+ var/type_wound = pick(list(/datum/wound/slash/severe, /datum/wound/slash/moderate))
+ slice_part.force_wound_upwards(type_wound, smited=TRUE)
+ type_wound = pick(list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate))
+ slice_part.force_wound_upwards(type_wound, smited=TRUE)
+ type_wound = pick(list(/datum/wound/slash/critical, /datum/wound/slash/severe))
+ slice_part.force_wound_upwards(type_wound, smited=TRUE)
+ if(ADMIN_PUNISHMENT_SCARIFY)
+ if(!iscarbon(target))
+ to_chat(usr,"This must be used on a carbon mob.", confidential = TRUE)
+ return
+ var/mob/living/carbon/dude = target
+ dude.generate_fake_scars(rand(1, 4))
+ to_chat(dude, "You feel your body grow jaded and torn...")
+ if(ADMIN_PUNISHMENT_PERFORATE)
+ if(!iscarbon(target))
+ to_chat(usr,"This must be used on a carbon mob.", confidential = TRUE)
+ return
+
+ var/list/how_fucked_is_this_dude = list("A little", "A lot", "So fucking much", "FUCK THIS DUDE")
+ var/hatred = input("How much do you hate this guy?") in how_fucked_is_this_dude
+ var/repetitions
+ var/shots_per_limb_per_rep = 2
+ var/damage
+ switch(hatred)
+ if("A little")
+ repetitions = 1
+ damage = 5
+ if("A lot")
+ repetitions = 2
+
+ damage = 8
+ if("So fucking much")
+ repetitions = 3
+ damage = 10
+ if("FUCK THIS DUDE")
+ repetitions = 4
+ damage = 10
+
+ var/mob/living/carbon/dude = target
+ var/list/open_adj_turfs = get_adjacent_open_turfs(dude)
+ var/list/wound_bonuses = list(15, 70, 110, 250)
+
+ var/delay_per_shot = 1
+ var/delay_counter = 1
+
+ dude.Immobilize(5 SECONDS)
+ for(var/wound_bonus_rep in 1 to repetitions)
+ for(var/i in dude.bodyparts)
+ var/obj/item/bodypart/slice_part = i
+ var/shots_this_limb = 0
+ for(var/t in shuffle(open_adj_turfs))
+ var/turf/iter_turf = t
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/firing_squad, dude, iter_turf, slice_part.body_zone, wound_bonuses[wound_bonus_rep], damage), delay_counter)
+ delay_counter += delay_per_shot
+ shots_this_limb++
+ if(shots_this_limb > shots_per_limb_per_rep)
+ break
if(ADMIN_PUNISHMENT_PICKLE)
target.turn_into_pickle()
if(ADMIN_PUNISHMENT_FRY)
target.fry()
+ if(ADMIN_PUNISHMENT_SHOES)
+ if(!iscarbon(target))
+ to_chat(usr,"This must be used on a carbon mob.")
+ return
+ var/mob/living/carbon/C = target
+ var/obj/item/clothing/shoes/sick_kicks = C.shoes
+ if(!sick_kicks?.can_be_tied)
+ to_chat(usr,"[C] does not have knottable shoes!")
+ return
+ sick_kicks.adjust_laces(SHOES_KNOTTED)
+
punish_log(target, punishment)
+/**
+ * firing_squad is a proc for the :B:erforate smite to shoot each individual bullet at them, so that we can add actual delays without sleep() nonsense
+ *
+ * Hilariously, if you drag someone away mid smite, the bullets will still chase after them from the original spot, possibly hitting other people. Too funny to fix imo
+ *
+ * Arguments:
+ * * target- guy we're shooting obviously
+ * * source_turf- where the bullet begins, preferably on a turf next to the target
+ * * body_zone- which bodypart we're aiming for, if there is one there
+ * * wound_bonus- the wounding power we're assigning to the bullet, since we don't care about the base one
+ * * damage- the damage we're assigning to the bullet, since we don't care about the base one
+ */
+/proc/firing_squad(mob/living/carbon/target, turf/source_turf, body_zone, wound_bonus, damage)
+ if(!target.get_bodypart(body_zone))
+ return
+ playsound(target, 'sound/weapons/shot.ogg', 100)
+ var/obj/item/projectile/bullet/smite/divine_wrath = new(source_turf)
+ divine_wrath.damage = damage
+ divine_wrath.wound_bonus = wound_bonus
+ divine_wrath.original = target
+ divine_wrath.def_zone = body_zone
+ divine_wrath.spread = 0
+ divine_wrath.preparePixelProjectile(target, source_turf)
+ divine_wrath.fire()
+
/client/proc/punish_log(var/whom, var/punishment)
var/msg = "[key_name_admin(usr)] punished [key_name_admin(whom)] with [punishment]."
message_admins(msg)
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index b4fc5b5948..7eb7ec2af2 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -60,8 +60,10 @@
/datum/antagonist/abductor/greet()
to_chat(owner.current, "You are the [owner.special_role]!")
- to_chat(owner.current, "With the help of your teammate, kidnap and experiment on station crew members!")
- to_chat(owner.current, "Try not to disturb the habitat, it could lead to dead specimens.")
+ to_chat(owner.current, "You are an operative for your home planet's government. Your mission is to detain, experiment, and observe.")
+ to_chat(owner.current, "Work together with your teammate to bring live subjects from the space station nearby onto your ship for experimentation.")
+ to_chat(owner.current, "For the sake of the mission, do not damage the integrity of the station, do not kill anyone unless in self defense, always capture specimens first if you can, and do not steal equipment or belongings from abducted specimens.")
+ to_chat(owner.current, "Your task is to observe and take notes of the effects of your experiments.")
to_chat(owner.current, "[greet_text]")
owner.announce_objectives()
diff --git a/code/modules/antagonists/abductor/equipment/orderable_gear.dm b/code/modules/antagonists/abductor/equipment/orderable_gear.dm
new file mode 100644
index 0000000000..d15e450c99
--- /dev/null
+++ b/code/modules/antagonists/abductor/equipment/orderable_gear.dm
@@ -0,0 +1,79 @@
+GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
+
+/datum/abductor_gear
+ /// Name of the gear
+ var/name = "Generic Abductor Gear"
+ /// Description of the gear
+ var/description = "Generic description."
+ /// Unique ID of the gear
+ var/id = "abductor_generic"
+ /// Credit cost of the gear
+ var/cost = 1
+ /// Build path of the gear itself
+ var/build_path = null
+ /// Category of the gear
+ var/category = "Basic Gear"
+
+/datum/abductor_gear/agent_helmet
+ name = "Agent Helmet"
+ description = "Abduct with style - spiky style. Prevents digital tracking."
+ id = "agent_helmet"
+ build_path = /obj/item/clothing/head/helmet/abductor
+
+/datum/abductor_gear/agent_vest
+ name = "Agent Vest"
+ description = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth."
+ id = "agent_vest"
+ build_path = /obj/item/clothing/suit/armor/abductor/vest
+
+/datum/abductor_gear/radio_silencer
+ name = "Radio Silencer"
+ description = "A compact device used to shut down communications equipment."
+ id = "radio_silencer"
+ build_path = /obj/item/abductor/silencer
+
+/datum/abductor_gear/science_tool
+ name = "Science Tool"
+ description = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras."
+ id = "science_tool"
+ build_path = /obj/item/abductor/gizmo
+/*
+/datum/abductor_gear/advanced_baton
+ name = "Advanced Baton"
+ description = "A quad-mode baton used for incapacitation and restraining of specimens."
+ id = "advanced_baton"
+ cost = 2
+ build_path = /obj/item/melee/baton/abductor //does not exist?
+*/
+/datum/abductor_gear/superlingual_matrix
+ name = "Superlingual Matrix"
+ description = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something."
+ id = "superlingual_matrix"
+ build_path = /obj/item/organ/tongue/abductor
+ category = "Advanced Gear"
+
+/datum/abductor_gear/mental_interface
+ name = "Mental Interface Device"
+ description = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
+ or to send a command to a test subject with a charged gland."
+ id = "mental_interface"
+ cost = 2
+ build_path = /obj/item/abductor/mind_device
+ category = "Advanced Gear"
+
+/datum/abductor_gear/reagent_synthesizer
+ name = "Reagent Synthesizer"
+ description = "Synthesizes a variety of reagents using proto-matter."
+ id = "reagent_synthesizer"
+ cost = 2
+ build_path = /obj/item/abductor_machine_beacon/chem_dispenser
+ category = "Advanced Gear"
+
+/datum/abductor_gear/shrink_ray
+ name = "Shrink Ray Blaster"
+ description = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \
+ That or it's just space magic. Either way, it shrinks stuff."
+ id = "shrink_ray"
+ cost = 2
+ build_path = /obj/item/gun/energy/shrink_ray
+ category = "Advanced Gear"
diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm
index 9c9715ee43..f06f4fe68a 100644
--- a/code/modules/antagonists/abductor/machinery/console.dm
+++ b/code/modules/antagonists/abductor/machinery/console.dm
@@ -23,102 +23,105 @@
var/obj/machinery/abductor/pad/pad
var/obj/machinery/computer/camera_advanced/abductor/camera
var/list/datum/icon_snapshot/disguises = list()
+ /// Currently selected gear category
+ var/selected_cat
+ /// Dictates if the compact mode of the interface is on or off
+ var/compact_mode = FALSE
+ /// Possible gear to be dispensed
+ var/list/possible_gear
-/obj/machinery/abductor/console/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/machinery/abductor/console/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) && !HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
to_chat(user, "You start mashing alien buttons at random!")
if(do_after(user,100, target = src))
TeleporterSend()
- return
- user.set_machine(src)
- var/dat = ""
- dat += "
Abductsoft 3000
"
+/obj/machinery/abductor/console/ui_status(mob/user)
+ if(!isabductor(user) && !isobserver(user))
+ return UI_CLOSE
+ return ..()
+
+/obj/machinery/abductor/console/ui_state(mob/user)
+ return GLOB.physical_state
+
+/obj/machinery/abductor/console/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AbductorConsole", name)
+ ui.open()
+
+/obj/machinery/abductor/console/ui_static_data(mob/user)
+ var/list/data = list()
+ data["categories"] = list()
+ for(var/category in possible_gear)
+ var/list/cat = list(
+ "name" = category,
+ "items" = (category == selected_cat ? list() : null))
+ for(var/gear in possible_gear[category])
+ var/datum/abductor_gear/AG = possible_gear[category][gear]
+ cat["items"] += list(list(
+ "name" = AG.name,
+ "cost" = AG.cost,
+ "desc" = AG.description,
+ ))
+ data["categories"] += list(cat)
+ return data
+
+/obj/machinery/abductor/console/ui_data(mob/user)
+ var/list/data = list()
+ data["compactMode"] = compact_mode
+ data["experiment"] = experiment ? TRUE : FALSE
if(experiment)
- var/points = experiment.points
- var/credits = experiment.credits
- dat += "Collected Samples : [points] "
- dat += "Gear Credits: [credits] "
- dat += "Transfer data in exchange for supplies: "
- dat += "Advanced Baton (2 Credits) "
- dat += "Mental Interface Device (2 Credits) "
- dat += "Reagent Synthesizer (2 Credits) "
- dat += "Agent Helmet (1 Credit) "
- dat += "Agent Vest (1 Credit) "
- dat += "Radio Silencer (1 Credit) "
- dat += "Science Tool (1 Credit) "
- dat += "Superlingual Matrix (1 Credit) "
- else
- dat += "NO EXPERIMENT MACHINE DETECTED "
-
+ data["points"] = experiment.points
+ data["credits"] = experiment.credits
+ data["pad"] = pad ? TRUE : FALSE
if(pad)
- dat += "Emergency Teleporter System."
- dat += "Consider using primary observation console first."
- dat += "Activate Teleporter "
- if(gizmo && gizmo.marked)
- dat += "Retrieve Mark "
- else
- dat += "Retrieve Mark "
- else
- dat += "NO TELEPAD DETECTED"
-
+ data["gizmo"] = gizmo && gizmo.marked ? TRUE : FALSE
+ data["vest"] = vest ? TRUE : FALSE
if(vest)
- dat += "
"
- dat = dat.Join()
- var/datum/browser/popup = new(user, "bounties", "Nanotrasen Bounties", 700, 600)
- popup.set_content(dat)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
- popup.open()
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "CargoBountyConsole", name)
+ ui.open()
-/obj/machinery/computer/bounty/Topic(href, href_list)
+/obj/machinery/computer/bounty/ui_data(mob/user)
+ var/list/data = list()
+ var/list/bountyinfo = list()
+ for(var/datum/bounty/B in GLOB.bounties_list)
+ bountyinfo += list(list("name" = B.name, "description" = B.description, "reward_string" = B.reward_string(), "completion_string" = B.completion_string() , "claimed" = B.claimed, "can_claim" = B.can_claim(), "priority" = B.high_priority, "bounty_ref" = REF(B)))
+ data["stored_cash"] = cargocash.account_balance
+ data["bountydata"] = bountyinfo
+ return data
+
+/obj/machinery/computer/bounty/ui_act(action,params)
if(..())
return
-
- switch(href_list["choice"])
+ switch(action)
+ if("ClaimBounty")
+ var/datum/bounty/cashmoney = locate(params["bounty"]) in GLOB.bounties_list
+ if(cashmoney)
+ cashmoney.claim()
+ return TRUE
if("Print")
if(printer_ready < world.time)
printer_ready = world.time + PRINTER_TIMEOUT
print_paper()
-
- if("Claim")
- var/datum/bounty/B = locate(href_list["d_rec"])
- if(B in GLOB.bounties_list)
- B.claim()
-
- if(href_list["refresh"])
- playsound(src, "terminal_type", 25, 0)
-
- updateUsrDialog()
+ return
diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm
index f33ea7059b..b7eac1e591 100644
--- a/code/modules/cargo/centcom_podlauncher.dm
+++ b/code/modules/cargo/centcom_podlauncher.dm
@@ -11,7 +11,7 @@
/client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui
set name = "Config/Launch Supplypod"
- set desc = "Configure and launch a Centcom supplypod full of whatever your heart desires!"
+ set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!"
set category = "Admin"
var/datum/centcom_podlauncher/plaunch = new(usr)//create the datum
plaunch.ui_interact(usr)//datum has a tgui component, here we open the window
@@ -23,7 +23,10 @@
var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back
var/client/holder //client of whoever is using this datum
var/area/bay //What bay we're using to launch shit from.
+ var/turf/dropoff_turf //If we're reversing, where the reverse pods go
+ var/picking_dropoff_turf
var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicateObject() and send the result
+ var/launchRandomItem = FALSE //If true, lauches a single random item instead of everything on a turf.
var/launchChoice = 1 //Determines if we launch all at once (0) , in order (1), or at random(2)
var/explosionChoice = 0 //Determines if there is no explosion (0), custom explosion (1), or just do a maxcap (2)
var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2)
@@ -50,20 +53,25 @@
temp_pod = new(locate(/area/centcom/supplypod/podStorage) in GLOB.sortedAreas) //Create a new temp_pod in the podStorage area on centcom (so users are free to look at it and change other variables if needed)
orderedArea = createOrderedArea(bay) //Order all the turfs in the selected bay (top left to bottom right) to a single list. Used for the "ordered" mode (launchChoice = 1)
-/datum/centcom_podlauncher/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, \
-force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)//ui_interact is called when the client verb is called.
+/datum/centcom_podlauncher/ui_state(mob/user)
+ return GLOB.admin_state
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/centcom_podlauncher/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "CentcomPodLauncher", "Config/Launch Supplypod", 700, 700, master_ui, state)
+ ui = new(user, src, "CentcomPodLauncher")
ui.open()
/datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI.
var/list/data = list() //*****NOTE*****: Many of these comments are similarly described in supplypod.dm. If you change them here, please consider doing so in the supplypod code as well!
- var/B = (istype(bay, /area/centcom/supplypod/loading/one)) ? 1 : (istype(bay, /area/centcom/supplypod/loading/two)) ? 2 : (istype(bay, /area/centcom/supplypod/loading/three)) ? 3 : (istype(bay, /area/centcom/supplypod/loading/four)) ? 4 : 0 //top ten THICCEST FUCKING TERNARY CONDITIONALS OF 2036
- data["bay"] = B //Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map.
+ var/B = (istype(bay, /area/centcom/supplypod/loading/one)) ? 1 : (istype(bay, /area/centcom/supplypod/loading/two)) ? 2 : (istype(bay, /area/centcom/supplypod/loading/three)) ? 3 : (istype(bay, /area/centcom/supplypod/loading/four)) ? 4 : 0 //(istype(bay, /area/centcom/supplypod/loading/ert)) ? 5 : 0 //top ten THICCEST FUCKING TERNARY CONDITIONALS OF 2036
+ data["bay"] = bay //Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map.
+ data["bayNumber"] = B //Holds the bay as a number. Useful for comparisons in centcom_podlauncher.ract
data["oldArea"] = (oldTurf ? get_area(oldTurf) : null) //Holds the name of the area that the user was in before using the teleportCentcom action
+ data["picking_dropoff_turf"] = picking_dropoff_turf //If we're picking or have picked a dropoff turf. Only works when pod is in reverse mode
+ data["dropoff_turf"] = dropoff_turf //The turf that reverse pods will drop their newly acquired cargo off at
data["launchClone"] = launchClone //Do we launch the actual items in the bay or just launch clones of them?
+ data["launchRandomItem"] = launchRandomItem //Do we launch a single random item instead of everything on the turf?
data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1)
data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
@@ -72,11 +80,12 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
data["openingDelay"] = temp_pod.openingDelay //How long the pod takes to open after landing
data["departureDelay"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod.
+ data["effectShrapnel"] = FALSE //temp_pod.effectShrapnel //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands
data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing
- data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isnt displayed on the turf where the pod will land
+ data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isn't displayed on the turf where the pod will land
data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
data["effectMissile"] = temp_pod.effectMissile //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground
data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
@@ -115,20 +124,41 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
bay = locate(/area/centcom/supplypod/loading/four) in GLOB.sortedAreas
refreshBay()
. = TRUE
+ if("bay5")
+ to_chat(usr, "LetterN is lazy and didin't bother porting this new cc area!")
+ return
+ // bay = locate(/area/centcom/supplypod/loading/ert) in GLOB.sortedAreas
+ // refreshBay()
+ // . = TRUE
+ if("pickDropoffTurf") //Enters a mode that lets you pick the dropoff location for reverse pods
+ if (picking_dropoff_turf)
+ picking_dropoff_turf = FALSE
+ updateCursor(FALSE, FALSE) //Update the cursor of the user to a cool looking target icon
+ return
+ if (launcherActivated)
+ launcherActivated = FALSE //We don't want to have launch mode enabled while we're picking a turf
+ picking_dropoff_turf = TRUE
+ updateCursor(FALSE, TRUE) //Update the cursor of the user to a cool looking target icon
+ . = TRUE
+ if("clearDropoffTurf")
+ picking_dropoff_turf = FALSE
+ dropoff_turf = null
+ updateCursor(FALSE, FALSE)
+ . = TRUE
if("teleportCentcom") //Teleports the user to the centcom supply loading facility.
var/mob/M = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
oldTurf = get_turf(M) //Used for the "teleportBack" action
- var/area/A = locate(/area/centcom/supplypod/loading) in GLOB.sortedAreas
+ var/area/A = locate(bay) in GLOB.sortedAreas
var/list/turfs = list()
for(var/turf/T in A)
turfs.Add(T) //Fill a list with turfs in the area
- var/turf/T = safepick(turfs) //Only teleport if the list isn't empty
- if(!T) //If the list is empty, error and cancel
+ if (!length(turfs)) //If the list is empty, error and cancel
to_chat(M, "Nowhere to jump to!")
- return
+ return //Only teleport if the list isn't empty
+ var/turf/T = pick(turfs)
M.forceMove(T) //Perform the actual teleport
- log_admin("[key_name(usr)] jumped to [AREACOORD(A)]")
- message_admins("[key_name_admin(usr)] jumped to [AREACOORD(A)]")
+ log_admin("[key_name(usr)] jumped to [AREACOORD(T)]")
+ message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]")
. = TRUE
if("teleportBack") //After teleporting to centcom, this button allows the user to teleport to the last spot they were at.
var/mob/M = holder.mob
@@ -144,6 +174,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if("launchClone") //Toggles the launchClone var. See variable declarations above for what this specifically means
launchClone = !launchClone
. = TRUE
+ if("launchRandomItem") //Pick random turfs from the supplypod bay at centcom to launch
+ launchRandomItem = !launchRandomItem
+ . = TRUE
if("launchOrdered") //Launch turfs (from the orderedArea list) one at a time in order, from the supplypod bay at centcom
if (launchChoice == 1) //launchChoice 1 represents ordered. If we push "ordered" and it already is, then we go to default value
launchChoice = 0
@@ -152,7 +185,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
launchChoice = 1
updateSelector()
. = TRUE
- if("launchRandom") //Pick random turfs from the supplypod bay at centcom to launch
+ if("launchRandomTurf") //Pick random turfs from the supplypod bay at centcom to launch
if (launchChoice == 2)
launchChoice = 0
updateSelector()
@@ -170,11 +203,11 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
var/list/expNames = list("Devastation", "Heavy Damage", "Light Damage", "Flame") //Explosions have a range of different types of damage
var/list/boomInput = list()
for (var/i=1 to expNames.len) //Gather input from the user for the value of each type of damage
- boomInput.Add(input("[expNames[i]] Range", "Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", 0) as null|num)
+ boomInput.Add(input("Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", "[expNames[i]] Range", 0) as null|num)
if (isnull(boomInput[i]))
return
if (!isnum(boomInput[i])) //If the user doesn't input a number, set that specific explosion value to zero
- alert(usr, "That wasnt a number! Value set to default (zero) instead.")
+ alert(usr, "That wasn't a number! Value set to default (zero) instead.")
boomInput = 0
explosionChoice = 1
temp_pod.explosionSize = boomInput
@@ -192,11 +225,11 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
damageChoice = 0
temp_pod.damage = 0
return
- var/damageInput = input("How much damage to deal", "Enter the amount of brute damage dealt by getting hit", 0) as null|num
+ var/damageInput = input("Enter the amount of brute damage dealt by getting hit","How much damage to deal", 0) as null|num
if (isnull(damageInput))
return
if (!isnum(damageInput)) //Sanitize the input for damage to deal.s
- alert(usr, "That wasnt a number! Value set to default (zero) instead.")
+ alert(usr, "That wasn't a number! Value set to default (zero) instead.")
damageInput = 0
damageChoice = 1
temp_pod.damage = damageInput
@@ -226,13 +259,32 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
temp_pod.desc = descInput
temp_pod.adminNamed = TRUE //This variable is checked in the supplypod/setStyle() proc
. = TRUE
+ /*
+ if("effectShrapnel") //Creates a cloud of shrapnel on landing
+ if (temp_pod.effectShrapnel == TRUE) //If already doing custom damage, set back to default (no shrapnel)
+ temp_pod.effectShrapnel = FALSE
+ return
+ var/shrapnelInput = input("Please enter the type of pellet cloud you'd like to create on landing (Can be any projectile!)", "Projectile Typepath", 0) in sortList(subtypesof(/obj/item/projectile), /proc/cmp_typepaths_asc)
+ if (isnull(shrapnelInput))
+ return
+ var/shrapnelMagnitude = input("Enter the magnitude of the pellet cloud. This is usually a value around 1-5. Please note that Ryll-Ryll has asked me to tell you that if you go too crazy with the projectiles you might crash the server. So uh, be gentle!", "Shrapnel Magnitude", 0) as null|num
+ if (isnull(shrapnelMagnitude))
+ return
+ if (!isnum(shrapnelMagnitude))
+ alert(usr, "That wasn't a number! Value set to 3 instead.")
+ shrapnelMagnitude = 3
+ temp_pod.shrapnel_type = shrapnelInput
+ temp_pod.shrapnel_magnitude = shrapnelMagnitude
+ temp_pod.effectShrapnel = TRUE
+ . = TRUE
+ */
if("effectStun") //Toggle: Any mob under the pod is stunned (cant move) until the pod lands, hitting them!
temp_pod.effectStun = !temp_pod.effectStun
. = TRUE
if("effectLimb") //Toggle: Anyone carbon mob under the pod loses a limb when it lands
temp_pod.effectLimb = !temp_pod.effectLimb
. = TRUE
- if("effectOrgans") //Toggle: Any carbon mob under the pod loses every limb and organ
+ if("effectOrgans") //Toggle: Anyone carbon mob under the pod loses a limb when it lands
temp_pod.effectOrgans = !temp_pod.effectOrgans
. = TRUE
if("effectBluespace") //Toggle: Deletes the pod after landing
@@ -253,7 +305,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if("effectBurst") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target
effectBurst = !effectBurst
. = TRUE
- if("effectAnnounce") //Toggle: Sends a ghost announcement.
+ if("effectAnnounce") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target
effectAnnounce = !effectAnnounce
. = TRUE
if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from
@@ -272,15 +324,15 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
. = TRUE
////////////////////////////TIMER DELAYS//////////////////
- if("fallDuration") //Change the falling animation duration
- if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the fall duration has already been changed when we push the "change value" button, then set it to default
+ if("fallDuration") //Change the time it takes the pod to land, after firing
+ if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the landing delay has already been changed when we push the "change value" button, then set it to default
temp_pod.fallDuration = initial(temp_pod.fallDuration)
return
- var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num
+ var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
- alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.")
+ alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.")
timeInput = initial(temp_pod.fallDuration)
temp_pod.fallDuration = 10 * timeInput
. = TRUE
@@ -292,7 +344,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
- alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.landingDelay)*0.1]) instead.")
+ alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.landingDelay)*0.1]) instead.")
timeInput = initial(temp_pod.landingDelay)
temp_pod.landingDelay = 10 * timeInput
. = TRUE
@@ -304,7 +356,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input
- alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.openingDelay)*0.1]) instead.")
+ alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.openingDelay)*0.1]) instead.")
timeInput = initial(temp_pod.openingDelay)
temp_pod.openingDelay = 10 * timeInput
. = TRUE
@@ -316,13 +368,13 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (isnull(timeInput))
return
if (!isnum(timeInput))
- alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.departureDelay)*0.1]) instead.")
+ alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.departureDelay)*0.1]) instead.")
timeInput = initial(temp_pod.departureDelay)
temp_pod.departureDelay = 10 * timeInput
. = TRUE
////////////////////////////ADMIN SOUNDS//////////////////
- if("fallingSound") //Admin sound from a local file that plays when the pod falls
+ if("fallSound") //Admin sound from a local file that plays when the pod lands
if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound))
temp_pod.fallingSound = initial(temp_pod.fallingSound)
temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength)
@@ -334,7 +386,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (isnull(timeInput))
return
if (!isnum(timeInput))
- alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.")
+ alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.")
temp_pod.fallingSound = soundInput
temp_pod.fallingSoundLength = 10 * timeInput
. = TRUE
@@ -369,7 +421,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (temp_pod.soundVolume != initial(temp_pod.soundVolume))
temp_pod.soundVolume = initial(temp_pod.soundVolume)
return
- var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 80 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num
+ var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 50 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num
if (isnull(soundInput))
return
temp_pod.soundVolume = soundInput
@@ -421,26 +473,36 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
. = TRUE
if("giveLauncher") //Enters the "Launch Mode". When the launcher is activated, temp_pod is cloned, and the result it filled and launched anywhere the user clicks (unless specificTarget is true)
launcherActivated = !launcherActivated
- updateCursor(launcherActivated) //Update the cursor of the user to a cool looking target icon
+ updateCursor(launcherActivated, FALSE) //Update the cursor of the user to a cool looking target icon
+ . = TRUE
+ if("clearBay") //Delete all mobs and objs in the selected bay
+ if(alert(usr, "This will delete all objs and mobs in [bay]. Are you sure?", "Confirmation", "Delete that shit", "No") == "Delete that shit")
+ clearBay()
+ refreshBay()
. = TRUE
/datum/centcom_podlauncher/ui_close() //Uses the destroy() proc. When the user closes the UI, we clean up the temp_pod and supplypod_selector variables.
qdel(src)
-/datum/centcom_podlauncher/proc/updateCursor(var/launching) //Update the moues of the user
- if (holder) //Check to see if we have a client
- if (launching) //If the launching param is true, we give the user new mouse icons.
- holder.mouse_up_icon = 'icons/effects/supplypod_target.dmi' //Icon for when mouse is released
- holder.mouse_down_icon = 'icons/effects/supplypod_down_target.dmi' //Icon for when mouse is pressed
- holder.mouse_pointer_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released)
- holder.click_intercept = src //Create a click_intercept so we know where the user is clicking
- else
- var/mob/M = holder.mob
- holder.mouse_up_icon = null
- holder.mouse_down_icon = null
- holder.click_intercept = null
- if (M)
- M.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)()
+/datum/centcom_podlauncher/proc/updateCursor(var/launching, var/turf_picking) //Update the mouse of the user
+ if (!holder) //Can't update the mouse icon if the client doesnt exist!
+ return
+ if (launching || turf_picking) //If the launching param is true, we give the user new mouse icons.
+ if(launching)
+ holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_target.dmi' //Icon for when mouse is released
+ holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_down_target.dmi' //Icon for when mouse is pressed
+ if(turf_picking)
+ holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi' //Icon for when mouse is released
+ holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_pickturf_down.dmi' //Icon for when mouse is pressed
+ holder.mouse_pointer_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released)
+ holder.click_intercept = src //Create a click_intercept so we know where the user is clicking
+ else
+ var/mob/M = holder.mob
+ holder.mouse_up_icon = null
+ holder.mouse_down_icon = null
+ holder.click_intercept = null
+ if (M)
+ M.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)()
/datum/centcom_podlauncher/proc/InterceptClickOn(user,params,atom/target) //Click Intercept so we know where to send pods where the user clicks
var/list/pa = params2list(params)
@@ -461,7 +523,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
else
return //if target is null and we don't have a specific target, cancel
if (effectAnnounce)
- deadchat_broadcast("A special package is being launched at the station!", turf_target = target)
+ deadchat_broadcast("A special package is being launched at the station!", turf_target = target) //, message_type=DEADCHAT_ANNOUNCEMENT)
var/list/bouttaDie = list()
for (var/mob/living/M in target)
bouttaDie.Add(M)
@@ -479,6 +541,15 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
else
launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target
sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire.
+ else if (picking_dropoff_turf)
+ //Clicking on UI elements shouldn't pick a dropoff turf
+ if(istype(target,/obj/screen))
+ return FALSE
+
+ . = TRUE
+ if(left_click) //When we left click:
+ dropoff_turf = get_turf(target)
+ to_chat(user, " You've selected [dropoff_turf] at [COORD(dropoff_turf)] as your dropoff location.")
/datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched
orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay
@@ -489,7 +560,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
to_chat(holder.mob, "No /area/centcom/supplypod/loading/one (or /two or /three or /four) in the world! You can make one yourself (then refresh) for now, but yell at a mapper to fix this, today!")
CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!")
orderedArea = list()
- if (!isemptylist(A.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values
+ if (length(A.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values
var/startX = A.contents[1].x //Create the four values (we do it off a.contents[1] so they have some sort of arbitrary initial value. They should be overwritten in a few moments)
var/endX = A.contents[1].x
var/startY = A.contents[1].y
@@ -512,12 +583,12 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
numTurfs = 0 //Counts the number of turfs that can be launched (remember, supplypods either launch all at once or one turf-worth of items at a time)
acceptableTurfs = list()
for (var/turf/T in orderedArea) //Go through the orderedArea list
- if (typecache_filter_list_reverse(T.contents, ignored_atoms).len != 0) //if there is something in this turf that isnt in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
+ if (typecache_filter_list_reverse(T.contents, ignored_atoms).len != 0) //if there is something in this turf that isn't in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
acceptableTurfs.Add(T) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well.
numTurfs ++
launchList = list() //Anything in launchList will go into the supplypod when it is launched
- if (!isemptylist(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true)
+ if (length(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true)
switch(launchChoice)
if(0) //If we are launching all the turfs at once
for (var/turf/T in acceptableTurfs)
@@ -536,22 +607,36 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (isnull(A))
return
var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result
- toLaunch.bay = bay //Bay is currently a nonstatic expression, so it cant go into toLaunch using DuplicateObject
- toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands
- if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
- for (var/atom/movable/O in launchList)
- DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod
- new /obj/effect/abstract/DPtarget(A, toLaunch) //Create the DPTarget, which will eventually forceMove the temp_pod to it's location
+ /*
+ if(dropoff_turf)
+ toLaunch.reverse_dropoff_turf = dropoff_turf
else
- for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList
+ toLaunch.reverse_dropoff_turf = bay //Bay is currently a nonstatic expression, so it cant go into toLaunch using DuplicateObject
+ */
+ toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands
+ // var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/fly_me_to_the_moon]
+ // toLaunch.forceMove(shippingLane) The shipping lane is temporarily closed due to ratvarian blockades
+ if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
+ if(launchRandomItem)
+ var/atom/movable/O = pick_n_take(launchList)
+ DuplicateObject(O).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod
+ else
+ for (var/atom/movable/O in launchList)
+ DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod
+ else
+ if(launchRandomItem)
+ var/atom/movable/O = pick_n_take(launchList)
O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
- new /obj/effect/abstract/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
+ else
+ for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList
+ O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
+ new /obj/effect/abstract/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
if (launchClone)
launchCounter++ //We only need to increment launchCounter if we are cloning objects.
//If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order
/datum/centcom_podlauncher/proc/updateSelector() //Ensures that the selector effect will showcase the next item if needed
- if (launchChoice == 1 && !isemptylist(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay
+ if (launchChoice == 1 && length(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay
var/index = launchCounter + 1 //launchCounter acts as an index to the ordered acceptableTurfs list, so adding one will show the next item in the list
if (index > acceptableTurfs.len) //out of bounds check
index = 1
@@ -559,8 +644,14 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
else
selector.moveToNullspace() //Otherwise, we move the selector to nullspace until it is needed again
+/datum/centcom_podlauncher/proc/clearBay() //Clear all objs and mobs from the selected bay
+ for (var/obj/O in bay.GetAllContents())
+ qdel(O)
+ for (var/mob/M in bay.GetAllContents())
+ qdel(M)
+
/datum/centcom_podlauncher/Destroy() //The Destroy() proc. This is called by ui_close proc, or whenever the user leaves the game
- updateCursor(FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode
+ updateCursor(FALSE, FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode
qdel(temp_pod) //Delete the temp_pod
qdel(selector) //Delete the selector effect
. = ..()
@@ -581,8 +672,8 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
for (var/X in temp_pod.explosionSize)
explosionString += "[X]|"
- var/msg = "launched [podString][whomString].[delayString][damageString][explosionString]]"
- message_admins("[key_name_admin(usr)] [msg] in [AREACOORD(specificTarget)].")
- if (!isemptylist(whoDyin))
+ var/msg = "launched [podString] towards [whomString] [delayString][damageString][explosionString]"
+ message_admins("[key_name_admin(usr)] [msg] in [ADMIN_VERBOSEJMP(specificTarget)].")
+ if (length(whoDyin))
for (var/mob/living/M in whoDyin)
admin_ticket_log(M, "[key_name_admin(usr)] [msg]")
diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm
index 8a438a1342..f5a8d21278 100644
--- a/code/modules/cargo/console.dm
+++ b/code/modules/cargo/console.dm
@@ -3,9 +3,6 @@
desc = "Used to order supplies, approve requests, and control the shuttle."
icon_screen = "supply"
circuit = /obj/item/circuitboard/computer/cargo
- req_access = list(ACCESS_CARGO)
- ui_x = 780
- ui_y = 750
var/requestonly = FALSE
var/contraband = FALSE
@@ -27,7 +24,6 @@
desc = "Used to request supplies from cargo."
icon_screen = "request"
circuit = /obj/item/circuitboard/computer/cargo/request
- req_access = list()
requestonly = TRUE
/obj/machinery/computer/cargo/Initialize()
@@ -66,15 +62,12 @@
var/obj/item/circuitboard/computer/cargo/board = circuit
board.contraband = TRUE
board.obj_flags |= EMAGGED
- req_access = list()
update_static_data(user)
- return ..()
-/obj/machinery/computer/cargo/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/cargo/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Cargo", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "Cargo", name)
ui.open()
/obj/machinery/computer/cargo/ui_data()
@@ -120,7 +113,6 @@
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])
@@ -135,8 +127,8 @@
"cost" = P.cost,
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
+ "goody" = P.goody,
"private_goody" = P.goody == PACK_GOODY_PRIVATE,
- "goody" = P.goody == PACK_GOODY_PUBLIC,
"access" = P.access,
"can_private_buy" = P.can_private_buy
))
@@ -145,9 +137,6 @@
/obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui)
if(..())
return
- if(!allowed(usr))
- to_chat(usr, "Access denied.")
- return
switch(action)
if("send")
if(!SSshuttle.supply.canMove())
@@ -179,6 +168,8 @@
else
SSshuttle.shuttle_loan.loan_shuttle()
say("The supply shuttle has been loaned to CentCom.")
+ investigate_log("[key_name(usr)] accepted a shuttle loan event.", INVESTIGATE_CARGO)
+ log_game("[key_name(usr)] accepted a shuttle loan event.")
. = TRUE
if("add")
var/id = text2path(params["id"])
@@ -200,13 +191,15 @@
rank = "Silicon"
var/datum/bank_account/account
- if(self_paid)
- if(!pack.can_private_buy && !(obj_flags & EMAGGED))
- return
- var/obj/item/card/id/id_card = usr.get_idcard(TRUE)
+ if(self_paid && ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/card/id/id_card = H.get_idcard(TRUE)
if(!istype(id_card))
say("No ID card detected.")
return
+ if(istype(id_card, /obj/item/card/id/departmental_budget))
+ say("The [src] rejects [id_card].")
+ return
account = id_card.registered_account
if(!istype(account))
say("Invalid bank account.")
@@ -241,6 +234,9 @@
SSshuttle.shoppinglist += SO
if(self_paid)
say("Order processed. The price will be charged to [account.account_holder]'s bank account on delivery.")
+ if(requestonly && message_cooldown < world.time)
+ radio.talk_into(src, "A new order has been requested.", RADIO_CHANNEL_SUPPLY)
+ message_cooldown = world.time + 30 SECONDS
. = TRUE
if("remove")
var/id = text2num(params["id"])
diff --git a/code/modules/cargo/coupon.dm b/code/modules/cargo/coupon.dm
index c77050c530..1c1f2a36e1 100644
--- a/code/modules/cargo/coupon.dm
+++ b/code/modules/cargo/coupon.dm
@@ -8,6 +8,7 @@
icon = 'icons/obj/card.dmi'
item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_TINY
+ attack_speed = CLICK_CD_RAPID
var/datum/supply_pack/discounted_pack
var/discount_pct_off = 0.05
var/obj/machinery/computer/cargo/inserted_console
@@ -34,6 +35,7 @@
if(discount_pct_off == COUPON_OMEN)
to_chat(user, "\The [O] validates the coupon as authentic, but refuses to accept it...")
O.say("Coupon fulfillment already in progress...")
+ user.DelayNextAction()
return
inserted_console = O
diff --git a/code/modules/cargo/exports/organs_robotics.dm b/code/modules/cargo/exports/organs_robotics.dm
index a6c5ee93ca..7f54e675ca 100644
--- a/code/modules/cargo/exports/organs_robotics.dm
+++ b/code/modules/cargo/exports/organs_robotics.dm
@@ -144,7 +144,7 @@
/datum/export/robotics/surgery_gear_basic
cost = 10
unit_name = "surgery tool"
- export_types = list(/obj/item/retractor, /obj/item/hemostat, /obj/item/cautery, /obj/item/surgicaldrill, /obj/item/scalpel, /obj/item/circular_saw, /obj/item/surgical_drapes)
+ export_types = list(/obj/item/retractor, /obj/item/hemostat, /obj/item/cautery, /obj/item/surgicaldrill, /obj/item/scalpel, /obj/item/circular_saw, /obj/item/bonesetter, /obj/item/surgical_drapes)
/datum/export/robotics/mech_weapon_laser
cost = 300 //Sadly just metal and glass
diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm
index dc7e4b5a06..4ca97a13a5 100644
--- a/code/modules/cargo/expressconsole.dm
+++ b/code/modules/cargo/expressconsole.dm
@@ -1,5 +1,5 @@
#define MAX_EMAG_ROCKETS 8
-#define BEACON_COST 5000
+#define BEACON_COST 500
#define SP_LINKED 1
#define SP_READY 2
#define SP_LAUNCH 3
@@ -13,10 +13,9 @@
All sales are near instantaneous - please choose carefully"
icon_screen = "supply_express"
circuit = /obj/item/circuitboard/computer/cargo/express
- ui_x = 600
- ui_y = 700
blockade_warning = "Bluespace instability detected. Delivery impossible."
req_access = list(ACCESS_QM)
+
var/message
var/printed_beacons = 0 //number of beacons printed. Used to determine beacon names.
var/list/meme_pack_data
@@ -42,7 +41,7 @@
to_chat(user, "You [locked ? "lock" : "unlock"] the interface.")
return
else if(istype(W, /obj/item/disk/cargo/bluespace_pod))
- podType = /obj/structure/closet/supplypod/bluespacepod
+ podType = /obj/structure/closet/supplypod/bluespacepod //doesnt effect circuit board, making reversal possible
to_chat(user, "You insert the disk into [src], allowing for advanced supply delivery vehicles.")
qdel(W)
return TRUE
@@ -52,22 +51,20 @@
sb.link_console(src, user)
return TRUE
else
- to_chat(user, "[src] is already linked to [sb].")
+ to_chat(user, "[src] is already linked to [sb].")
..()
/obj/machinery/computer/cargo/express/emag_act(mob/living/user)
- . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
if(obj_flags & EMAGGED)
return
- user.visible_message("[user] swipes a suspicious card through [src]!",
- "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.")
+ if(user)
+ user.visible_message("[user] swipes a suspicious card through [src]!",
+ "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.")
obj_flags |= EMAGGED
// This also sets this on the circuit board
var/obj/item/circuitboard/computer/cargo/board = circuit
board.obj_flags |= EMAGGED
packin_up()
- req_access = list()
- return TRUE
/obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry
meme_pack_data = list() // sorry for what?
@@ -89,10 +86,10 @@
"desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name.
))
-/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "CargoExpress", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "CargoExpress", name)
ui.open()
/obj/machinery/computer/cargo/express/ui_data(mob/user)
@@ -131,9 +128,6 @@
return data
/obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui)
- if(!allowed(usr))
- to_chat(usr, "Access denied.")
- return
switch(action)
if("LZCargo")
usingBeacon = FALSE
@@ -153,6 +147,7 @@
printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1
beacon.name = "Supply Pod Beacon #[printed_beacons]"
+
if("add")//Generate Supply Order first
var/id = text2path(params["id"])
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
@@ -195,7 +190,6 @@
LZ = pick(empty_turfs)
if (SO.pack.cost <= points_to_check && LZ)//we need to call the cost check again because of the CHECK_TICK call
D.adjust_money(-SO.pack.cost)
- SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
new /obj/effect/abstract/DPtarget(LZ, podType, SO)
. = TRUE
update_icon()
@@ -209,7 +203,7 @@
CHECK_TICK
if(empty_turfs && empty_turfs.len)
D.adjust_money(-(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS)))
- SSblackbox.record_feedback("nested tally", "cargo_imports", MAX_EMAG_ROCKETS, list("[SO.pack.cost * 0.72]", "[SO.pack.name]"))
+
SO.generateRequisition(get_turf(src))
for(var/i in 1 to MAX_EMAG_ROCKETS)
var/LZ = pick(empty_turfs)
diff --git a/code/modules/cargo/packs/goodies.dm b/code/modules/cargo/packs/goodies.dm
index ac8b1e9032..86a7c73a34 100644
--- a/code/modules/cargo/packs/goodies.dm
+++ b/code/modules/cargo/packs/goodies.dm
@@ -75,3 +75,15 @@
desc = "The simple beach ball is one of Nanotrasen's most popular products. 'Why do we make beach balls? Because we can! (TM)' - Nanotrasen"
cost = 200
contains = list(/obj/item/toy/beach_ball)
+
+/datum/supply_pack/goody/hell_single
+ name = "Hellgun Single-Pack"
+ desc = "Contains one hellgun, an old pattern of laser gun infamous for its ability to horribly disfigure targets with burns. Technically violates the Space Geneva Convention when used on humanoids."
+ cost = 1500
+ contains = list(/obj/item/gun/energy/laser/hellgun)
+
+/datum/supply_pack/goody/medipen_twopak
+ name = "Medipen Two-Pak"
+ desc = "Contains one standard epinephrine medipen and one standard emergency first-aid kit medipen. For when you want to prepare for the worst."
+ cost = 500
+ contains = list(/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/hypospray/medipen/ekit)
diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm
index 2bb629308c..6a4165f840 100644
--- a/code/modules/cargo/packs/medical.dm
+++ b/code/modules/cargo/packs/medical.dm
@@ -114,7 +114,9 @@
/obj/item/storage/box/medsprays,
/obj/item/storage/box/syringes,
/obj/item/storage/box/bodybags,
- /obj/item/storage/pill_bottle/stimulant)
+ /obj/item/storage/pill_bottle/stimulant,
+ /obj/item/stack/medical/bone_gel,
+ /obj/item/stack/medical/bone_gel)
crate_name = "medical supplies crate"
/datum/supply_pack/medical/adv_surgery_tools
@@ -216,3 +218,18 @@
/obj/item/storage/box/beakers)
crate_name = "virus containment unit crate"
crate_type = /obj/structure/closet/crate/secure/plasma
+
+/datum/supply_pack/medical/medipen_variety
+ name = "Medipen Variety-Pak"
+ desc = "Contains eight different medipens in three different varieties, to assist in quickly treating seriously injured patients."
+ cost = 2000
+ contains = list(/obj/item/reagent_containers/hypospray/medipen/,
+ /obj/item/reagent_containers/hypospray/medipen/,
+ /obj/item/reagent_containers/hypospray/medipen/ekit,
+ /obj/item/reagent_containers/hypospray/medipen/ekit,
+ /obj/item/reagent_containers/hypospray/medipen/ekit,
+ /obj/item/reagent_containers/hypospray/medipen/blood_loss,
+ /obj/item/reagent_containers/hypospray/medipen/blood_loss,
+ /obj/item/reagent_containers/hypospray/medipen/blood_loss)
+
+ crate_name = "medipen crate"
diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm
index a84e22f6f9..c6728831eb 100644
--- a/code/modules/cargo/packs/misc.dm
+++ b/code/modules/cargo/packs/misc.dm
@@ -194,9 +194,9 @@
/datum/supply_pack/misc/dirtymags
name = "Dirty Magazines"
- desc = "Get your mind out of the gutter operative, you have work to do. Three items per order. Possible Results: .357 Speedloaders, Kitchen Gun Mags, Stetchkin Mags."
+ desc = "Get your mind out of the gutter operative, you have work to do. Three items per order. Possible Results: .357 Speedloaders, Kitchen Gun patented magazines, or Stetchkin magazines."
hidden = TRUE
- cost = 12000
+ cost = 4000
var/num_contained = 3
contains = list(/obj/item/ammo_box/a357,
/obj/item/ammo_box/magazine/pistolm9mm,
@@ -415,21 +415,10 @@
/obj/item/restraints/handcuffs/fake/kinky,
/obj/item/clothing/head/kitty/genuine, // Why its illegal
/obj/item/clothing/head/kitty/genuine,
- /obj/item/storage/pill_bottle/penis_enlargement,
- /obj/structure/reagent_dispensers/keg/aphro)
+ /obj/item/storage/pill_bottle/penis_enlargement)
crate_name = "lewd kit"
crate_type = /obj/structure/closet/crate
-/datum/supply_pack/misc/lewdkeg
- name = "Lewd Deluxe Keg"
- desc = "That other stuff not getting you ready? Well I have a Chemslut making tons of the good stuff."
- cost = 7500 //It can be a weapon
- contraband = TRUE
- contains = list(/obj/structure/reagent_dispensers/keg/aphro/strong)
- crate_name = "deluxe keg"
- crate_type = /obj/structure/closet/crate
-
-
///Special supply crate that generates random syndicate gear up to a determined TC value
/datum/supply_pack/misc/syndicate
@@ -466,4 +455,4 @@
if(crate_value < I.cost)
continue
crate_value -= I.cost
- new I.item(C)
\ No newline at end of file
+ new I.item(C)
diff --git a/code/modules/cargo/packs/organic.dm b/code/modules/cargo/packs/organic.dm
index 249faae33d..0f01dfd5d9 100644
--- a/code/modules/cargo/packs/organic.dm
+++ b/code/modules/cargo/packs/organic.dm
@@ -361,6 +361,7 @@
/obj/item/seeds/reishi,
/obj/item/seeds/banana,
/obj/item/seeds/eggplant/eggy,
+ /obj/item/seeds/poppy/lily/trumpet,
/obj/item/seeds/random,
/obj/item/seeds/random)
crate_name = "exotic seeds crate"
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 7f1ba86ff5..ae48fddfb4 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -30,6 +30,9 @@
var/move_delay = 0
var/area = null
+ /// Last time we Click()ed. No clicking twice in one tick!
+ var/last_click = 0
+
///////////////
//SOUND STUFF//
///////////////
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 1da69f197f..9b7e928852 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -41,6 +41,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(!asset_cache_job)
return
+ // Rate limiting
var/mtl = CONFIG_GET(number/minute_topic_limit)
if (!holder && mtl)
var/minute = round(world.time, 600)
@@ -98,6 +99,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
keyUp(keycode)
return
+ // Tgui Topic middleware
+ if(!tgui_Topic(href_list))
+ return
+
// Admin PM
if(href_list["priv_msg"])
cmd_admin_pm(href_list["priv_msg"],null)
@@ -471,6 +476,11 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
//////////////
/client/Del()
+ if(!gc_destroyed)
+ Destroy()
+ return ..()
+
+/client/Destroy()
if(credits)
QDEL_LIST(credits)
log_access("Logout: [key_name(src)]")
@@ -504,9 +514,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
Master.UpdateTickRate()
- return ..()
-
-/client/Destroy()
+ . = ..()
return QDEL_HINT_HARDDEL_NOW
/client/proc/set_client_age_from_db(connectiontopic)
@@ -771,6 +779,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
ip_intel = res.intel
/client/Click(atom/object, atom/location, control, params, ignore_spam = FALSE)
+ if(last_click > world.time - world.tick_lag)
+ return
+ last_click = world.time
var/ab = FALSE
var/list/L = params2list(params)
if (object && object == middragatom && L["left"])
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 8b4c28a1f4..1b6e1f9748 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -40,7 +40,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were,
//autocorrected this round, not that you'd need to check that.
-
var/UI_style = null
var/buttons_locked = FALSE
var/hotkeys = FALSE
@@ -83,24 +82,24 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/gender = MALE //gender of character (well duh)
var/age = 30 //age of character
var/underwear = "Nude" //underwear type
- var/undie_color = "FFF"
+ var/undie_color = "FFFFFF"
var/undershirt = "Nude" //undershirt type
- var/shirt_color = "FFF"
+ var/shirt_color = "FFFFFF"
var/socks = "Nude" //socks type
- var/socks_color = "FFF"
+ var/socks_color = "FFFFFF"
var/backbag = DBACKPACK //backpack type
var/jumpsuit_style = PREF_SUIT //suit/skirt
var/hair_style = "Bald" //Hair type
- var/hair_color = "000" //Hair color
+ var/hair_color = "000000" //Hair color
var/facial_hair_style = "Shaved" //Face hair type
- var/facial_hair_color = "000" //Facial hair color
+ var/facial_hair_color = "000000" //Facial hair color
var/skin_tone = "caucasian1" //Skin color
var/use_custom_skin_tone = FALSE
- var/eye_color = "000" //Eye color
+ var/eye_color = "000000" //Eye color
var/datum/species/pref_species = new /datum/species/human() //Mutant race
- var/list/features = list("mcolor" = "FFF",
- "mcolor2" = "FFF",
- "mcolor3" = "FFF",
+ var/list/features = list("mcolor" = "FFFFFF",
+ "mcolor2" = "FFFFFF",
+ "mcolor3" = "FFFFFF",
"tail_lizard" = "Smooth",
"tail_human" = "None",
"snout" = "Round",
@@ -131,23 +130,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"cock_shape" = DEF_COCK_SHAPE,
"cock_length" = COCK_SIZE_DEF,
"cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF,
- "cock_color" = "fff",
+ "cock_color" = "ffffff",
"cock_taur" = FALSE,
"has_balls" = FALSE,
- "balls_color" = "fff",
+ "balls_color" = "ffffff",
"balls_shape" = DEF_BALLS_SHAPE,
"balls_size" = BALLS_SIZE_DEF,
"balls_cum_rate" = CUM_RATE,
"balls_cum_mult" = CUM_RATE_MULT,
"balls_efficiency" = CUM_EFFICIENCY,
"has_breasts" = FALSE,
- "breasts_color" = "fff",
+ "breasts_color" = "ffffff",
"breasts_size" = BREASTS_SIZE_DEF,
"breasts_shape" = DEF_BREASTS_SHAPE,
"breasts_producing" = FALSE,
"has_vag" = FALSE,
"vag_shape" = DEF_VAGINA_SHAPE,
- "vag_color" = "fff",
+ "vag_color" = "ffffff",
"has_womb" = FALSE,
"balls_visibility" = GEN_VISIBLE_NO_UNDIES,
"breasts_visibility"= GEN_VISIBLE_NO_UNDIES,
@@ -230,7 +229,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/gear_points = 10
var/list/gear_categories
var/list/chosen_gear = list()
- var/gear_tab
+ var/gear_category
+ var/gear_subcategory
var/screenshake = 100
var/damagescreenshake = 2
@@ -239,6 +239,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/autostand = TRUE
var/auto_ooc = FALSE
+ /// If we have persistent scars enabled
+ var/persistent_scars = TRUE
+ /// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
+ var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
+ /// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
+ var/scars_index = 1
+
/datum/preferences/New(client/C)
parent = C
@@ -825,6 +832,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Socks Color:Change "
dat += "Backpack:[backbag]"
dat += "Jumpsuit: [jumpsuit_style] "
+ if((HAS_FLESH in pref_species.species_traits) || (HAS_BONE in pref_species.species_traits))
+ dat += " Temporal Scarring: [(persistent_scars) ? "Enabled" : "Disabled"]"
+ dat += "Clear scar slots"
dat += "Uplink Location:[uplink_spawn_loc]"
dat += ""
@@ -1049,58 +1059,83 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += " "
if(3)
- if(!gear_tab)
- gear_tab = GLOB.loadout_items[1]
dat += "
"
- for(var/V in categories[cat])
- var/datum/design/D = V
- dat += "[D.name]: Make"
- if(cat in timesFiveCategories)
- dat += "x5"
- if(ispath(D.build_path, /obj/item/stack))
- dat += "x10"
- dat += "([CEILING(D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency, 1)]) "
- dat += "
"
- else
- dat += "
No container inside, please insert container.
"
-
- var/datum/browser/popup = new(user, "biogen", name, 350, 520)
- popup.set_content(dat)
- popup.open()
-
/obj/machinery/biogenerator/AltClick(mob/living/user)
. = ..()
- if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) && can_interact(user))
detach(user)
-/obj/machinery/biogenerator/proc/activate()
- if (usr.stat != CONSCIOUS)
+/**
+ * activate: Activates biomass processing and converts all inserted grown products into biomass
+ *
+ * Arguments:
+ * * user The mob starting the biomass processing
+ */
+/obj/machinery/biogenerator/proc/activate(mob/user)
+ if(user.stat != CONSCIOUS)
return
- if (src.stat != NONE) //NOPOWER etc
+ if(stat != NONE)
return
if(processing)
- to_chat(usr, "The biogenerator is in the process of working.")
+ to_chat(user, "The biogenerator is in the process of working.")
return
var/S = 0
- var/total = 0
for(var/obj/item/reagent_containers/food/snacks/grown/I in contents)
S += 5
- var/nutri_amount = I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)
- if(nutri_amount < 0.1)
- total += 1*productivity
+ if(I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) < 0.1)
+ points += 1 * productivity
else
- total += nutri_amount*10*productivity
+ points += I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) * 10 * productivity
qdel(I)
- points += round(total)
if(S)
processing = TRUE
update_icon()
- updateUsrDialog()
- playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
- use_power(S*30)
- sleep(S+15/productivity)
+ playsound(loc, 'sound/machines/blender.ogg', 50, TRUE)
+ use_power(S * 30)
+ sleep(S + 15 / productivity)
+ if(QDELETED(src)) //let's not.
+ return
processing = FALSE
update_icon()
- else
- menustat = "void"
/obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = TRUE)
if(materials.len != 1 || materials[1] != SSmaterials.GetMaterialRef(/datum/material/biomass))
return FALSE
- var/cost = CEILING(materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency, 1)
- if (cost > points)
- menustat = "nopoints"
+ if (materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency > points)
return FALSE
else
if(remove_points)
- points -= cost
+ points -= materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency
update_icon()
- updateUsrDialog()
return TRUE
/obj/machinery/biogenerator/proc/check_container_volume(list/reagents, multiplier = 1)
@@ -262,7 +205,6 @@
sum_reagents *= multiplier
if(beaker.reagents.total_volume + sum_reagents > beaker.reagents.maximum_volume)
- menustat = "nobeakerspace"
return FALSE
return TRUE
@@ -284,6 +226,7 @@
var/i = amount
while(i > 0)
if(!check_container_volume(D.make_reagents))
+ say("Warning: Attached container does not have enough free capacity!")
return .
if(!check_cost(D.materials))
return .
@@ -293,51 +236,100 @@
beaker.reagents.add_reagent(R, D.make_reagents[R])
. = 1
--i
-
- menustat = "complete"
update_icon()
return .
/obj/machinery/biogenerator/proc/detach(mob/living/user)
if(beaker)
- user.put_in_hands(beaker)
+ if(can_interact(user))
+ user.put_in_hands(beaker)
+ else
+ beaker.drop_location(get_turf(src))
beaker = null
update_icon()
-/obj/machinery/biogenerator/Topic(href, href_list)
- if(..() || panel_open)
+/obj/machinery/biogenerator/ui_status(mob/user)
+ if(stat & BROKEN || panel_open)
+ return UI_CLOSE
+ return ..()
+
+/obj/machinery/biogenerator/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/research_designs),
+ )
+
+/obj/machinery/biogenerator/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Biogenerator", name)
+ ui.open()
+
+/obj/machinery/biogenerator/ui_data(mob/user)
+ var/list/data = list()
+ data["beaker"] = beaker ? TRUE : FALSE
+ data["biomass"] = points
+ data["processing"] = processing
+ if(locate(/obj/item/reagent_containers/food/snacks/grown) in contents)
+ data["can_process"] = TRUE
+ else
+ data["can_process"] = FALSE
+ return data
+
+/obj/machinery/biogenerator/ui_static_data(mob/user)
+ var/list/data = list()
+ data["categories"] = list()
+
+ var/categories = show_categories.Copy()
+ for(var/V in categories)
+ categories[V] = list()
+ for(var/V in stored_research.researched_designs)
+ var/datum/design/D = SSresearch.techweb_design_by_id(V)
+ for(var/C in categories)
+ if(C in D.category)
+ categories[C] += D
+
+ for(var/category in categories)
+ var/list/cat = list(
+ "name" = category,
+ "items" = (category == selected_cat ? list() : null))
+ for(var/item in categories[category])
+ var/datum/design/D = item
+ cat["items"] += list(list(
+ "id" = D.id,
+ "name" = D.name,
+ "cost" = D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency,
+ ))
+ data["categories"] += list(cat)
+
+ return data
+
+/obj/machinery/biogenerator/ui_act(action, list/params)
+ if(..())
return
- usr.set_machine(src)
-
- if(href_list["activate"])
- activate()
- updateUsrDialog()
-
- else if(href_list["detach"])
- detach(usr)
- updateUsrDialog()
-
- else if(href_list["create"])
- var/amount = (text2num(href_list["amount"]))
- //Can't be outside these (if you change this keep a sane limit)
- amount = clamp(amount, 1, 50)
- var/id = href_list["create"]
- if(!stored_research.researched_designs.Find(id))
- //naughty naughty
- stack_trace("ID did not map to a researched datum [id]")
- return
-
- //Get design by id (or may return error design)
- var/datum/design/D = SSresearch.techweb_design_by_id(id)
- //Valid design datum, amount and the datum is not the error design, lets proceed
- if(D && amount && !istype(D, /datum/design/error_design))
- create_product(D, amount)
- //This shouldnt happen normally but href forgery is real
- else
- stack_trace("ID could not be turned into a valid techweb design datum [id]")
- updateUsrDialog()
-
- else if(href_list["menu"])
- menustat = "menu"
- updateUsrDialog()
+ switch(action)
+ if("activate")
+ activate(usr)
+ return TRUE
+ if("detach")
+ detach(usr)
+ return TRUE
+ if("create")
+ var/amount = text2num(params["amount"])
+ amount = clamp(amount, 1, 10)
+ if(!amount)
+ return
+ var/id = params["id"]
+ if(!stored_research.researched_designs.Find(id))
+ stack_trace("ID did not map to a researched datum [id]")
+ return
+ var/datum/design/D = SSresearch.techweb_design_by_id(id)
+ if(D && !istype(D, /datum/design/error_design))
+ create_product(D, amount)
+ else
+ stack_trace("ID could not be turned into a valid techweb design datum [id]")
+ return
+ return TRUE
+ if("select")
+ selected_cat = params["category"]
+ return TRUE
diff --git a/code/modules/hydroponics/fermenting_barrel.dm b/code/modules/hydroponics/fermenting_barrel.dm
index 70e204a14f..76e36a1725 100644
--- a/code/modules/hydroponics/fermenting_barrel.dm
+++ b/code/modules/hydroponics/fermenting_barrel.dm
@@ -56,7 +56,7 @@
else
return ..()
-/obj/structure/fermenting_barrel/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/fermenting_barrel/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
open = !open
if(open)
DISABLE_BITFIELD(reagents.reagents_holder_flags, DRAINABLE)
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index 0411a80443..81318f8fe1 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -27,6 +27,12 @@
juice_results = list(/datum/reagent/consumable/banana = 0)
distill_reagent = /datum/reagent/consumable/ethanol/bananahonk
+/obj/item/reagent_containers/food/snacks/grown/banana/generate_trash(atom/location)
+ . = ..()
+ var/obj/item/grown/bananapeel/peel = .
+ if(istype(peel))
+ peel.grind_results = list(/datum/reagent/consumable/banana_peel = seed.potency * 0.2)
+
/obj/item/reagent_containers/food/snacks/grown/banana/suicide_act(mob/user)
user.visible_message("[user] is aiming [src] at [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1, -1)
diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm
index 42674029fb..001a90b441 100644
--- a/code/modules/hydroponics/grown/chili.dm
+++ b/code/modules/hydroponics/grown/chili.dm
@@ -80,11 +80,9 @@
foodtype = FRUIT
wine_power = 50
-/obj/item/reagent_containers/food/snacks/grown/ghost_chili/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/reagent_containers/food/snacks/grown/ghost_chili/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
- if(.)
- return
- if( ismob(loc) )
+ if(ishuman(loc))
held_mob = loc
START_PROCESSING(SSobj, src)
diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm
index 0979ea483f..cee7748c59 100644
--- a/code/modules/hydroponics/grown/nettle.dm
+++ b/code/modules/hydroponics/grown/nettle.dm
@@ -90,6 +90,7 @@
icon_state = "deathnettle"
force = 30
throwforce = 15
+ wound_bonus = CANT_WOUND
/obj/item/reagent_containers/food/snacks/grown/nettle/death/add_juice()
..()
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index 78fddbd989..328b4c391c 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -29,6 +29,28 @@
create_reagents(volume, INJECTABLE | DRAWABLE)
+/obj/item/seeds/replicapod/pre_attack(obj/machinery/hydroponics/I)
+ if(istype(I, /obj/machinery/hydroponics))
+ if(!I.myseed)
+ START_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/seeds/replicapod/proc/check_mind_orbiting(atom/A)
+ for(var/mob/M in A.orbiters?.orbiters)
+ if(mind && M.mind && ckey(M.mind.key) == ckey(mind.key) && M.ckey && M.client && M.stat == DEAD && !M.suiciding && isobserver(M))
+ return TRUE
+ return FALSE
+
+/obj/item/seeds/replicapod/process()
+ var/obj/machinery/hydroponics/parent = loc
+ if(parent.harvest != 1)
+ return
+ if (check_mind_orbiting(parent))
+ icon_harvest = "replicapod-orbit"
+ else
+ icon_harvest = "replicapod-harvest"
+ parent.update_icon_plant()
+
/obj/item/seeds/replicapod/on_reagent_change(changetype)
if(changetype == ADD_REAGENT)
var/datum/reagent/blood/B = reagents.has_reagent(/datum/reagent/blood)
@@ -59,8 +81,11 @@
/obj/item/seeds/replicapod/get_analyzer_text()
var/text = ..()
+ var/obj/machinery/hydroponics/parent = loc
if(contains_sample)
text += "\n It contains a blood sample!"
+ if (parent && istype(parent) && check_mind_orbiting(parent))
+ text += "\n The soul is ready to enter the body."
return text
@@ -115,7 +140,7 @@
features["mcolor"] = "#59CE00"
for(var/V in quirks)
new V(podman)
- podman.hardset_dna(null,null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
+ podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
podman.set_cloned_appearance()
else //else, one packet of seeds. maybe two
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index 164c27d105..ecbfa7584b 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -207,10 +207,7 @@
return ..()
-/obj/structure/bonfire/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/bonfire/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(burning)
to_chat(user, "You need to extinguish [src] before removing the logs!")
return
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index 9b5983c8e9..abf6632939 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -82,7 +82,7 @@
custom_materials = list(/datum/material/iron = 15000)
attack_verb = list("chopped", "torn", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
/obj/item/hatchet/Initialize()
. = ..()
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index efe965e8ea..a208f2de3c 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -889,10 +889,7 @@
return ..()
-/obj/machinery/hydroponics/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/machinery/hydroponics/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(issilicon(user)) //How does AI know what plant is?
return
if(harvest)
diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index 63b96632e6..71701d9637 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -1,3 +1,18 @@
+/**
+ * Finds and extracts seeds from an object
+ *
+ * Checks if the object is such that creates a seed when extracted. Used by seed
+ * extractors or posably anything that would create seeds in some way. The seeds
+ * are dropped either at the extractor, if it exists, or where the original object
+ * was and it qdel's the object
+ *
+ * Arguments:
+ * * O - Object containing the seed, can be the loc of the dumping of seeds
+ * * t_max - Amount of seed copies to dump, -1 is ranomized
+ * * extractor - Seed Extractor, used as the dumping loc for the seeds and seed multiplier
+ * * user - checks if we can remove the object from the inventory
+ * *
+ */
/proc/seedify(obj/item/O, t_max, obj/machinery/seed_extractor/extractor, mob/living/user)
var/t_amount = 0
var/list/seeds = list()
@@ -46,20 +61,22 @@
icon_state = "sextractor"
density = TRUE
circuit = /obj/item/circuitboard/machine/seed_extractor
- var/piles = list()
+ /// Associated list of seeds, they are all weak refs. We check the len to see how many refs we have for each
+ // seed
+ var/list/piles = list()
var/max_seeds = 1000
var/seed_multiplier = 1
/obj/machinery/seed_extractor/RefreshParts()
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
- max_seeds = 1000 * B.rating
+ max_seeds = initial(max_seeds) * B.rating
for(var/obj/item/stock_parts/manipulator/M in component_parts)
- seed_multiplier = M.rating
+ seed_multiplier = initial(seed_multiplier) * M.rating
/obj/machinery/seed_extractor/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce. Machine can store up to [max_seeds] seeds."
+ . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce. Machine can store up to [max_seeds]% seeds."
/obj/machinery/seed_extractor/attackby(obj/item/O, mob/user, params)
@@ -102,78 +119,26 @@
else
return ..()
-/datum/seed_pile
- var/name = ""
- var/lifespan = 0 //Saved stats
- var/endurance = 0
- var/maturation = 0
- var/production = 0
- var/yield = 0
- var/potency = 0
- var/amount = 0
+/**
+ * Generate seed string
+ *
+ * Creates a string based of the traits of a seed. We use this string as a bucket for all
+ * seeds that match as well as the key the ui uses to get the seed. We also use the key
+ * for the data shown in the ui. Javascript parses this string to display
+ *
+ * Arguments:
+ * * O - seed to generate the string from
+ */
+/obj/machinery/seed_extractor/proc/generate_seed_string(obj/item/seeds/O)
+ return "name=[O.name];lifespan=[O.lifespan];endurance=[O.endurance];maturation=[O.maturation];production=[O.production];yield=[O.yield];potency=[O.potency];instability=0"
-/datum/seed_pile/New(var/name, var/life, var/endur, var/matur, var/prod, var/yie, var/poten, var/am = 1)
- src.name = name
- src.lifespan = life
- src.endurance = endur
- src.maturation = matur
- src.production = prod
- src.yield = yie
- src.potency = poten
- src.amount = am
-
-/obj/machinery/seed_extractor/ui_interact(mob/user)
- . = ..()
- if (stat)
- return FALSE
-
- var/dat = "Stored seeds: "
-
- if (contents.len == 0)
- dat += "No seeds"
- else
- dat += "
Name
Lifespan
Endurance
Maturation
Production
Yield
Potency
Stock
"
- for (var/datum/seed_pile/O in piles)
- dat += "
"
@@ -294,6 +298,12 @@
if (!strip_silence)
to_chat(src, "You feel your [pocket_side] pocket being fumbled with!")
+ if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY, null, FALSE))
+ // separate from first canusetopic
+ var/mob/living/user = usr
+ if(istype(user) && href_list["shoes"] && (user.mobility_flags & MOBILITY_USE)) // we need to be on the ground, so we'll be a bit looser
+ shoes.handle_tying(usr)
+
..() //CITADEL CHANGE - removes a tab from behind this ..() so that flavortext can actually be examined
@@ -390,7 +400,7 @@
// Checks the user has security clearence before allowing them to change arrest status via hud, comment out to enable all access
var/allowed_access = null
var/obj/item/clothing/glasses/G = H.glasses
- if (!(G.obj_flags |= EMAGGED))
+ if (!(G.obj_flags & EMAGGED))
if(H.wear_id)
var/list/access = H.wear_id.GetAccess()
if(ACCESS_SEC_DOORS in access)
@@ -735,8 +745,7 @@
/mob/living/carbon/human/resist_restraints()
if(wear_suit && wear_suit.breakouttime)
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
+ MarkResistTime()
cuff_resist(wear_suit)
else
..()
@@ -1031,15 +1040,9 @@
return TRUE
return FALSE
-/mob/living/carbon/human/proc/clear_shove_slowdown()
- remove_movespeed_modifier(/datum/movespeed_modifier/shove)
- var/active_item = get_active_held_item()
- if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
- visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE)
-
/mob/living/carbon/human/updatehealth()
. = ..()
-
+ dna?.species.spec_updatehealth(src)
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN)) //if we want to ignore slowdown from damage and equipment
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
@@ -1057,10 +1060,21 @@
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
+
/mob/living/carbon/human/do_after_coefficent()
. = ..()
. *= physiology.do_after_speed
+/mob/living/carbon/human/is_bleeding()
+ if(NOBLOOD in dna.species.species_traits || bleedsuppress)
+ return FALSE
+ return ..()
+
+/mob/living/carbon/human/get_total_bleed_rate()
+ if(NOBLOOD in dna.species.species_traits)
+ return FALSE
+ return ..()
+
/mob/living/carbon/human/species
var/race = null
@@ -1185,6 +1199,9 @@
/mob/living/carbon/human/species/lizard
race = /datum/species/lizard
+/mob/living/carbon/human/species/ethereal
+ race = /datum/species/ethereal
+
/mob/living/carbon/human/species/lizard/ashwalker
race = /datum/species/lizard/ashwalker
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 79dd318b20..1673c57a80 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -34,6 +34,19 @@
protection += physiology.armor.getRating(d_type)
return protection
+///Get all the clothing on a specific body part
+/mob/living/carbon/human/proc/clothingonpart(obj/item/bodypart/def_zone)
+ var/list/covering_part = list()
+ var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id, wear_neck) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
+ for(var/bp in body_parts)
+ if(!bp)
+ continue
+ if(bp && istype(bp , /obj/item/clothing))
+ var/obj/item/clothing/C = bp
+ if(C.body_parts_covered & def_zone.body_part)
+ covering_part += C
+ return covering_part
+
/mob/living/carbon/human/on_hit(obj/item/projectile/P)
if(dna && dna.species)
dna.species.on_hit(P, src)
@@ -93,22 +106,23 @@
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src, attackchain_flags, damage_multiplier)
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
- . = ..(user, TRUE)
- if(.)
- return
- var/hulk_verb_continous = "smashes"
- var/hulk_verb_simple = "smash"
- if(prob(50))
- hulk_verb_continous = "pummels"
- hulk_verb_simple = "pummel"
- playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
- visible_message("[user] [hulk_verb_continous] [src]!", \
- "[user] [hulk_verb_continous] you!", null, COMBAT_MESSAGE_RANGE, null, user,
- "You [hulk_verb_simple] [src]!")
- adjustBruteLoss(15)
- return 1
+ if(user.a_intent == INTENT_HARM)
+ . = ..(user, TRUE)
+ if(.)
+ return
+ var/hulk_verb_continous = "smashes"
+ var/hulk_verb_simple = "smash"
+ if(prob(50))
+ hulk_verb_continous = "pummels"
+ hulk_verb_simple = "pummel"
+ playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
+ visible_message("[user] [hulk_verb_continous] [src]!", \
+ "[user] [hulk_verb_continous] you!", null, COMBAT_MESSAGE_RANGE, null, user,
+ "You [hulk_verb_simple] [src]!")
+ apply_damage(15, BRUTE, wound_bonus=10)
+ return 1
-/mob/living/carbon/human/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/mob/living/carbon/human/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.) //To allow surgery to return properly.
return
@@ -117,6 +131,9 @@
dna.species.spec_attack_hand(H, src, null, act_intent, unarmed_attack_flags)
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
+ if(!M.CheckActionCooldown(CLICK_CD_MELEE))
+ return
+ M.DelayNextAction()
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
@@ -216,16 +233,17 @@
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration)
- apply_damage(damage, M.melee_damage_type, affecting, armor)
-
+ apply_damage(damage, M.melee_damage_type, affecting, armor, wound_bonus = M.wound_bonus, bare_wound_bonus = M.bare_wound_bonus, sharpness = M.sharpness)
/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
. = ..()
if(!.) //unsuccessful slime attack
return
var/damage = rand(5, 25)
+ var/wound_mod = -45 // 25^1.4=90, 90-45=45
if(M.is_adult)
damage = rand(10, 35)
+ wound_mod = -90 // 35^1.4=145, 145-90=55
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
@@ -235,7 +253,7 @@
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor_block)
+ apply_damage(damage, BRUTE, affecting, armor_block, wound_bonus=wound_mod)
/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
if(M.occupant.a_intent == INTENT_HARM)
@@ -613,6 +631,20 @@
no_damage = TRUE
to_send += "\t Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].\n"
+ for(var/thing in LB.wounds)
+ var/datum/wound/W = thing
+ var/msg
+ switch(W.severity)
+ if(WOUND_SEVERITY_TRIVIAL)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]."
+ if(WOUND_SEVERITY_MODERATE)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!"
+ if(WOUND_SEVERITY_SEVERE)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!"
+ if(WOUND_SEVERITY_CRITICAL)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!"
+ to_chat(src, msg)
+
for(var/obj/item/I in LB.embedded_objects)
if(I.isEmbedHarmless())
to_chat(src, "\t There is \a [I] stuck to your [LB.name]!")
@@ -622,8 +654,25 @@
for(var/t in missing)
to_send += "Your [parse_zone(t)] is missing!\n"
- if(bleed_rate)
- to_send += "You are bleeding!\n"
+ if(is_bleeding())
+ var/list/obj/item/bodypart/bleeding_limbs = list()
+ for(var/i in bodyparts)
+ var/obj/item/bodypart/BP = i
+ if(BP.get_bleed_rate())
+ bleeding_limbs += BP
+
+ var/num_bleeds = LAZYLEN(bleeding_limbs)
+ var/bleed_text = "You are bleeding from your"
+ switch(num_bleeds)
+ if(1 to 2)
+ bleed_text += " [bleeding_limbs[1].name][num_bleeds == 2 ? " and [bleeding_limbs[2].name]" : ""]"
+ if(3 to INFINITY)
+ for(var/i in 1 to (num_bleeds - 1))
+ var/obj/item/bodypart/BP = bleeding_limbs[i]
+ bleed_text += " [BP.name],"
+ bleed_text += " and [bleeding_limbs[num_bleeds].name]"
+ bleed_text += "!"
+ to_chat(src, bleed_text)
if(getStaminaLoss())
if(getStaminaLoss() > 30)
to_send += "You're completely exhausted.\n"
@@ -716,6 +765,89 @@
..()
+/mob/living/carbon/human/check_self_for_injuries()
+ if(stat == DEAD || stat == UNCONSCIOUS)
+ return
+
+ visible_message("[src] examines [p_them()]self.", \
+ "You check yourself for injuries.")
+
+ var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/LB = X
+ missing -= LB.body_zone
+ if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
+ continue
+ var/self_aware = FALSE
+ if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
+ self_aware = TRUE
+ var/limb_max_damage = LB.max_damage
+ var/status = ""
+ var/brutedamage = LB.brute_dam
+ var/burndamage = LB.burn_dam
+ if(hallucination)
+ if(prob(30))
+ brutedamage += rand(30,40)
+ if(prob(30))
+ burndamage += rand(30,40)
+
+ if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
+ status = "[brutedamage] brute damage and [burndamage] burn damage"
+ if(!brutedamage && !burndamage)
+ status = "no damage"
+
+ else
+ if(brutedamage > 0)
+ status = LB.light_brute_msg
+ if(brutedamage > (limb_max_damage*0.4))
+ status = LB.medium_brute_msg
+ if(brutedamage > (limb_max_damage*0.8))
+ status = LB.heavy_brute_msg
+ if(brutedamage > 0 && burndamage > 0)
+ status += " and "
+
+ if(burndamage > (limb_max_damage*0.8))
+ status += LB.heavy_burn_msg
+ else if(burndamage > (limb_max_damage*0.2))
+ status += LB.medium_burn_msg
+ else if(burndamage > 0)
+ status += LB.light_burn_msg
+
+ if(status == "")
+ status = "OK"
+ var/no_damage
+ if(status == "OK" || status == "no damage")
+ no_damage = TRUE
+ var/isdisabled = " "
+ if(LB.is_disabled())
+ isdisabled = " is disabled "
+ if(no_damage)
+ isdisabled += " but otherwise "
+ else
+ isdisabled += " and "
+ to_chat(src, "\t Your [LB.name][isdisabled][self_aware ? " has " : " is "][status].")
+
+ for(var/thing in LB.wounds)
+ var/datum/wound/W = thing
+ var/msg
+ switch(W.severity)
+ if(WOUND_SEVERITY_TRIVIAL)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]."
+ if(WOUND_SEVERITY_MODERATE)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!"
+ if(WOUND_SEVERITY_SEVERE)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!"
+ if(WOUND_SEVERITY_CRITICAL)
+ msg = "\t Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!"
+ to_chat(src, msg)
+
+ for(var/obj/item/I in LB.embedded_objects)
+ if(I.isEmbedHarmless())
+ to_chat(src, "\t There is \a [I] stuck to your [LB.name]!")
+ else
+ to_chat(src, "\t There is \a [I] embedded in your [LB.name]!")
+
/mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
if(damage_type != BRUTE && damage_type != BURN)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index c72bfe044e..13456ed61c 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -51,7 +51,6 @@
var/special_voice = "" // For changing our voice. Used by a symptom.
- var/bleed_rate = 0 //how much are we bleeding
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
var/blood_state = BLOOD_STATE_NOT_BLOODY
@@ -103,7 +102,7 @@
"HUMAN_PARRY_MININUM_EFFICIENCY" = 0.9
)
-/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
+/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
var/datum/block_parry_data/D = return_block_parry_datum(block_parry_data)
if(!owner.Adjacent(attacker))
return ..()
@@ -111,7 +110,7 @@
return ..()
visible_message("[src] strikes back perfectly at [attacker], staggering them!")
if(D.parry_data["HUMAN_PARRY_PUNCH"])
- UnarmedAttack(attacker, TRUE, INTENT_HARM, UNARMED_ATTACK_PARRY)
+ UnarmedAttack(attacker, TRUE, INTENT_HARM, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_ACTION | ATTACK_IGNORE_CLICKDELAY | NO_AUTO_CLICKDELAY_HANDLING)
var/mob/living/L = attacker
if(istype(L))
L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"])
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 7c256f5367..af95b9e1b7 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -151,3 +151,32 @@
if(blood_dna.len)
last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
last_blood_DNA = blood_dna[blood_dna.len]*/
+
+/// For use formatting all of the scars this human has for saving for persistent scarring
+/mob/living/carbon/human/proc/format_scars()
+ var/list/missing_bodyparts = get_missing_limbs()
+ if(!all_scars && !length(missing_bodyparts))
+ return
+ var/scars = ""
+ for(var/i in missing_bodyparts)
+ var/datum/scar/scaries = new
+ scars += "[scaries.format_amputated(i)]"
+ for(var/i in all_scars)
+ var/datum/scar/scaries = i
+ scars += "[scaries.format()];"
+ return scars
+
+/// Takes a single scar from the persistent scar loader and recreates it from the saved data
+/mob/living/carbon/human/proc/load_scar(scar_line)
+ var/list/scar_data = splittext(scar_line, "|")
+ if(LAZYLEN(scar_data) != SCAR_SAVE_LENGTH)
+ return // invalid, should delete
+ var/version = text2num(scar_data[SCAR_SAVE_VERS])
+ if(!version || version < SCAR_CURRENT_VERSION) // get rid of old scars
+ return
+ var/obj/item/bodypart/the_part = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]")
+ var/datum/scar/scaries = new
+ return scaries.load(the_part, scar_data[SCAR_SAVE_VERS], scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]))
+
+/mob/living/carbon/human/get_biological_state()
+ return dna.species.get_biological_state()
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index d703f6a4e2..22cb10026b 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -91,6 +91,7 @@
return " (as [get_id_name("Unknown")])"
/mob/living/carbon/human/proc/forcesay(list/append) //this proc is at the bottom of the file because quote fuckery makes notepad++ cri
+ set waitfor = FALSE // WINGET IS A SLEEP. DO. NOT. SLEEP.
if(stat == CONSCIOUS)
if(client)
var/temp = winget(client, "input", "text")
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 7f883aafd4..54c3b314b9 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
var/limbs_id //this is used if you want to use a different species limb sprites. Mainly used for angels as they look like humans.
var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
- var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
+ var/default_color = "#FFFFFF" // if alien colors are disabled, this is the color that will be used by that race
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
var/has_field_of_vision = TRUE
@@ -56,6 +56,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/list/mutant_organs = list() //Internal organs that are unique to this race.
var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster
var/armor = 0 // overall defense for the race... or less defense, if it's negative.
+ var/attack_type = BRUTE // the type of damage unarmed attacks from this species do
var/brutemod = 1 // multiplier for brute damage
var/burnmod = 1 // multiplier for burn damage
var/coldmod = 1 // multiplier for cold damage
@@ -73,7 +74,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/datum/outfit/outfit_important_for_life // A path to an outfit that is important for species life e.g. plasmaman outfit
// species-only traits. Can be found in DNA.dm
- var/list/species_traits = list()
+ var/list/species_traits = list(HAS_FLESH,HAS_BONE) //by default they can scar and have bones/flesh unless set to something else
// generic traits tied to having the species
var/list/inherent_traits = list()
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
@@ -105,6 +106,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/whitelisted = 0 //Is this species restricted to certain players?
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
var/icon_limbs //Overrides the icon used for the limbs of this species. Mainly for downstream, and also because hardcoded icons disgust me. Implemented and maintained as a favor in return for a downstream's implementation of synths.
+ var/species_type
+
+ var/tail_type //type of tail i.e. mam_tail
+ var/wagging_type //type of wagging i.e. waggingtail_lizard
/// Our default override for typing indicator state
var/typing_indicator_state
@@ -113,14 +118,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// PROCS //
///////////
-
/datum/species/New()
if(!limbs_id) //if we havent set a limbs id to use, just use our own id
limbs_id = id
..()
-
/proc/generate_selectable_species(clear = FALSE)
if(clear)
GLOB.roundstart_races = list()
@@ -854,10 +857,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
var/list/colorlist = list()
var/husk = HAS_TRAIT(H, TRAIT_HUSK)
- colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor"]]0")
- colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor2"]]0")
- colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]0")
- colorlist += list(0,0,0, hair_alpha)
+ colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor"]]00")
+ colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor2"]]00")
+ colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]00")
+ colorlist += husk ? list(0, 0, 0) : list(0, 0, 0, hair_alpha)
for(var/index in 1 to colorlist.len)
colorlist[index] /= 255
@@ -1031,7 +1034,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_overlay(BODY_FRONT_LAYER)
H.apply_overlay(HORNS_LAYER)
-
/*
* Equip the outfit required for life. Replaces items currently worn.
*/
@@ -1062,7 +1064,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.adjustBruteLoss(1)
/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H)
- return
+ if(H)
+ stop_wagging_tail(H)
/datum/species/proc/auto_equip(mob/living/carbon/human/H)
// handles the equipping of species-specific gear
@@ -1285,9 +1288,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/check_weakness(obj/item, mob/living/attacker)
return FALSE
-////////
- //LIFE//
- ////////
+/////////////
+////LIFE////
+////////////
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
@@ -1362,6 +1365,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if(hungry >= 70)
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50))
+ else if(isethereal(H))
+ var/datum/species/ethereal/E = H.dna.species
+ if(E.get_charge(H) <= ETHEREAL_CHARGE_NORMAL)
+ H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - E.get_charge(H) / 100)))
else
H.remove_movespeed_modifier(/datum/movespeed_modifier/hunger)
@@ -1418,6 +1425,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// ATTACK PROCS //
//////////////////
+/datum/species/proc/spec_updatehealth(mob/living/carbon/human/H)
+ return
+
+/datum/species/proc/spec_fully_heal(mob/living/carbon/human/H)
+ return
+
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH))
target.help_shake_act(user)
@@ -1446,7 +1459,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.grabbedby(user)
return 1
-/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, unarmed_attack_flags = NONE)
+/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, attackchain_flags = NONE)
if(!attacker_style && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to harm [target]!")
return FALSE
@@ -1458,7 +1471,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target_message = "[target] blocks your attack!")
return FALSE
- if(!(unarmed_attack_flags & UNARMED_ATTACK_PARRY))
+ if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
user.adjustStaminaLossBuffered(1.5)
else
@@ -1490,17 +1503,17 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//CITADEL CHANGES - makes resting and disabled combat mode reduce punch damage, makes being out of combat mode result in you taking more damage
if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- damage *= 1.5
+ damage *= 1.2
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
- damage *= 0.5
+ damage *= 0.8
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- damage *= 0.25
+ damage *= 0.8
//END OF CITADEL CHANGES
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
- if(unarmed_attack_flags & UNARMED_ATTACK_PARRY)
+ if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
miss_chance = 0
else
if(user.dna.species.punchdamagelow)
@@ -1536,11 +1549,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.dismembering_strike(user, affecting.body_zone)
if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage + 0.5x stamina damage
- target.apply_damage(damage*1.5, BRUTE, affecting, armor_block)
+ target.apply_damage(damage*1.5, attack_type, affecting, armor_block)
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
log_combat(user, target, "kicked")
else//other attacks deal full raw damage + 2x in stamina damage
- target.apply_damage(damage, BRUTE, affecting, armor_block)
+ target.apply_damage(damage, attack_type, affecting, armor_block)
target.apply_damage(damage*2, STAMINA, affecting, armor_block)
log_combat(user, target, "punched")
@@ -1687,7 +1700,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
return
-/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
+/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, attackchain_flags)
if(!istype(M))
return
CHECK_DNA_AND_SPECIES(M)
@@ -1707,7 +1720,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
grab(M, H, attacker_style)
if("harm")
- harm(M, H, attacker_style, unarmed_attack_flags)
+ harm(M, H, attacker_style, attackchain_flags)
if("disarm")
disarm(M, H, attacker_style)
@@ -1717,7 +1730,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// Allows you to put in item-specific reactions based on species
if(user != H)
var/list/block_return = list()
- if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
+ if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
return 0
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
if(H.check_martial_melee_block())
@@ -1734,24 +1747,23 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/armor_block = H.run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].",I.armour_penetration)
armor_block = min(90,armor_block) //cap damage reduction at 90%
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
+ var/Iwound_bonus = I.wound_bonus
+
+ // this way, you can't wound with a surgical tool on help intent if they have a surgery active and are laying down, so a misclick with a circular saw on the wrong limb doesn't bleed them dry (they still get hit tho)
+ if((I.item_flags & SURGICAL_TOOL) && user.a_intent == INTENT_HELP && (H.mobility_flags & ~MOBILITY_STAND) && (LAZYLEN(H.surgeries) > 0))
+ Iwound_bonus = CANT_WOUND
var/weakness = H.check_weakness(I, user)
- apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage
+ apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H, wound_bonus = Iwound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness())
- H.send_item_attack_message(I, user, hit_area, totitemdamage)
+
+ H.send_item_attack_message(I, user, hit_area, affecting, totitemdamage)
I.do_stagger_action(H, user, totitemdamage)
if(!totitemdamage)
return 0 //item force is zero
- //dismemberment
- var/probability = I.get_dismemberment_chance(affecting)
- if(prob(probability) || (HAS_TRAIT(H, TRAIT_EASYDISMEMBER) && prob(probability))) //try twice
- if(affecting.dismember(I.damtype))
- I.add_mob_blood(H)
- playsound(get_turf(H), I.get_dismember_sound(), 80, 1)
-
var/bloody = 0
if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2))))
if(affecting.status == BODYPART_ORGANIC)
@@ -1822,6 +1834,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return TRUE
CHECK_DNA_AND_SPECIES(M)
CHECK_DNA_AND_SPECIES(H)
+ if(!M.CheckActionCooldown())
+ return
+ M.DelayNextAction(CLICK_CD_MELEE)
if(!istype(M)) //sanity check for drones.
return TRUE
@@ -1931,11 +1946,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.visible_message("[user.name] shoves [target.name]!",
"[user.name] shoves you!", null, COMBAT_MESSAGE_RANGE, null,
user, "You shove [target.name]!")
+ target.Stagger(SHOVE_STAGGER_DURATION)
var/obj/item/target_held_item = target.get_active_held_item()
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null
- if(!target.has_movespeed_modifier(/datum/movespeed_modifier/shove))
- target.add_movespeed_modifier(/datum/movespeed_modifier/shove)
+ if(!target.has_status_effect(STATUS_EFFECT_OFF_BALANCE))
if(target_held_item)
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
target.visible_message("[target.name]'s grip on \the [target_held_item] loosens!",
@@ -1943,16 +1958,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
append_message += ", loosening their grip on [target_held_item]"
else
append_message += ", but couldn't loose their grip on [target_held_item]"
- addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
else if(target_held_item)
if(target.dropItemToGround(target_held_item))
target.visible_message("[target.name] drops \the [target_held_item]!!",
"You drop \the [target_held_item]!!", null, COMBAT_MESSAGE_RANGE)
append_message += ", causing them to drop [target_held_item]"
+ target.ShoveOffBalance(SHOVE_OFFBALANCE_DURATION)
log_combat(user, target, "shoved", append_message)
-/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE)
- SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
+/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
+ SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal
var/hit_percent = (100-(blocked+armor))/100
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
if(!forced && hit_percent <= 0)
@@ -1979,7 +1994,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.damageoverlaytemp = 20
var/damage_amount = forced ? damage : damage * hit_percent * brutemod * H.physiology.brute_mod
if(BP)
- if(damage > 0 ? BP.receive_damage(damage_amount, 0) : BP.heal_damage(abs(damage_amount), 0))
+ if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
H.update_damage_overlays()
if(HAS_TRAIT(H, TRAIT_MASO) && prob(damage_amount))
H.mob_climax(forced_climax=TRUE)
@@ -1990,7 +2005,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.damageoverlaytemp = 20
var/damage_amount = forced ? damage : damage * hit_percent * burnmod * H.physiology.burn_mod
if(BP)
- if(damage > 0 ? BP.receive_damage(0, damage_amount) : BP.heal_damage(0, abs(damage_amount)))
+ if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
H.update_damage_overlays()
else
H.adjustFireLoss(damage_amount)
@@ -2027,6 +2042,25 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// called before a projectile hit
return
+/**
+
+
+
+ * The human species version of [/mob/living/carbon/proc/get_biological_state]. Depends on the HAS_FLESH and HAS_BONE species traits, having bones lets you have bone wounds, having flesh lets you have burn, slash, and piercing wounds
+
+
+
+ */
+
+
+
+/datum/species/proc/get_biological_state(mob/living/carbon/human/H)
+ . = BIO_INORGANIC
+ if(HAS_FLESH in species_traits)
+ . |= BIO_JUST_FLESH
+ if(HAS_BONE in species_traits)
+ . |= BIO_JUST_BONE
+
/////////////
//BREATHING//
/////////////
@@ -2220,12 +2254,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/ExtinguishMob(mob/living/carbon/human/H)
return
-
////////////
//Stun//
////////////
/datum/species/proc/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ stop_wagging_tail(H)
+
. = stunmod * H.physiology.stun_mod * amount
//////////////
@@ -2243,11 +2279,30 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
////////////////
/datum/species/proc/can_wag_tail(mob/living/carbon/human/H)
- return FALSE
+ if(!tail_type || !wagging_type)
+ return FALSE
+ else
+ return mutant_bodyparts[tail_type] || mutant_bodyparts[wagging_type]
/datum/species/proc/is_wagging_tail(mob/living/carbon/human/H)
- return FALSE
+ return mutant_bodyparts[wagging_type]
/datum/species/proc/start_wagging_tail(mob/living/carbon/human/H)
+ if(tail_type && wagging_type)
+ if(mutant_bodyparts[tail_type])
+ mutant_bodyparts[wagging_type] = mutant_bodyparts[tail_type]
+ mutant_bodyparts -= tail_type
+ if(tail_type == "tail_lizard") //special lizard thing
+ mutant_bodyparts["waggingspines"] = mutant_bodyparts["spines"]
+ mutant_bodyparts -= "spines"
+ H.update_body()
/datum/species/proc/stop_wagging_tail(mob/living/carbon/human/H)
+ if(tail_type && wagging_type)
+ if(mutant_bodyparts[wagging_type])
+ mutant_bodyparts[tail_type] = mutant_bodyparts[wagging_type]
+ mutant_bodyparts -= wagging_type
+ if(tail_type == "tail_lizard") //special lizard thing
+ mutant_bodyparts["spines"] = mutant_bodyparts["waggingspines"]
+ mutant_bodyparts -= "waggingspines"
+ H.update_body()
diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm
index 0899038da4..38e10e8662 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -3,9 +3,10 @@
id = "abductor"
say_mod = "gibbers"
sexes = FALSE
- species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
+ species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_CHUNKYFINGERS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
mutanttongue = /obj/item/organ/tongue/abductor
+ species_type = "alien"
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm
index 94f64ceacb..c5b57b82ab 100644
--- a/code/modules/mob/living/carbon/human/species_types/android.dm
+++ b/code/modules/mob/living/carbon/human/species_types/android.dm
@@ -11,6 +11,7 @@
mutanttongue = /obj/item/organ/tongue/robot
species_language_holder = /datum/language_holder/synthetic
limbs_id = "synth"
+ species_type = "robotic"
/datum/species/android/on_species_gain(mob/living/carbon/C)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/angel.dm b/code/modules/mob/living/carbon/human/species_types/angel.dm
index 1a92da3b0a..2cf054c7b9 100644
--- a/code/modules/mob/living/carbon/human/species_types/angel.dm
+++ b/code/modules/mob/living/carbon/human/species_types/angel.dm
@@ -2,13 +2,14 @@
name = "Angel"
id = "angel"
default_color = "FFFFFF"
- species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
+ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "wings" = "Angel")
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
no_equip = list(SLOT_BACK)
blacklisted = 1
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
+ species_type = "human" //they're a kind of human
var/datum/action/innate/flight/fly
diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
index a79f9e2392..2a955e28a4 100644
--- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
@@ -3,9 +3,9 @@
id = "insect"
say_mod = "chitters"
default_color = "00FF00"
- species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR)
+ species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
- mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
+ mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None",
"insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None", "insect_markings" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
@@ -17,32 +17,6 @@
exotic_bloodtype = "BUG"
exotic_blood_color = BLOOD_COLOR_BUG
-/datum/species/insect/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/insect/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/insect/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/insect/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/insect/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_tail"])
- mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
- mutant_bodyparts -= "mam_tail"
- H.update_body()
-
-/datum/species/insect/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_waggingtail"])
- mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
- mutant_bodyparts -= "mam_waggingtail"
- H.update_body()
-
-/datum/species/insect/qualifies_for_rank(rank, list/features)
- return TRUE
+ tail_type = "mam_tail"
+ wagging_type = "mam_waggingtail"
+ species_type = "insect"
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm
index e062e1cbf7..a2597ed286 100644
--- a/code/modules/mob/living/carbon/human/species_types/corporate.dm
+++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm
@@ -17,4 +17,5 @@
species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS)
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER)
sexes = 0
- gib_types = /obj/effect/gibspawner/robot
\ No newline at end of file
+ gib_types = /obj/effect/gibspawner/robot
+ species_type = "robotic"
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index 1d19f28aa8..d8dfe63b35 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -2,7 +2,7 @@
name = "Dullahan"
id = "dullahan"
default_color = "FFFFFF"
- species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
+ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "deco_wings" = "None")
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
@@ -14,6 +14,7 @@
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head.
+ species_type = "undead"
var/pumpkin = FALSE
var/obj/item/dullahan_relay/myhead
diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
index 7ca057711e..a465e7c3a9 100644
--- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
@@ -6,7 +6,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
name = "Dwarf"
id = "dwarf" //Also called Homo sapiens pumilionis
default_color = "FFFFFF"
- species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
+ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_DWARF,TRAIT_SNOB)
limbs_id = "human"
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
@@ -18,6 +18,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
mutant_organs = list(/obj/item/organ/dwarfgland) //Dwarven alcohol gland, literal gland warrior
mutantliver = /obj/item/organ/liver/dwarf //Dwarven super liver (Otherwise they r doomed)
species_language_holder = /datum/language_holder/dwarf
+ species_type = "human" //a kind of human
/mob/living/carbon/human/species/dwarf //species admin spawn path
race = /datum/species/dwarf //and the race the path is set to.
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
new file mode 100644
index 0000000000..27338f598f
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -0,0 +1,182 @@
+#define ETHEREAL_COLORS list("#00ffff", "#ffc0cb", "#9400D3", "#4B0082", "#0000FF", "#00FF00", "#FFFF00", "#FF7F00", "#FF0000")
+
+/datum/species/ethereal
+ name = "Ethereal"
+ id = "ethereal"
+ attack_verb = "burn"
+ attack_sound = 'sound/weapons/etherealhit.ogg'
+ miss_sound = 'sound/weapons/etherealmiss.ogg'
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ethereal
+ mutantstomach = /obj/item/organ/stomach/ethereal
+ mutanttongue = /obj/item/organ/tongue/ethereal
+ exotic_blood = /datum/reagent/consumable/liquidelectricity //Liquid Electricity. fuck you think of something better gamer
+ siemens_coeff = 0.5 //They thrive on energy
+ brutemod = 1.25 //They're weak to punches
+ attack_type = BURN //burn bish
+ damage_overlay_type = "" //We are too cool for regular damage overlays
+ species_traits = list(MUTCOLORS, NO_UNDERWEAR, HAIR, HAS_FLESH, HAS_BONE) // i mean i guess they have blood so they can have wounds too
+ species_language_holder = /datum/language_holder/ethereal
+ inherent_traits = list(TRAIT_NOHUNGER)
+ sexes = FALSE
+ toxic_food = NONE
+ /*
+ citadel doesn't have per-species temperatures, yet
+ // Body temperature for ethereals is much higher then humans as they like hotter environments
+ bodytemp_normal = (BODYTEMP_NORMAL + 50)
+ bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // about 150C
+ // Cold temperatures hurt faster as it is harder to move with out the heat energy
+ bodytemp_cold_damage_limit = (T20C - 10) // about 10c
+ */
+ hair_color = "fixedmutcolor"
+ hair_alpha = 140
+ var/current_color
+ var/EMPeffect = FALSE
+ var/emageffect = FALSE
+ var/r1
+ var/g1
+ var/b1
+ var/static/r2 = 237
+ var/static/g2 = 164
+ var/static/b2 = 149
+ //this is shit but how do i fix it? no clue.
+ var/drain_time = 0 //used to keep ethereals from spam draining power sources
+
+/datum/species/ethereal/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
+ .=..()
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ default_color = "#" + H.dna.features["mcolor"]
+ r1 = GETREDPART(default_color)
+ g1 = GETGREENPART(default_color)
+ b1 = GETBLUEPART(default_color)
+ spec_updatehealth(H)
+ RegisterSignal(C, COMSIG_ATOM_EMAG_ACT, .proc/on_emag_act)
+ RegisterSignal(C, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act)
+
+/datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
+ .=..()
+ C.set_light(0)
+ UnregisterSignal(C, COMSIG_ATOM_EMAG_ACT)
+ UnregisterSignal(C, COMSIG_ATOM_EMP_ACT)
+
+/datum/species/ethereal/random_name(gender,unique,lastname)
+ if(unique)
+ return random_unique_ethereal_name()
+
+ var/randname = ethereal_name()
+
+ return randname
+
+/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H)
+ .=..()
+ if(H.stat != DEAD && !EMPeffect)
+ var/healthpercent = max(H.health, 0) / 100
+ if(!emageffect)
+ current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent))
+ H.set_light(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color)
+ fixed_mut_color = copytext_char(current_color, 2)
+ else
+ H.set_light(0)
+ fixed_mut_color = rgb(128,128,128)
+ H.update_body()
+
+/datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/H, severity)
+ EMPeffect = TRUE
+ spec_updatehealth(H)
+ to_chat(H, "You feel the light of your body leave you.")
+ switch(severity)
+ if(EMP_LIGHT)
+ addtimer(CALLBACK(src, .proc/stop_emp, H), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds
+ if(EMP_HEAVY)
+ addtimer(CALLBACK(src, .proc/stop_emp, H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds
+
+/datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user)
+ if(emageffect)
+ return
+ emageffect = TRUE
+ if(user)
+ to_chat(user, "You tap [H] on the back with your card.")
+ H.visible_message("[H] starts flickering in an array of colors!")
+ handle_emag(H)
+ addtimer(CALLBACK(src, .proc/stop_emag, H), 30 SECONDS) //Disco mode for 30 seconds! This doesn't affect the ethereal at all besides either annoying some players, or making someone look badass.
+
+
+/datum/species/ethereal/spec_life(mob/living/carbon/human/H)
+ .=..()
+ handle_charge(H)
+
+
+/datum/species/ethereal/proc/stop_emp(mob/living/carbon/human/H)
+ EMPeffect = FALSE
+ spec_updatehealth(H)
+ to_chat(H, "You feel more energized as your shine comes back.")
+
+
+/datum/species/ethereal/proc/handle_emag(mob/living/carbon/human/H)
+ if(!emageffect)
+ return
+ current_color = pick(ETHEREAL_COLORS)
+ spec_updatehealth(H)
+ addtimer(CALLBACK(src, .proc/handle_emag, H), 5) //Call ourselves every 0.5 seconds to change color
+
+/datum/species/ethereal/proc/stop_emag(mob/living/carbon/human/H)
+ emageffect = FALSE
+ spec_updatehealth(H)
+ H.visible_message("[H] stops flickering and goes back to their normal state!")
+
+/datum/species/ethereal/proc/handle_charge(mob/living/carbon/human/H)
+ brutemod = 1.25
+ switch(get_charge(H))
+ if(ETHEREAL_CHARGE_NONE)
+ H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 3)
+ if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER)
+ H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 2)
+ if(H.health > 10.5)
+ apply_damage(0.65, TOX, null, null, H)
+ brutemod = 1.75
+ if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
+ H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 1)
+ brutemod = 1.5
+ if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD)
+ H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 1)
+ apply_damage(0.2, TOX, null, null, H)
+ brutemod = 1.5
+ if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
+ H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 2)
+ apply_damage(0.65, TOX, null, null, H)
+ brutemod = 1.75
+ if(prob(10)) //10% each tick for ethereals to explosively release excess energy if it reaches dangerous levels
+ discharge_process(H)
+ else
+ H.clear_alert("ethereal_charge")
+ H.clear_alert("ethereal_overcharge")
+
+/datum/species/ethereal/proc/discharge_process(mob/living/carbon/human/H)
+ to_chat(H, "You begin to lose control over your charge!")
+ H.visible_message("[H] begins to spark violently!")
+ var/static/mutable_appearance/overcharge //shameless copycode from lightning spell
+ overcharge = overcharge || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER)
+ H.add_overlay(overcharge)
+ if(do_mob(H, H, 50, 1))
+ H.flash_lighting_fx(5, 7, current_color)
+ var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
+ playsound(H, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
+ H.cut_overlay(overcharge)
+ tesla_zap(H, 2, stomach.crystal_charge*50, ZAP_OBJ_DAMAGE | ZAP_ALLOW_DUPLICATES)
+ if(istype(stomach))
+ stomach.adjust_charge(100 - stomach.crystal_charge)
+ to_chat(H, "You violently discharge energy!")
+ H.visible_message("[H] violently discharges energy!")
+ if(prob(10)) //chance of developing heart disease to dissuade overcharging oneself
+ var/datum/disease/D = new /datum/disease/heart_failure
+ H.ForceContractDisease(D)
+ to_chat(H, "You're pretty sure you just felt your heart stop for a second there..")
+ H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, 0)
+ H.Paralyze(100)
+ return
+
+/datum/species/ethereal/proc/get_charge(mob/living/carbon/H) //this feels like it should be somewhere else. Eh?
+ var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
+ if(istype(stomach))
+ return stomach.crystal_charge
+ return ETHEREAL_CHARGE_NONE
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index 2f0595e2c0..b760fd0aee 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -9,37 +9,9 @@
mutantears = /obj/item/organ/ears/cat
mutanttail = /obj/item/organ/tail/cat
-/datum/species/human/felinid/qualifies_for_rank(rank, list/features)
- return TRUE
-
-//Curiosity killed the cat's wagging tail.
-/datum/species/human/felinid/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/human/felinid/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-
-/datum/species/human/felinid/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/human/felinid/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/human/felinid/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_tail"])
- mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
- mutant_bodyparts -= "mam_tail"
- H.update_body()
-
-/datum/species/human/felinid/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_waggingtail"])
- mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
- mutant_bodyparts -= "mam_waggingtail"
- H.update_body()
+ tail_type = "mam_tail"
+ wagging_type = "mam_waggingtail"
+ species_type = "furry"
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
if(ishuman(C))
diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
index dbf097196d..c56adaf1b0 100644
--- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
@@ -2,7 +2,7 @@
name = "Anthromorphic Fly"
id = "fly"
say_mod = "buzzes"
- species_traits = list(NOEYES)
+ species_traits = list(NOEYES,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
mutanttongue = /obj/item/organ/tongue/fly
mutantliver = /obj/item/organ/liver/fly
@@ -12,6 +12,7 @@
liked_food = GROSS
exotic_bloodtype = "BUG"
exotic_blood_color = BLOOD_COLOR_BUG
+ species_type = "insect"
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
if(istype(chem, /datum/reagent/toxin/pestkiller))
diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index b6d56b8e5d..7706d4a9d5 100644
--- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -3,9 +3,9 @@
id = "mammal"
default_color = "4B4B4B"
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BEAST
- mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
+ mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
"mam_body_markings" = "Husky", "taur" = "None", "horns" = "None", "legs" = "Plantigrade", "meat_type" = "Mammalian")
attack_verb = "claw"
attack_sound = 'sound/weapons/slash.ogg'
@@ -14,67 +14,6 @@
liked_food = MEAT | FRIED
disliked_food = TOXIC
-//Curiosity killed the cat's wagging tail.
-/datum/species/mammal/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/mammal/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/mammal/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/mammal/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/mammal/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_tail"])
- mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
- mutant_bodyparts -= "mam_tail"
- H.update_body()
-
-/datum/species/mammal/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_waggingtail"])
- mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
- mutant_bodyparts -= "mam_waggingtail"
- H.update_body()
-
-
-/datum/species/mammal/qualifies_for_rank(rank, list/features)
- return TRUE
-
-
-//Alien//
-/datum/species/xeno
- // A cloning mistake, crossing human and xenomorph DNA
- name = "Xenomorph Hybrid"
- id = "xeno"
- say_mod = "hisses"
- default_color = "00FF00"
- icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS)
- mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade")
- attack_verb = "slash"
- attack_sound = 'sound/weapons/slash.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
- gib_types = list(/obj/effect/gibspawner/xeno/xenoperson, /obj/effect/gibspawner/xeno/xenoperson/bodypartless)
- skinned_type = /obj/item/stack/sheet/animalhide/xeno
- exotic_bloodtype = "X*"
- damage_overlay_type = "xeno"
- liked_food = MEAT
-
-//Praise the Omnissiah, A challange worthy of my skills - HS
-
-//EXOTIC//
-//These races will likely include lots of downsides and upsides. Keep them relatively balanced.//
-
-//misc
-/mob/living/carbon/human/dummy
- vore_flags = NO_VORE
-
-/mob/living/carbon/human/vore
- vore_flags = DEVOURABLE | DIGESTABLE | FEEDING
+ tail_type = "mam_tail"
+ wagging_type = "mam_waggingtail"
+ species_type = "furry"
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 7100caf178..438eaf1eea 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -32,6 +32,8 @@
var/special_name_chance = 5
var/owner //dobby is a free golem
+ species_type = "golem"
+
/datum/species/golem/random_name(gender,unique,lastname)
var/golem_surname = pick(GLOB.golem_names)
// 3% chance that our golem has a human surname, because
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index 606b7a8bfd..f175ddb921 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -3,15 +3,16 @@
id = "human"
default_color = "FFFFFF"
- species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR)
- mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
+ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR,HAS_FLESH,HAS_BONE)
+ mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
skinned_type = /obj/item/stack/sheet/animalhide/human
disliked_food = GROSS | RAW
liked_food = JUNKFOOD | FRIED
-/datum/species/human/qualifies_for_rank(rank, list/features)
- return TRUE //Pure humans are always allowed in all roles.
+ tail_type = "tail_human"
+ wagging_type = "waggingtail_human"
+ species_type = "human"
/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
@@ -21,21 +22,3 @@
if(H)
stop_wagging_tail(H)
. = ..()
-
-/datum/species/human/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["tail_human"] || mutant_bodyparts["waggingtail_human"]
-
-/datum/species/human/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["waggingtail_human"]
-
-/datum/species/human/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["tail_human"])
- mutant_bodyparts["waggingtail_human"] = mutant_bodyparts["tail_human"]
- mutant_bodyparts -= "tail_human"
- H.update_body()
-
-/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["waggingtail_human"])
- mutant_bodyparts["tail_human"] = mutant_bodyparts["waggingtail_human"]
- mutant_bodyparts -= "waggingtail_human"
- H.update_body()
diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm
index 96efaebd74..3aef14c256 100644
--- a/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -6,7 +6,7 @@
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
blacklisted = 0
sexes = 0
- species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING)
+ species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
mutant_bodyparts = list("ipc_screen" = "Blank", "ipc_antenna" = "None")
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
@@ -21,6 +21,7 @@
exotic_bloodtype = "HF"
exotic_blood_color = BLOOD_COLOR_OIL
+ species_type = "robotic"
var/datum/action/innate/monitor_change/screen
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 31f326fd53..c762a52ffc 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -4,10 +4,10 @@
id = "jelly"
default_color = "00FF90"
say_mod = "chirps"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR,HAS_FLESH)
mutantlungs = /obj/item/organ/lungs/slime
mutant_heart = /obj/item/organ/heart/slime
- mutant_bodyparts = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
+ mutant_bodyparts = list("mcolor" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
inherent_traits = list(TRAIT_TOXINLOVER)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
@@ -25,6 +25,10 @@
species_language_holder = /datum/language_holder/jelly
mutant_brain = /obj/item/organ/brain/jelly
+ tail_type = "mam_tail"
+ wagging_type = "mam_waggingtail"
+ species_type = "jelly"
+
/obj/item/organ/brain/jelly
name = "slime nucleus"
desc = "A slimey membranous mass from a slime person"
@@ -128,33 +132,6 @@
return
to_chat(H, "...but there is not enough of you to go around! You must attain more mass to heal!")
-/datum/species/jelly/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/jelly/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/jelly/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/jelly/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/jelly/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_tail"])
- mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
- mutant_bodyparts -= "mam_tail"
- H.update_body()
-
-/datum/species/jelly/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_waggingtail"])
- mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
- mutant_bodyparts -= "mam_waggingtail"
- H.update_body()
-
////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
@@ -310,11 +287,16 @@
else
ui_interact(owner)
-/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
+/datum/action/innate/swap_body/ui_host(mob/user)
+ return owner
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/action/innate/swap_body/ui_state(mob/user)
+ return GLOB.not_incapacitated_state
+
+/datum/action/innate/swap_body/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "SlimeBodySwapper", name, 400, 400, master_ui, state)
+ ui = new(user, src, "SlimeBodySwapper", name)
ui.open()
/datum/action/innate/swap_body/ui_data(mob/user)
@@ -384,7 +366,8 @@
return
switch(action)
if("swap")
- var/mob/living/carbon/human/selected = locate(params["ref"])
+ var/datum/species/jelly/slime/SS = H.dna.species
+ var/mob/living/carbon/human/selected = locate(params["ref"]) in SS.bodies
if(!can_swap(selected))
return
SStgui.close_uis(src)
@@ -443,7 +426,7 @@
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
inherent_traits = list(TRAIT_TOXINLOVER)
- mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
+ mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
say_mod = "says"
hair_color = "mutcolor"
hair_alpha = 160 //a notch brighter so it blends better.
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index c42e0bf175..d768788e87 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -4,7 +4,7 @@
id = "lizard"
say_mod = "hisses"
default_color = "00FF00"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings")
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE
mutanttongue = /obj/item/organ/tongue/lizard
@@ -27,6 +27,10 @@
inert_mutation = FIREBREATH
species_language_holder = /datum/language_holder/lizard
+ tail_type = "tail_lizard"
+ wagging_type = "waggingtail_lizard"
+ species_type = "lizard"
+
/datum/species/lizard/random_name(gender,unique,lastname)
if(unique)
return random_unique_lizard_name(gender)
@@ -38,41 +42,6 @@
return randname
-/datum/species/lizard/qualifies_for_rank(rank, list/features)
- return TRUE
-
-//I wag in death
-/datum/species/lizard/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/lizard/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/lizard/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["tail_lizard"] || mutant_bodyparts["waggingtail_lizard"]
-
-/datum/species/lizard/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["waggingtail_lizard"]
-
-/datum/species/lizard/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["tail_lizard"])
- mutant_bodyparts["waggingtail_lizard"] = mutant_bodyparts["tail_lizard"]
- mutant_bodyparts["waggingspines"] = mutant_bodyparts["spines"]
- mutant_bodyparts -= "tail_lizard"
- mutant_bodyparts -= "spines"
- H.update_body()
-
-/datum/species/lizard/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["waggingtail_lizard"])
- mutant_bodyparts["tail_lizard"] = mutant_bodyparts["waggingtail_lizard"]
- mutant_bodyparts["spines"] = mutant_bodyparts["waggingspines"]
- mutant_bodyparts -= "waggingtail_lizard"
- mutant_bodyparts -= "waggingspines"
- H.update_body()
-
/*
Lizard subspecies: ASHWALKERS
*/
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index dcb6d868fc..f91c3518a3 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -8,7 +8,7 @@
nojumpsuit = TRUE
say_mod = "poofs" //what does a mushroom sound like
- species_traits = list(MUTCOLORS, NOEYES, NO_UNDERWEAR,NOGENITALS,NOAROUSAL)
+ species_traits = list(MUTCOLORS, NOEYES, NO_UNDERWEAR,NOGENITALS,NOAROUSAL,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOBREATH)
speedmod = 1.5 //faster than golems but not by much
@@ -21,6 +21,8 @@
burnmod = 1.25
heatmod = 1.5
+ species_type = "plant"
+
mutanteyes = /obj/item/organ/eyes/night_vision/mushroom
var/datum/martial_art/mushpunch/mush
species_language_holder = /datum/language_holder/mushroom
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 91d3135ae1..b61e29b685 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -4,7 +4,7 @@
say_mod = "rattles"
sexes = 0
meat = /obj/item/stack/sheet/mineral/plasma
- species_traits = list(NOBLOOD,NOTRANSSTING,NOGENITALS)
+ species_traits = list(NOBLOOD,NOTRANSSTING,NOGENITALS,HAS_BONE)
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_NOHUNGER,TRAIT_CALCIUM_HEALER)
inherent_biotypes = MOB_HUMANOID|MOB_MINERAL
mutantlungs = /obj/item/organ/lungs/plasmaman
@@ -22,6 +22,8 @@
liked_food = VEGETABLES
outfit_important_for_life = /datum/outfit/plasmaman
+ species_type = "skeleton"
+
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
var/datum/gas_mixture/environment = H.loc.return_air()
var/atmos_sealed = FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index e79160da06..f5a2f807e4 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -3,7 +3,7 @@
name = "Anthromorphic Plant"
id = "pod"
default_color = "59CE00"
- species_traits = list(MUTCOLORS,EYECOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE)
attack_verb = "slash"
attack_sound = 'sound/weapons/slice.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -19,6 +19,8 @@
var/light_burnheal = -1
var/light_bruteheal = -1
+ species_type = "plant"
+
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
C.faction |= "plants"
@@ -64,36 +66,12 @@
name = "Anthromorphic Plant"
id = "podweak"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
- mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
+ mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
limbs_id = "pod"
light_nutrition_gain_factor = 3
light_bruteheal = -0.2
light_burnheal = -0.2
light_toxheal = -0.7
-/datum/species/pod/pseudo_weak/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/pod/pseudo_weak/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/pod/pseudo_weak/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/pod/pseudo_weak/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/pod/pseudo_weak/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_tail"])
- mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
- mutant_bodyparts -= "mam_tail"
- H.update_body()
-
-/datum/species/pod/pseudo_weak/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_waggingtail"])
- mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
- mutant_bodyparts -= "mam_waggingtail"
- H.update_body()
+ tail_type = "mam_tail"
+ wagging_type = "mam_waggingtail"
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index fede67b47a..b760af9850 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -9,12 +9,14 @@
blacklisted = 1
ignored_by = list(/mob/living/simple_animal/hostile/faithless)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/shadow
- species_traits = list(NOBLOOD,NOEYES)
+ species_traits = list(NOBLOOD,NOEYES,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_NOBREATH)
dangerous_existence = 1
mutanteyes = /obj/item/organ/eyes/night_vision
+ species_type = "shadow"
+
/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
C.AddElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
@@ -164,7 +166,7 @@
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
item_flags = ABSTRACT | DROPDEL
w_class = WEIGHT_CLASS_HUGE
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/light_eater/Initialize()
@@ -183,6 +185,8 @@
T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
else if(isliving(AM))
var/mob/living/L = AM
+ if(isethereal(AM))
+ AM.emp_act(EMP_LIGHT)
if(iscyborg(AM))
var/mob/living/silicon/robot/borg = AM
if(borg.lamp_intensity)
diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
index 78efddf70d..51d81bd4d3 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -5,7 +5,7 @@
blacklisted = 0
sexes = 0
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
- species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
+ species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,HAS_BONE)
inherent_traits = list(TRAIT_NOBREATH,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
mutanttongue = /obj/item/organ/tongue/bone
@@ -15,6 +15,8 @@
brutemod = 1.25
burnmod = 1.25
+ species_type = "skeleton" //they have their own category that's disassociated from undead, paired with plasmapeople
+
/datum/species/skeleton/New()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season!
inherent_traits |= list(TRAIT_RESISTHEAT,TRAIT_RESISTCOLD)
diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm
index af2e83ee0f..5ed806b302 100644
--- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm
@@ -4,7 +4,7 @@
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
say_mod = "beeps"
default_color = "00FF00"
- species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR)
+ species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
mutant_bodyparts = list("ipc_antenna" = "Synthetic Lizard - Antennae","mam_tail" = "Synthetic Lizard", "mam_snouts" = "Synthetic Lizard - Snout", "legs" = "Digitigrade", "mam_body_markings" = "Synthetic Lizard - Plates", "taur" = "None")
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
@@ -20,33 +20,6 @@
exotic_bloodtype = "S"
exotic_blood_color = BLOOD_COLOR_OIL
-/datum/species/synthliz/qualifies_for_rank(rank, list/features)
- return TRUE
-
-//I wag in death
-/datum/species/synthliz/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/synthliz/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/synthliz/can_wag_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/synthliz/is_wagging_tail(mob/living/carbon/human/H)
- return mutant_bodyparts["mam_waggingtail"]
-
-/datum/species/synthliz/start_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_tail"])
- mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
- mutant_bodyparts -= "mam_tail"
- H.update_body()
-
-/datum/species/synthliz/stop_wagging_tail(mob/living/carbon/human/H)
- if(mutant_bodyparts["mam_waggingtail"])
- mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
- mutant_bodyparts -= "mam_waggingtail"
- H.update_body()
+ tail_type = "mam_tail"
+ wagging_type = "mam_waggingtail"
+ species_type = "robotic"
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index 85f1fbf386..a1a2a33c54 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -17,6 +17,7 @@
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
species_language_holder = /datum/language_holder/synthetic
+ species_type = "robotic"
/datum/species/synth/military
name = "Military Synth"
@@ -43,7 +44,6 @@
return TRUE
return ..()
-
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
if(S && !istype(S, type))
name = S.name
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index f720aa7f8a..723c4848fe 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -2,10 +2,10 @@
name = "Vampire"
id = "vampire"
default_color = "FFFFFF"
- species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD)
+ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
- mutant_bodyparts = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
+ mutant_bodyparts = list("mcolor" = "FFFFFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
exotic_bloodtype = "U"
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
mutant_heart = /obj/item/organ/heart/vampire
@@ -14,6 +14,7 @@
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability."
+ species_type = "undead"
/datum/species/vampire/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
diff --git a/code/modules/mob/living/carbon/human/species_types/xeno.dm b/code/modules/mob/living/carbon/human/species_types/xeno.dm
new file mode 100644
index 0000000000..db34d1ae45
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species_types/xeno.dm
@@ -0,0 +1,19 @@
+/datum/species/xeno
+ // A cloning mistake, crossing human and xenomorph DNA
+ name = "Xenomorph Hybrid"
+ id = "xeno"
+ say_mod = "hisses"
+ default_color = "00FF00"
+ icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
+ species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR)
+ mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade")
+ attack_verb = "slash"
+ attack_sound = 'sound/weapons/slash.ogg'
+ miss_sound = 'sound/weapons/slashmiss.ogg'
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
+ gib_types = list(/obj/effect/gibspawner/xeno/xenoperson, /obj/effect/gibspawner/xeno/xenoperson/bodypartless)
+ skinned_type = /obj/item/stack/sheet/animalhide/xeno
+ exotic_bloodtype = "X*"
+ damage_overlay_type = "xeno"
+ liked_food = MEAT
+ species_type = "alien"
diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm
index 26a99dbc2b..8d86ad2fa9 100644
--- a/code/modules/mob/living/carbon/human/species_types/zombies.dm
+++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm
@@ -8,13 +8,14 @@
sexes = 0
blacklisted = 1
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/zombie
- species_traits = list(NOBLOOD,NOZOMBIE,NOTRANSSTING)
+ species_traits = list(NOBLOOD,NOZOMBIE,NOTRANSSTING,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
mutanttongue = /obj/item/organ/tongue/zombie
var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg')
disliked_food = NONE
liked_food = GROSS | MEAT | RAW
+ species_type = "undead"
/datum/species/zombie/notspaceproof
id = "notspaceproofzombie"
@@ -31,9 +32,10 @@
name = "Infectious Zombie"
id = "memezombies"
limbs_id = "zombie"
+ inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_NOSOFTCRIT, TRAIT_FAKEDEATH)
mutanthands = /obj/item/zombie_hand
armor = 20 // 120 damage to KO a zombie, which kills it
- speedmod = 1.6
+ speedmod = 1.6 // they're very slow
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
var/heal_rate = 1
var/regen_cooldown = 0
@@ -41,11 +43,10 @@
/datum/species/zombie/infectious/check_roundstart_eligible()
return FALSE
-
/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount)
. = min(20, amount)
-/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE)
+/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
. = ..()
if(.)
regen_cooldown = world.time + REGENERATION_DELAY
@@ -62,6 +63,10 @@
heal_amt *= 2
C.heal_overall_damage(heal_amt,heal_amt)
C.adjustToxLoss(-heal_amt)
+ for(var/i in C.all_wounds)
+ var/datum/wound/iter_wound = i
+ if(prob(4-iter_wound.severity))
+ iter_wound.remove_wound()
if(!C.InCritical() && prob(4))
playsound(C, pick(spooks), 50, TRUE, 10)
@@ -85,6 +90,11 @@
infection = new()
infection.Insert(C)
+ //make their bodyparts stamina-immune, its a corpse.
+ var/incoming_stam_mult = 0
+ for(var/obj/item/bodypart/part in C.bodyparts)
+ part.incoming_stam_mult = incoming_stam_mult
+ //todo: add negative wound resistance to all parts when wounds is merged (zombies are physically weak in terms of limbs)
// Your skin falls off
/datum/species/krokodil_addict
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index b40d87a68a..e29c6b9ffe 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -1,6 +1,8 @@
/mob/living/carbon/BiologicalLife(seconds, times_fired)
//Updates the number of stored chemicals for powers
handle_changeling()
+ //Handles the unique mentabolism of bloodsuckers, look at /datum/antagonist/bloodsucker/proc/LifeTick()
+ handle_bloodsucker()
//Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs()
. = ..() // if . is false, we are dead.
@@ -404,6 +406,12 @@
if(stat != DEAD || D.process_dead)
D.stage_act()
+/mob/living/carbon/handle_wounds()
+ for(var/thing in all_wounds)
+ var/datum/wound/W = thing
+ if(W.processes) // meh
+ W.handle_process()
+
//todo generalize this and move hud out
/mob/living/carbon/proc/handle_changeling()
if(mind && hud_used && hud_used.lingchemdisplay)
@@ -416,6 +424,12 @@
hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
+/mob/living/carbon/proc/handle_bloodsucker()
+ if(mind && AmBloodsucker(src))
+ var/datum/antagonist/bloodsucker/B = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
+ B.LifeTick()
+
+
/mob/living/carbon/handle_mutations_and_radiation()
if(dna && dna.temporary_mutations.len)
for(var/mut in dna.temporary_mutations)
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index 149ec5f0e3..13d234092c 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -90,8 +90,7 @@
else if(legcuffed)
I = legcuffed
if(I)
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
+ MarkResistTime()
cuff_resist(I)
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
@@ -354,7 +353,7 @@
battle_screech()
a_intent = INTENT_HARM
-/mob/living/carbon/monkey/attack_hand(mob/living/L)
+/mob/living/carbon/monkey/on_attack_hand(mob/living/L)
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(L)
else if(L.a_intent == INTENT_DISARM && prob(MONKEY_RETALIATE_DISARM_PROB))
diff --git a/code/modules/mob/living/carbon/monkey/monkey_defense.dm b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
index 8f862af8fa..16b3c1a79e 100644
--- a/code/modules/mob/living/carbon/monkey/monkey_defense.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
@@ -42,7 +42,7 @@
adjustBruteLoss(15)
return TRUE
-/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
+/mob/living/carbon/monkey/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) //To allow surgery to return properly.
return
diff --git a/code/modules/mob/living/carbon/monkey/punpun.dm b/code/modules/mob/living/carbon/monkey/punpun.dm
index c5cb4dc713..c59218a8a3 100644
--- a/code/modules/mob/living/carbon/monkey/punpun.dm
+++ b/code/modules/mob/living/carbon/monkey/punpun.dm
@@ -26,6 +26,8 @@
//These have to be after the parent new to ensure that the monkey
//bodyparts are actually created before we try to equip things to
//those slots
+ if(ancestor_chain > 1)
+ generate_fake_scars(rand(ancestor_chain, ancestor_chain * 4))
if(relic_hat)
equip_to_slot_or_del(new relic_hat, SLOT_HEAD)
if(relic_mask)
diff --git a/code/modules/mob/living/clickdelay.dm b/code/modules/mob/living/clickdelay.dm
new file mode 100644
index 0000000000..dfdb9104bf
--- /dev/null
+++ b/code/modules/mob/living/clickdelay.dm
@@ -0,0 +1,4 @@
+/mob/living/GetActionCooldownMod()
+ . = ..()
+ for(var/datum/status_effect/S in status_effects)
+ . *= S.action_cooldown_mod()
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 0c049ab5c1..47c9062148 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -14,7 +14,7 @@
*
* Returns TRUE if damage applied
*/
-/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE)
+/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
var/hit_percent = (100-blocked)/100
if(!damage || (hit_percent <= 0))
return 0
@@ -245,7 +245,7 @@
update_stamina()
// damage ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
+/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status, check_armor = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
adjustBruteLoss(brute, FALSE) //zero as argument for no instant health update
adjustFireLoss(burn, FALSE)
adjustStaminaLoss(stamina, FALSE)
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 7d0a701e8f..97de8bfd6c 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -226,7 +226,7 @@
'sound/voice/catpeople/nyahehe.ogg'),
50, 1)
return
- else if(ismoth(C))
+ else if(isinsect(C))
playsound(C, 'sound/voice/moth/mothlaugh.ogg', 50, 1)
else if(ishumanbasic(C))
if(user.gender == FEMALE)
@@ -244,7 +244,7 @@
. = ..()
if(. && iscarbon(user)) //Citadel Edit because this is hilarious
var/mob/living/carbon/C = user
- if(ismoth(C))
+ if(isinsect(C))
playsound(C, 'sound/voice/moth/mothchitter.ogg', 50, 1)
/datum/emote/living/look
@@ -326,6 +326,11 @@
key_third_person = "smiles"
message = "smiles."
+/datum/emote/living/smirk
+ key = "smirk"
+ key_third_person = "smirks"
+ message = "smirks."
+
/datum/emote/living/sneeze
key = "sneeze"
key_third_person = "sneezes"
@@ -441,7 +446,7 @@
to_chat(user, "You cannot send IC messages (muted).")
return FALSE
else if(!params)
- var/custom_emote = stripped_multiline_input(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
+ var/custom_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
if(custom_emote && !check_invalid(user, custom_emote))
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
switch(type)
@@ -531,3 +536,29 @@
to_chat(user, "You ready your slapping hand.")
else
to_chat(user, "You're incapable of slapping in your current state.")
+
+/datum/emote/living/audio_emote/blorble
+ key = "blorble"
+ key_third_person = "blorbles"
+ message = "blorbles."
+ message_param = "blorbles at %t."
+
+/datum/emote/living/audio_emote/blorble/run_emote(mob/user, params)
+ . = ..()
+ if(. && iscarbon(user))
+ var/mob/living/carbon/C = user
+ if(isjellyperson(C))
+ pick(playsound(C, 'sound/effects/attackblob.ogg', 50, 1),playsound(C, 'sound/effects/blobattack.ogg', 50, 1))
+
+/datum/emote/living/audio_emote/blurp
+ key = "blurp"
+ key_third_person = "blurps"
+ message = "blurps."
+ message_param = "blurps at %t."
+
+/datum/emote/living/audio_emote/blurp/run_emote(mob/user, params)
+ . = ..()
+ if(. && iscarbon(user))
+ var/mob/living/carbon/C = user
+ if(isjellyperson(C))
+ pick(playsound(C, 'sound/effects/meatslap.ogg', 50, 1),playsound(C, 'sound/effects/gib_step.ogg', 50, 1))
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 1993d86b74..89321082c9 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -3,7 +3,7 @@
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
*/
/mob/living/proc/Life(seconds, times_fired)
- set waitfor = FALSE // yeah hey we're kind of on a subsystem, no sleeping will be tolerated here!
+ SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
@@ -45,6 +45,8 @@
/mob/living/proc/BiologicalLife(seconds, times_fired)
handle_diseases()// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
+ handle_wounds()
+
// Everything after this shouldn't process while dead (as of the time of writing)
if(stat == DEAD)
return FALSE
@@ -80,7 +82,7 @@
handle_diginvis() //AI becomes unable to see mob
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
- float(on = TRUE)
+ INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
if(!loc)
return FALSE
@@ -109,6 +111,9 @@
/mob/living/proc/handle_diseases()
return
+/mob/living/proc/handle_wounds()
+ return
+
/mob/living/proc/handle_diginvis()
if(!digitaldisguise)
src.digitaldisguise = image(loc = src)
@@ -134,7 +139,7 @@
ExtinguishMob()
return
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
- if(G.get_moles(/datum/gas/oxygen, 1))
+ if(!G.get_moles(/datum/gas/oxygen, 1))
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
return
var/turf/location = get_turf(src)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 892518d6ba..0f55d5c408 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -273,7 +273,7 @@
return
stop_pulling()
- changeNext_move(CLICK_CD_GRABBING)
+ DelayNextAction(CLICK_CD_GRABBING)
if(AM.pulledby)
if(!supress_message)
@@ -605,41 +605,55 @@
SEND_SIGNAL(item, COMSIG_ITEM_WEARERCROSSED, AM)
/mob/living/proc/makeTrail(turf/target_turf, turf/start, direction)
- if(!has_gravity())
+ if(!has_gravity() || !isturf(start) || !blood_volume)
return
- var/blood_exists = FALSE
+ var/blood_exists = locate(/obj/effect/decal/cleanable/trail_holder) in start
- for(var/obj/effect/decal/cleanable/trail_holder/C in start) //checks for blood splatter already on the floor
- blood_exists = TRUE
- if(isturf(start))
- var/trail_type = getTrail()
- if(trail_type)
- var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
- if(blood_volume && blood_volume > max((BLOOD_VOLUME_NORMAL*blood_ratio)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
- blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage.
- var/newdir = get_dir(target_turf, start)
- if(newdir != direction)
- newdir = newdir | direction
- if(newdir == 3) //N + S
- newdir = NORTH
- else if(newdir == 12) //E + W
- newdir = EAST
- if((newdir in GLOB.cardinals) && (prob(50)))
- newdir = turn(get_dir(target_turf, start), 180)
- if(!blood_exists)
- new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses())
+ var/trail_type = getTrail()
+ if(!trail_type)
+ return
- for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
- if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
- TH.existing_dirs += newdir
- TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
- TH.transfer_mob_blood_dna(src)
+ var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
+ if(blood_volume < max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
+ return
+
+ var/bleed_amount = bleedDragAmount()
+ blood_volume = max(blood_volume - bleed_amount, 0) //that depends on our brute damage.
+ var/newdir = get_dir(target_turf, start)
+ if(newdir != direction)
+ newdir = newdir | direction
+ if(newdir == (NORTH|SOUTH))
+ newdir = NORTH
+ else if(newdir == (EAST|WEST))
+ newdir = EAST
+ if((newdir in GLOB.cardinals) && (prob(50)))
+ newdir = turn(get_dir(target_turf, start), 180)
+ if(!blood_exists)
+ new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses())
+
+ for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
+ if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
+ TH.existing_dirs += newdir
+ TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
+ TH.transfer_mob_blood_dna(src)
/mob/living/carbon/human/makeTrail(turf/T)
- if((NOBLOOD in dna.species.species_traits) || !bleed_rate || bleedsuppress)
+ if((NOBLOOD in dna.species.species_traits) || !is_bleeding() || bleedsuppress)
return
..()
+///Returns how much blood we're losing from being dragged a tile, from [mob/living/proc/makeTrail]
+/mob/living/proc/bleedDragAmount()
+ var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
+ return max(1, brute_ratio * 2)
+
+/mob/living/carbon/bleedDragAmount()
+ var/bleed_amount = 0
+ for(var/i in all_wounds)
+ var/datum/wound/iter_wound = i
+ bleed_amount += iter_wound.drag_bleed_amount()
+ return bleed_amount
+
/mob/living/proc/getTrail()
if(getBruteLoss() < 300)
return pick("ltrails_1", "ltrails_2")
@@ -676,7 +690,7 @@
..(pressure_difference, direction, pressure_resistance_prob_delta)
/mob/living/can_resist()
- return !((next_move > world.time) || !CHECK_MOBILITY(src, MOBILITY_RESIST))
+ return CheckResistCooldown() && CHECK_MOBILITY(src, MOBILITY_RESIST)
/// Resist verb for attempting to get out of whatever is restraining your motion. Gives you resist clickdelay if do_resist() returns true.
/mob/living/verb/resist()
@@ -687,10 +701,12 @@
return
if(do_resist())
- changeNext_move(CLICK_CD_RESIST)
+ MarkResistTime()
+ DelayNextAction(CLICK_CD_RESIST)
-/// The actual proc for resisting. Return TRUE to give clickdelay.
+/// The actual proc for resisting. Return TRUE to give CLICK_CD_RESIST clickdelay.
/mob/living/proc/do_resist()
+ set waitfor = FALSE // some of these sleep.
SEND_SIGNAL(src, COMSIG_LIVING_RESIST, src)
//resisting grabs (as if it helps anyone...)
// only works if you're not cuffed.
@@ -701,7 +717,7 @@
return old_gs? TRUE : FALSE
// unbuckling yourself. stops the chain if you try it.
- if(buckled && last_special <= world.time)
+ if(buckled)
log_combat(src, buckled, "resisted buckle")
return resist_buckle()
@@ -730,13 +746,12 @@
if(CHECK_MOBILITY(src, MOBILITY_USE) && resist_embedded()) //Citadel Change for embedded removal memes - requires being able to use items.
// DO NOT GIVE DEFAULT CLICKDELAY - This is a combat action.
- changeNext_move(CLICK_CD_MELEE)
+ DelayNextAction(CLICK_CD_MELEE)
return FALSE
- if(last_special <= world.time)
- resist_restraints() //trying to remove cuffs.
- // DO NOT GIVE CLICKDELAY - last_special handles this.
- return FALSE
+ resist_restraints() //trying to remove cuffs.
+ // DO NOT GIVE CLICKDELAY
+ return FALSE
/// Proc to resist a grab. moving_resist is TRUE if this began by someone attempting to move. Return FALSE if still grabbed/failed to break out. Use this instead of resist_grab() directly.
/mob/proc/attempt_resist_grab(moving_resist, forced, log = TRUE)
@@ -802,7 +817,7 @@
else
throw_alert("gravity", /obj/screen/alert/weightless)
if(!override && !is_flying())
- float(!has_gravity)
+ INVOKE_ASYNC(src, /atom/movable.proc/float, !has_gravity)
/mob/living/float(on)
if(throwing)
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 4211b2cfd9..729e7d3d7a 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -10,8 +10,7 @@
REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
remove_movespeed_modifier(/datum/movespeed_modifier/active_block)
var/datum/block_parry_data/data = I.get_block_parry_data()
- if(timeToNextMove() < data.block_end_click_cd_add)
- changeNext_move(data.block_end_click_cd_add)
+ DelayNextAction(data.block_end_click_cd_add)
return TRUE
/mob/living/proc/ACTIVE_BLOCK_START(obj/item/I)
@@ -97,7 +96,7 @@
return
// QOL: Attempt to toggle on combat mode if it isn't already
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
- if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
+ if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
to_chat(src, "You must be in combat mode to actively block!")
return FALSE
var/datum/block_parry_data/data = I.get_block_parry_data()
diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm
index 8141603f64..b6706d0548 100644
--- a/code/modules/mob/living/living_active_parry.dm
+++ b/code/modules/mob/living/living_active_parry.dm
@@ -59,14 +59,14 @@
return FALSE
//QOL: Try to enable combat mode if it isn't already
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
- if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
+ if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
to_chat(src, "You must be in combat mode to parry!")
return FALSE
data = return_block_parry_datum(data)
var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown
// no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can.
// can always implement it later, whatever.
- if((data.parry_respect_clickdelay && (next_move > world.time)) || ((parry_end_time_last + data.parry_cooldown) > world.time))
+ if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time))
to_chat(src, "You are not ready to parry (again)!")
return
// Point of no return, make sure everything is set.
@@ -121,7 +121,7 @@
Stagger(data.parry_failed_stagger_duration)
effect_text += "staggering themselves"
if(data.parry_failed_clickcd_duration)
- changeNext_move(data.parry_failed_clickcd_duration)
+ DelayNextAction(data.parry_failed_clickcd_duration, flush = TRUE)
effect_text += "throwing themselves off balance"
handle_parry_ending_effects(data, effect_text)
parrying = NOT_PARRYING
@@ -160,17 +160,17 @@
/**
* Called when an attack is parried using this, whether or not the parry was successful.
*/
-/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
+/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/**
* Called when an attack is parried innately, whether or not the parry was successful.
*/
-/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
+/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/**
* Called when an attack is parried using this, whether or not the parry was successful.
*/
-/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
+/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/**
* Called when an attack is parried and block_parra_data indicates to use a proc to handle counterattack.
@@ -245,7 +245,7 @@
. |= BLOCK_SUCCESS
var/list/effect_text
if(efficiency >= data.parry_efficiency_to_counterattack)
- run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency)
+ effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency)
if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK)
handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text)
successful_parries += efficiency
@@ -254,9 +254,12 @@
/mob/living/proc/handle_parry_feedback(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency, list/effect_text)
var/datum/block_parry_data/data = get_parry_data()
+ var/knockdown_check = FALSE
+ if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER] && parry_efficiency >= data.parry_efficiency_to_counterattack)
+ knockdown_check = TRUE
if(data.parry_sounds)
playsound(src, pick(data.parry_sounds), 75)
- visible_message("[src] parries \the [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""]!")
+ visible_message("[src] parries [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""][length(effect_text) && knockdown_check? " and" : ""][knockdown_check? " knocking them to the ground" : ""]!")
/// Run counterattack if any
/mob/living/proc/run_parry_countereffects(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency)
@@ -277,7 +280,7 @@
if(data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
switch(parrying)
if(ITEM_PARRY)
- active_parry_item.melee_attack_chain(src, attacker, null, ATTACKCHAIN_PARRY_COUNTERATTACK, data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
+ active_parry_item.melee_attack_chain(src, attacker, null, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_CLICKDELAY | ATTACK_IGNORE_ACTION | NO_AUTO_CLICKDELAY_HANDLING, data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
effect_text += "reflexively counterattacking with [active_parry_item]"
if(UNARMED_PARRY) // WARNING: If you are using these two, the attackchain parry counterattack flags and damage multipliers are unimplemented. Be careful with how you handle this.
UnarmedAttack(attacker)
@@ -288,15 +291,15 @@
if(data.parry_data[PARRY_DISARM_ATTACKER])
L.drop_all_held_items()
effect_text += "disarming"
- if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
- L.DefaultCombatKnockdown(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
- effect_text += "knocking them to the ground"
if(data.parry_data[PARRY_STAGGER_ATTACKER])
L.Stagger(data.parry_data[PARRY_STAGGER_ATTACKER])
effect_text += "staggering"
if(data.parry_data[PARRY_DAZE_ATTACKER])
L.Daze(data.parry_data[PARRY_DAZE_ATTACKER])
effect_text += "dazing"
+ if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
+ L.DefaultCombatKnockdown(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
+ // effect_text += "knocking them to the ground" - snowflaked above
return effect_text
/// Gets the datum/block_parry_data we're going to use to parry.
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 9f1ad1c27a..47dae8849d 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -126,6 +126,8 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/list/parry_imperfect_falloff_percent_override
/// Efficiency in percent on perfect parry.
var/parry_efficiency_perfect = 120
+ /// Override for attack types, list("[ATTACK_TYPE_DEFINE]" = perecntage) for perfect efficiency.
+ var/parry_efficiency_perfect_override
/// Parry effect data.
var/list/parry_data = list(
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 1
@@ -180,7 +182,11 @@ GLOBAL_LIST_EMPTY(block_parry_data)
if(isnull(leeway))
leeway = parry_time_perfect_leeway
difference -= leeway
- . = parry_efficiency_perfect
+ var/perfect = attack_type_list_scan(parry_efficiency_perfect_override, attack_type)
+ if(isnull(perfect))
+ . = parry_efficiency_perfect
+ else
+ . = perfect
if(difference <= 0)
return
var/falloff = attack_type_list_scan(parry_imperfect_falloff_percent_override, attack_type)
@@ -276,6 +282,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
RENDER_VARIABLE_SIMPLE(parry_imperfect_falloff_percent, "Linear falloff in percent per decisecond for attacks parried outside of perfect window.")
RENDER_OVERRIDE_LIST(parry_imperfect_falloff_percent_override, "Override for the above for each attack type")
RENDER_VARIABLE_SIMPLE(parry_efficiency_perfect, "Efficiency in percentage a parry in the perfect window is considered.")
+ RENDER_OVERRIDE_LIST(parry_efficiency_perfect_override, "Override for the above for each attack type")
// parry_data
dat += ""
RENDER_VARIABLE_SIMPLE(parry_efficiency_considered_successful, "Minimum parry efficiency to be considered a successful parry.")
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index b15275d57b..19adb7b787 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -77,6 +77,7 @@
final_percent = returnlist[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE]
if(returned & BLOCK_SHOULD_REDIRECT)
handle_projectile_attack_redirection(P, returnlist[BLOCK_RETURN_REDIRECT_METHOD])
+ return BULLET_ACT_FORCE_PIERCE
if(returned & BLOCK_REDIRECTED)
return BULLET_ACT_FORCE_PIERCE
if(returned & BLOCK_SUCCESS)
@@ -85,7 +86,7 @@
totaldamage = block_calculate_resultant_damage(totaldamage, returnlist)
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
if(!P.nodamage)
- apply_damage(totaldamage, P.damage_type, def_zone, armor)
+ apply_damage(totaldamage, P.damage_type, def_zone, armor, wound_bonus = P.wound_bonus, bare_wound_bonus = P.bare_wound_bonus, sharpness = P.sharpness)
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
var/missing = 100 - final_percent
@@ -135,12 +136,13 @@
dtype = I.damtype
if(!blocked)
- visible_message("[src] has been hit by [I].", \
- "You have been hit by [I].")
- var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration)
- apply_damage(total_damage, dtype, impacting_zone, armor)
- if(I.thrownby)
- log_combat(I.thrownby, src, "threw and hit", I)
+ if(!nosell_hit)
+ visible_message("[src] is hit by [I]!", \
+ "You're hit by [I]!")
+ if(!I.throwforce)
+ return
+ var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration)
+ apply_damage(I.throwforce, dtype, impacting_zone, armor, sharpness=I.get_sharpness(), wound_bonus=(nosell_hit * CANT_WOUND))
else
return 1
else
@@ -215,8 +217,8 @@
//proc to upgrade a simple pull into a more aggressive grab.
/mob/living/proc/grippedby(mob/living/carbon/user, instant = FALSE)
if(user.grab_state < GRAB_KILL)
- user.changeNext_move(CLICK_CD_GRABBING)
- playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ user.DelayNextAction(CLICK_CD_GRABBING, flush = TRUE)
+ playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(user.grab_state) //only the first upgrade is instantaneous
var/old_grab_state = user.grab_state
@@ -270,10 +272,10 @@
user.set_pull_offsets(src, grab_state)
return 1
-/mob/living/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/mob/living/on_attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
..() //Ignoring parent return value here.
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
- if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((unarmed_attack_flags & UNARMED_ATTACK_PARRY)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
+ if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
log_combat(user, src, "attempted to touch")
visible_message("[user] attempted to touch [src]!",
"[user] attempted to touch you!", target = user,
@@ -323,6 +325,9 @@
/mob/living/attack_animal(mob/living/simple_animal/M)
M.face_atom(src)
+ if(!M.CheckActionCooldown(CLICK_CD_MELEE))
+ return
+ M.DelayNextAction()
if(M.melee_damage_upper == 0)
M.visible_message("\The [M] [M.friendly_verb_continuous] [src]!",
"You [M.friendly_verb_simple] [src]!", target = src,
@@ -338,7 +343,7 @@
return 0
damage = block_calculate_resultant_damage(damage, return_list)
if(M.attack_sound)
- playsound(loc, M.attack_sound, 50, 1, 1)
+ playsound(src, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
visible_message("\The [M] [M.attack_verb_continuous] [src]!", \
"\The [M] [M.attack_verb_continuous] you!", null, COMBAT_MESSAGE_RANGE, null,
@@ -347,6 +352,9 @@
return damage
/mob/living/attack_paw(mob/living/carbon/monkey/M)
+ if(!M.CheckActionCooldown(CLICK_CD_MELEE))
+ return
+ M.DelayNextAction()
if (M.a_intent == INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "You don't want to hurt anyone!")
@@ -368,6 +376,7 @@
visible_message("[M.name] has attempted to bite [src]!", \
"[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE, null,
M, "You have attempted to bite [src]!")
+ return TRUE
return FALSE
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index b037221e2c..5495d37297 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -53,7 +53,6 @@
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
- var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
var/timeofdeath = 0
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index 4f2332e99d..2cbd1f35ca 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -151,7 +151,7 @@
to_chat(src, "Receiving control information from APC.")
sleep(2)
apc_override = 1
- theAPC.ui_interact(src, state = GLOB.conscious_state)
+ theAPC.ui_interact(src)
apc_override = 0
aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND
sleep(50)
diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm
index 0eaea103f2..bbfb7604ba 100644
--- a/code/modules/mob/living/silicon/ai/robot_control.dm
+++ b/code/modules/mob/living/silicon/ai/robot_control.dm
@@ -19,11 +19,13 @@
return ..()
return UI_CLOSE
-/datum/robot_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/robot_control/ui_state(mob/user)
+ return GLOB.always_state
+
+/datum/robot_control/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "RemoteRobotControl", "Remote Robot Control", 500, 500, master_ui, state)
+ ui = new(user, src, "RemoteRobotControl")
ui.open()
/datum/robot_control/ui_data(mob/user)
diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm
index 2a03afb61a..7530630d74 100644
--- a/code/modules/mob/living/silicon/damage_procs.dm
+++ b/code/modules/mob/living/silicon/damage_procs.dm
@@ -1,5 +1,5 @@
-/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE)
+/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
var/hit_percent = (100-blocked)/100
if(!damage || (!forced && hit_percent <= 0))
return 0
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index dcb7ac66c9..64509d2deb 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -28,8 +28,7 @@
fold_in(force = 1)
DefaultCombatKnockdown(200)
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
+/mob/living/silicon/pai/on_attack_hand(mob/living/carbon/human/user)
switch(user.a_intent)
if(INTENT_HELP)
visible_message("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.",
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index 65e1047cdc..c0fca997f5 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -3,8 +3,14 @@
emote_type = EMOTE_AUDIBLE
/datum/emote/sound/silicon
- mob_type_allowed_typecache = list(/mob/living/silicon)
+ mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human)
emote_type = EMOTE_AUDIBLE
+ var/unrestricted = FALSE
+
+/datum/emote/sound/silicon/run_emote(mob/user, params)
+ if(!unrestricted && !(issilicon(user) || isipcperson(user)))
+ return
+ return ..()
/datum/emote/silicon/boop
key = "boop"
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index 0d8a0880a8..a063d090db 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -16,8 +16,6 @@
return item
return module_active
-
-
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
if(!O)
return 0
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 51cff93ceb..9018c49b2c 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -16,6 +16,8 @@
wires = new /datum/wires/robot(src)
AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES)
+ RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge)
+
robot_modules_background = new()
robot_modules_background.icon_state = "block"
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it.
@@ -289,7 +291,7 @@
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src))
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
if (!getBruteLoss())
to_chat(user, "[src] is already in good condition!")
return
@@ -311,7 +313,7 @@
return
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
if (getFireLoss() > 0 || getToxLoss() > 0)
if(src == user)
to_chat(user, "You start fixing yourself...")
@@ -1097,6 +1099,15 @@
for(var/i in connected_ai.aicamera.stored)
aicamera.stored[i] = TRUE
+/mob/living/silicon/robot/proc/charge(datum/source, amount, repairs)
+ if(module)
+ var/coeff = amount * 0.005
+ module.respawn_consumable(src, coeff)
+ if(repairs)
+ heal_bodypart_damage(repairs, repairs - 1)
+ if(cell)
+ cell.charge = min(cell.charge + amount, cell.maxcharge)
+
/mob/living/silicon/robot/proc/rest_style()
set name = "Switch Rest Style"
set category = "Robot Commands"
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index e337618e4b..746c4f469d 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -62,8 +62,7 @@
return
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
+/mob/living/silicon/robot/on_attack_hand(mob/living/carbon/human/user)
add_fingerprint(user)
if(opened && !wiresexposed && cell && !issilicon(user))
cell.update_icon()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index cd3601942c..7c4125fbc6 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -324,7 +324,7 @@
/obj/item/crowbar/cyborg,
/obj/item/healthanalyzer,
/obj/item/reagent_containers/borghypo,
- /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/weapon/gripper/medical,
/obj/item/reagent_containers/dropper,
/obj/item/reagent_containers/syringe,
/obj/item/surgical_drapes,
@@ -334,9 +334,11 @@
/obj/item/surgicaldrill,
/obj/item/scalpel,
/obj/item/circular_saw,
+ /obj/item/bonesetter,
/obj/item/roller/robo,
/obj/item/borg/cyborghug/medical,
/obj/item/stack/medical/gauze/cyborg,
+ /obj/item/stack/medical/bone_gel/cyborg,
/obj/item/organ_storage,
/obj/item/borg/lollipop,
/obj/item/sensor_device,
@@ -359,8 +361,7 @@
"Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmed"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamed"),
"Eyebot" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "eyebotmed"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed"),
- "Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_med")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed")
)
var/list/L = list("Medihound" = "medihound", "Medihound Dark" = "medihounddark", "Vale" = "valemed")
for(var/a in L)
@@ -376,8 +377,6 @@
switch(med_borg_icon)
if("Default")
cyborg_base_icon = "medical"
- if("Zoomba")
- cyborg_base_icon = "zoomba_med"
if("Droid")
cyborg_base_icon = "medical"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
@@ -479,8 +478,7 @@
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "caneng"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinaeng"),
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidereng"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng"),
- "Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_engi")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng")
)
var/list/L = list("Pup Dozer" = "pupdozer", "Vale" = "valeeng")
for(var/a in L)
@@ -496,8 +494,6 @@
switch(engi_borg_icon)
if("Default")
cyborg_base_icon = "engineer"
- if("Zoomba")
- cyborg_base_icon = "zoomba_engi"
if("Default - Treads")
cyborg_base_icon = "engi-tread"
special_light_key = "engineer"
@@ -578,8 +574,7 @@
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "cansec"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinasec"),
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidersec"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec"),
- "Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_sec")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec")
)
var/list/L = list("K9" = "k9", "Vale" = "valesec", "K9 Dark" = "k9dark")
for(var/a in L)
@@ -595,8 +590,6 @@
switch(sec_borg_icon)
if("Default")
cyborg_base_icon = "sec"
- if("Zoomba")
- cyborg_base_icon = "zoomba_sec"
if("Default - Treads")
cyborg_base_icon = "sec-tread"
special_light_key = "sec"
@@ -834,8 +827,7 @@
"(Janitor) Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinajan"),
"(Janitor) Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekjan"),
"(Janitor) Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canjan"),
- "(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan"),
- "Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_jani")
+ "(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan")
)
var/list/L = list("(Service) DarkK9" = "k50", "(Service) Vale" = "valeserv", "(Service) ValeDark" = "valeservdark",
"(Janitor) Scrubpuppy" = "scrubpup")
@@ -850,8 +842,6 @@
service_icons = sortList(service_icons)
var/service_robot_icon = show_radial_menu(R, R , service_icons, custom_check = CALLBACK(src, .proc/check_menu, R), radius = 42, require_near = TRUE)
switch(service_robot_icon)
- if("Zoomba")
- cyborg_base_icon = "zoomba_jani"
if("(Service) Waitress")
cyborg_base_icon = "service_f"
special_light_key = "service"
@@ -954,8 +944,7 @@
"Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmin"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamin"),
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canmin"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin"),
- "Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_miner")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin")
)
var/list/L = list("Blade" = "blade", "Vale" = "valemine")
for(var/a in L)
@@ -999,8 +988,6 @@
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
sleeper_overlay = "valeminesleeper"
dogborg = TRUE
- if("Zoomba")
- cyborg_base_icon = "zoomba_miner"
else
return FALSE
return ..()
@@ -1050,6 +1037,8 @@
/obj/item/cautery,
/obj/item/surgicaldrill,
/obj/item/scalpel,
+ /obj/item/bonesetter,
+ /obj/item/stack/medical/bone_gel,
/obj/item/melee/transforming/energy/sword/cyborg/saw,
/obj/item/roller/robo,
/obj/item/card/emag,
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 0850f0f886..8be2183d3b 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -70,7 +70,7 @@
return TRUE
return FALSE
-/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
+/mob/living/silicon/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) //the attack was blocked
return
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index 278bb37d0d..b003e066ef 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -1,6 +1,6 @@
-/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
+/mob/living/simple_animal/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) //the attack was blocked
return
diff --git a/code/modules/mob/living/simple_animal/astral.dm b/code/modules/mob/living/simple_animal/astral.dm
index eee42c214f..f79a2b5b3e 100644
--- a/code/modules/mob/living/simple_animal/astral.dm
+++ b/code/modules/mob/living/simple_animal/astral.dm
@@ -41,7 +41,11 @@
to_chat(src, "Your astral projection is interrupted and your mind is sent back to your body with a shock!")
/mob/living/simple_animal/astral/ClickOn(var/atom/A, var/params)
- ..()
+ . = ..()
+ attempt_possess(A)
+
+/mob/living/simple_animal/astral/proc/attempt_possess(atom/A)
+ set waitfor = FALSE
if(pseudo_death == FALSE)
if(isliving(A))
if(ishuman(A))
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index a347b04e50..fe6792b5c2 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -102,6 +102,10 @@
var/can_salute = TRUE
var/salute_delay = 60 SECONDS
+ //emotes/speech stuff
+ var/patrol_emote = "Engaging patrol mode."
+ var/patrol_fail_emote = "Unable to start patrol."
+
/mob/living/simple_animal/bot/proc/get_mode()
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
if(paicard)
@@ -286,7 +290,7 @@
return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early.
-/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_HELP)
interact(H)
else
@@ -331,7 +335,6 @@
user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].")
ejectpai(user)
else
- user.changeNext_move(CLICK_CD_MELEE)
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
if(health >= maxHealth)
to_chat(user, "[src] does not need a repair!")
@@ -612,7 +615,7 @@ Pass a positive integer as an argument to override a bot's default speed.
if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol.
auto_patrol = 0
tries = 0
- speak("Unable to start patrol.")
+ speak(patrol_fail_emote)
return
@@ -628,7 +631,7 @@ Pass a positive integer as an argument to override a bot's default speed.
return
mode = BOT_PATROL
else // no patrol target, so need a new one
- speak("Engaging patrol mode.")
+ speak(patrol_emote)
find_patrol_target()
tries++
return
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 1f81e8db29..91462a6713 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -177,7 +177,7 @@ Auto Patrol[]"},
target = H
mode = BOT_HUNT
-/mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/ed209/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_HARM)
retaliate(H)
return ..()
@@ -532,8 +532,10 @@ Auto Patrol[]"},
/mob/living/simple_animal/bot/ed209/RangedAttack(atom/A)
if(!on)
- return
+ return ..()
shootAt(A)
+ DelayNextAction()
+ return TRUE
/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index 43f18d3890..0ee600ed1d 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -112,7 +112,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
target = H
mode = BOT_HUNT
-/mob/living/simple_animal/bot/honkbot/attack_hand(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/honkbot/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_HARM)
retaliate(H)
addtimer(CALLBACK(src, .proc/react_buzz), 5)
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index f998f58f02..fb5a889d89 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -604,7 +604,7 @@
/mob/living/simple_animal/bot/medbot/proc/get_healchem_toxin(mob/M)
return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
-/mob/living/simple_animal/bot/medbot/attack_hand(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/medbot/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_DISARM && mode != BOT_TIPPED)
H.visible_message("[H] begins tipping over [src].", "You begin tipping over [src]...")
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 5e96818766..d9bf8cc553 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -29,9 +29,6 @@
model = "MULE"
bot_core_type = /obj/machinery/bot_core/mulebot
- var/ui_x = 350
- var/ui_y = 425
-
var/id
path_image_color = "#7F5200"
@@ -170,11 +167,10 @@
return
ui_interact(user)
-/mob/living/simple_animal/bot/mulebot/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/mob/living/simple_animal/bot/mulebot/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Mule", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "Mule", name)
ui.open()
/mob/living/simple_animal/bot/mulebot/ui_data(mob/user)
@@ -191,8 +187,7 @@
data["modeStatus"] = "average"
if(BOT_NO_ROUTE)
data["modeStatus"] = "bad"
- else
- data["load"] = load ? load.name : null
+ data["load"] = load ? load.name : null //IF YOU CHANGE THE NAME OF THIS, UPDATE MULEBOT/PARANORMAL/UI_DATA.
data["destination"] = destination ? destination : null
data["home"] = home_destination
data["destinations"] = GLOB.deliverybeacontags
@@ -206,18 +201,20 @@
return data
/mob/living/simple_animal/bot/mulebot/ui_act(action, params)
- var/silicon_access = hasSiliconAccessInArea(usr)
- if(..() || (locked && silicon_access))
+ if(..() || (locked && hasSiliconAccessInArea(usr)))
return
switch(action)
if("lock")
- if(silicon_access)
+ if(hasSiliconAccessInArea(usr))
locked = !locked
. = TRUE
if("power")
if(on)
turn_off()
- else if(cell && !open)
+ else if(open)
+ to_chat(usr, "[name]'s maintenance panel is open!")
+ return
+ else if(cell)
if(!turn_on())
to_chat(usr, "You can't switch on [src]!")
return
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index cfff3eb751..cf9698655b 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -33,6 +33,20 @@
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
+ var/obj/item/clothing/head/bot_accessory
+ var/datum/beepsky_fashion/stored_fashion
+
+ //emotes (BOT is replaced with bot name, CRIMINAL with criminal name, THREAT_LEVEL with threat level)
+ var/death_emote = "BOT blows apart!"
+ var/capture_one = "BOT is trying to put zipties on CRIMINAL!"
+ var/capture_two = "BOT is trying to put zipties on you!"
+ var/infraction = "Level THREAT_LEVEL infraction alert!"
+ var/taunt = "BOT points at CRIMINAL!"
+ var/attack_one = "BOT has stunned CRIMINAL!"
+ var/attack_two = "BOT has stunned you!"
+ var/list/arrest_texts = list("Detaining", "Arresting")
+ var/arrest_emote = "ARREST_TYPE level THREAT_LEVEL scumbag CRIMINAL in LOCATION."
+
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
@@ -49,6 +63,103 @@
resize = 0.8
update_transform()
+/mob/living/simple_animal/bot/secbot/proc/process_emote(var/emote_type, var/atom/criminal, var/threat, var/arrest = -1, var/location)
+ var/emote = "The continuity of space itself collapses around [src]. You should probably report that to someone higher up."
+ switch(emote_type)
+ if("DEATH")
+ emote = death_emote
+ if("CAPTURE_ONE")
+ emote = capture_one
+ if("CAPTURE_TWO")
+ emote = capture_two
+ if("INFRACTION")
+ emote = infraction
+ if("TAUNT")
+ emote = taunt
+ if("ATTACK_ONE")
+ emote = attack_one
+ if("ATTACK_TWO")
+ emote = attack_two
+ if("ARREST")
+ emote = arrest_emote
+
+ //now replace pieces of the text with the information we have
+ if(emote_type != "TAUNT" && emote_type != "ARREST")
+ emote = replacetext(emote, "BOT", name)
+ else
+ emote = replacetext(emote, "BOT", "[name]") //needs to be bold if its a taunt or an arrest text
+ if(criminal)
+ emote = replacetext(emote, "CRIMINAL", criminal.name)
+ if(num2text(threat)) //because a threat of 0 will be false
+ emote = replacetext(emote, "THREAT_LEVEL", threat)
+ if(arrest > -1)
+ emote = replacetext(emote, "ARREST_TYPE", arrest_texts[arrest + 1])
+ if(location)
+ emote = replacetext(emote, "LOCATION", location)
+ return emote
+
+/mob/living/simple_animal/bot/secbot/proc/apply_fashion(var/datum/beepsky_fashion/fashion)
+ stored_fashion = new fashion
+ if(stored_fashion.name)
+ name = stored_fashion.name
+
+ if(stored_fashion.desc)
+ desc = stored_fashion.desc
+
+ if(stored_fashion.death_emote)
+ death_emote = stored_fashion.death_emote
+
+ if(stored_fashion.capture_one)
+ capture_one = stored_fashion.capture_one
+
+ if(stored_fashion.capture_two)
+ capture_two = stored_fashion.capture_two
+
+ if(stored_fashion.infraction)
+ infraction = stored_fashion.infraction
+
+ if(stored_fashion.taunt)
+ taunt = stored_fashion.taunt
+
+ if(stored_fashion.attack_one)
+ attack_one = stored_fashion.attack_one
+
+ if(stored_fashion.attack_two)
+ attack_two = stored_fashion.attack_two
+
+ if(stored_fashion.patrol_emote)
+ patrol_emote = stored_fashion.patrol_emote
+
+ if(stored_fashion.patrol_fail_emote)
+ patrol_fail_emote = stored_fashion.patrol_fail_emote
+
+ if(stored_fashion.arrest_texts)
+ arrest_texts = stored_fashion.arrest_texts
+
+ if(stored_fashion.arrest_emote)
+ arrest_emote = stored_fashion.arrest_emote
+
+ regenerate_icons()
+
+/mob/living/simple_animal/bot/secbot/proc/reset_fashion()
+ bot_accessory.forceMove(get_turf(src))
+ //reset all emotes/sounds and name/desc
+ name = initial(name)
+ desc = initial(desc)
+ death_emote = initial(death_emote)
+ capture_one = initial(capture_one)
+ capture_two = initial(capture_two)
+ infraction = initial(infraction)
+ taunt = initial(taunt)
+ attack_one = initial(attack_one)
+ attack_two = initial(attack_two)
+ arrest_texts = initial(arrest_texts)
+ arrest_emote = initial(arrest_emote)
+ patrol_emote = initial(patrol_emote)
+ arrest_texts = initial(arrest_texts)
+ arrest_emote = initial(arrest_emote)
+ bot_accessory = null
+ regenerate_icons()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/atom/Tsec = drop_location()
@@ -173,11 +284,16 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
return
-/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/secbot/on_attack_hand(mob/living/carbon/human/H)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
if(special_retaliate_after_attack(H))
return
+ if(H.a_intent == INTENT_HELP && bot_accessory)
+
+ to_chat(H, "You knock [bot_accessory] off of [src]'s head!")
+ reset_fashion()
+ return
return ..()
@@ -185,11 +301,48 @@ Auto Patrol: []"},
..()
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
return
+ if(istype(W, /obj/item/clothing/head))
+ attempt_place_on_head(user, W)
+ return
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
retaliate(user)
if(special_retaliate_after_attack(user))
return
+/mob/living/simple_animal/bot/secbot/proc/attempt_place_on_head(mob/user, obj/item/clothing/head/H)
+ if(user && !user.temporarilyRemoveItemFromInventory(H))
+ to_chat(user, "\The [H] is stuck to your hand, you cannot put it on [src]'s head!")
+ return
+ if(bot_accessory)
+ to_chat("\[src] already has an accessory, and the laws of physics disallow him from wearing a second!")
+ return
+
+ if(H.beepsky_fashion)
+ to_chat(user, "You set [H] on [src].")
+ bot_accessory = H
+ H.forceMove(src)
+ apply_fashion(H.beepsky_fashion)
+ else
+ to_chat(user, "You set [H] on [src]'s head, but it falls off!")
+ H.forceMove(drop_location())
+
+/mob/living/simple_animal/bot/secbot/regenerate_icons()
+ ..()
+ if(bot_accessory)
+ if(!stored_fashion)
+ stored_fashion = new bot_accessory.beepsky_fashion
+ if(!stored_fashion.obj_icon_state)
+ stored_fashion.obj_icon_state = bot_accessory.icon_state
+ if(!stored_fashion.obj_alpha)
+ stored_fashion.obj_alpha = bot_accessory.alpha
+ if(!stored_fashion.obj_color)
+ stored_fashion.obj_color = bot_accessory.color
+ add_overlay(stored_fashion.get_overlay())
+ else
+ if(stored_fashion)
+ cut_overlay(stored_fashion.get_overlay())
+ stored_fashion = null
+
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
. = ..()
if(emagged == 2)
@@ -233,8 +386,8 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
- C.visible_message("[src] is trying to put zipties on [C]!",\
- "[src] is trying to put zipties on you!")
+ C.visible_message("[process_emote("CAPTURE_ONE", C)]",\
+ "[process_emote("CAPTURE_TWO", C)]")
if(do_after(src, 60, FALSE, C))
attempt_handcuff(C)
@@ -249,16 +402,22 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
var/judgement_criteria = judgement_criteria()
- playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "secbot-c"
addtimer(CALLBACK(src, /atom/.proc/update_icon), 2)
var/threat = 5
if(ishuman(C))
+ if(stored_fashion)
+ stored_fashion.stun_attack(C)
+ if(stored_fashion.stun_sounds && !stored_fashion.ignore_sound)
+ playsound(src, pick(stored_fashion.stun_sounds), 50, TRUE, -1)
+ else
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.stuttering = 5
C.DefaultCombatKnockdown(100)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
else
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.DefaultCombatKnockdown(100)
C.stuttering = 5
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
@@ -266,9 +425,9 @@ Auto Patrol: []"},
log_combat(src,C,"stunned")
if(declare_arrests)
var/area/location = get_area(src)
- speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
- C.visible_message("[src] has stunned [C]!",\
- "[src] has stunned you!")
+ speak(process_emote("ARREST", C, threat, arrest_type, location), radio_channel)
+ C.visible_message("[process_emote("ATTACK_ONE", C)]",\
+ "[process_emote("ATTACK_TWO", C)]")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
@@ -355,7 +514,6 @@ Auto Patrol: []"},
look_for_perp()
bot_patrol()
-
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
@@ -391,9 +549,9 @@ Auto Patrol: []"},
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
- speak("Level [threatlevel] infraction alert!")
+ speak(process_emote("INFRACTION", target, threatlevel))
playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
- visible_message("[src] points at [C.name]!")
+ visible_message(process_emote("TAUNT", target, threatlevel))
mode = BOT_HUNT
INVOKE_ASYNC(src, .proc/handle_automated_action)
break
@@ -408,7 +566,7 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
- visible_message("[src] blows apart!")
+ visible_message("[process_emote("DEATH")]")
var/atom/Tsec = drop_location()
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index d30fa1b49f..c21875d1db 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -283,7 +283,7 @@
if(!D.is_decorated)
D.decorate_donut()
-/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
+/mob/living/simple_animal/pet/cat/cak/on_attack_hand(mob/living/L)
. = ..()
if(.) //the attack was blocked
return
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index 1f733a4d55..51e7ee6c03 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -166,7 +166,7 @@
if(stat == CONSCIOUS)
udder.generateMilk(milk_reagent)
-/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
+/mob/living/simple_animal/cow/on_attack_hand(mob/living/carbon/M)
if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
M.visible_message("[M] tips over [src].",
"You tip over [src].")
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index 73ebfa7c77..fb24b0fc09 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -60,11 +60,13 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
var/magic_fluff_string = "You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!"
var/tech_fluff_string = "BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!"
var/carp_fluff_string = "CARP CARP CARP SOME SORT OF HORRIFIC BUG BLAME THE CODERS CARP CARP CARP"
+ /// sigh, fine.
+ var/datum/song/holoparasite/music_datum
/mob/living/simple_animal/hostile/guardian/Initialize(mapload, theme)
GLOB.parasites += src
updatetheme(theme)
-
+ music_datum = new(src, get_allowed_instrument_ids())
. = ..()
/mob/living/simple_animal/hostile/guardian/med_hud_set_health()
@@ -84,8 +86,16 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
/mob/living/simple_animal/hostile/guardian/Destroy()
GLOB.parasites -= src
+ QDEL_NULL(music_datum)
return ..()
+/mob/living/simple_animal/hostile/guardian/verb/music_interact()
+ set name = "Access Internal Synthesizer"
+ set desc = "Access your internal musical synthesizer"
+ set category = "IC"
+
+ music_datum.ui_interact(src)
+
/mob/living/simple_animal/hostile/guardian/proc/updatetheme(theme) //update the guardian's theme
if(!theme)
theme = pick("magic", "tech", "carp")
@@ -638,6 +648,12 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
/obj/item/guardiancreator/tech/choose/dextrous
possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
+/obj/item/guardiancreator/tech/choose/nukie // lacks support and protector as encouraging nukies to play turtle isnt fun and dextrous is epic
+ possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Ranged", "Standard")
+
+/obj/item/guardiancreator/tech/choose/nukie/check_uplink_validity()
+ return !used
+
/obj/item/paper/guides/antag/guardian
name = "Holoparasite Guide"
icon_state = "paper_words"
@@ -677,7 +693,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
Charger: Moves extremely fast, does medium damage on attack, and can charge at targets, damaging the first target hit and forcing them to drop any items they are holding.
- Dexterous: Does low damage on attack, but is capable of holding items and storing a single item within it. It will drop items held in its hands when it recalls, but it will retain the stored item.
+ Dextrous: Does low damage on attack, but is capable of holding items and storing a single item within it. It will drop items held in its hands when it recalls, but it will retain the stored item.
Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.
@@ -691,6 +707,29 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
"}
+/obj/item/paper/guides/antag/guardian/nukie
+ name = "Guardian Guide"
+ info = {"A list of Guardian Types
+
+
+ Assassin: Does medium damage and takes full damage, but can enter stealth, causing its next attack to do massive damage and ignore armor. However, it becomes briefly unable to recall after attacking from stealth.
+
+ Chaos: Ignites enemies on touch and causes them to hallucinate all nearby people as the guardian. Automatically extinguishes the user if they catch on fire.
+
+ Charger: Moves extremely fast, does medium damage on attack, and can charge at targets, damaging the first target hit and forcing them to drop any items they are holding.
+
+ Dextrous: Does low damage on attack, but is capable of holding items and storing a single item within it. It will drop items held in its hands when it recalls, but it will retain the stored item.
+
+ Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.
+
+ Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.
+
+ Ranged: Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; Cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode.
+
+ Standard: Devastating close combat attacks and high damage resist. Can smash through weak walls.
+
+"}
+
/obj/item/storage/box/syndie_kit/guardian
name = "holoparasite injector kit"
@@ -699,6 +738,13 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
new /obj/item/guardiancreator/tech/choose/traitor(src)
new /obj/item/paper/guides/antag/guardian(src)
+/obj/item/storage/box/syndie_kit/nukieguardian
+ name = "holoparasite injector kit"
+
+/obj/item/storage/box/syndie_kit/nukieguardian/PopulateContents()
+ new /obj/item/guardiancreator/tech/choose/nukie(src)
+ new /obj/item/paper/guides/antag/guardian/nukie(src)
+
/obj/item/guardiancreator/carp
name = "holocarp fishsticks"
desc = "Using the power of Carp'sie, you can catch a carp from byond the veil of Carpthulu, and bind it to your fleshy flesh form."
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index d396434708..26e5d791f3 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -36,61 +36,21 @@
return
if(isobj(A) && Adjacent(A))
if(bomb_cooldown <= world.time && !stat)
- var/obj/guardian_bomb/B = new /obj/guardian_bomb(get_turf(A))
+ var/datum/component/killerqueen/K = A.AddComponent(/datum/component/killerqueen, EXPLODE_HEAVY, CALLBACK(src, .proc/on_explode), CALLBACK(src, .proc/on_failure), \
+ examine_message = "It glows with a strange light!")
+ QDEL_IN(K, 1 MINUTES)
to_chat(src, "Success! Bomb armed!")
bomb_cooldown = world.time + 200
- B.spawner = src
- B.disguise(A)
else
to_chat(src, "Your powers are on cooldown! You must wait 20 seconds between bombs.")
-/obj/guardian_bomb
- name = "bomb"
- desc = "You shouldn't be seeing this!"
- var/obj/stored_obj
- var/mob/living/simple_animal/hostile/guardian/spawner
+/mob/living/simple_animal/hostile/guardian/bomb/proc/on_explode(atom/bomb, atom/victim)
+ if((victim == src) || (victim == summoner) || (hasmatchingsummoner(victim)))
+ to_chat(victim, "[src] glows with a strange light, and you don't touch it.")
+ return FALSE
+ to_chat(src, "One of your explosive traps caught [victim]!")
+ to_chat(victim, "[bomb] was boobytrapped!")
+ return TRUE
-
-/obj/guardian_bomb/proc/disguise(obj/A)
- A.forceMove(src)
- stored_obj = A
- opacity = A.opacity
- anchored = A.anchored
- density = A.density
- appearance = A.appearance
- addtimer(CALLBACK(src, .proc/disable), 600)
-
-/obj/guardian_bomb/proc/disable()
- stored_obj.forceMove(get_turf(src))
- to_chat(spawner, "Failure! Your trap didn't catch anyone this time.")
- qdel(src)
-
-/obj/guardian_bomb/proc/detonate(mob/living/user)
- if(isliving(user))
- if(user != spawner && user != spawner.summoner && !spawner.hasmatchingsummoner(user))
- to_chat(user, "[src] was boobytrapped!")
- to_chat(spawner, "Success! Your trap caught [user]")
- var/turf/T = get_turf(src)
- stored_obj.forceMove(T)
- playsound(T,'sound/effects/explosion2.ogg', 200, 1)
- new /obj/effect/temp_visual/explosion(T)
- user.ex_act(EXPLODE_HEAVY)
- qdel(src)
- else
- to_chat(user, "[src] glows with a strange light, and you don't touch it.")
-
-/obj/guardian_bomb/Bump(atom/A)
- detonate(A)
- ..()
-
-/obj/guardian_bomb/attackby(mob/living/user)
- detonate(user)
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/guardian_bomb/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
- detonate(user)
-
-/obj/guardian_bomb/examine(mob/user)
- . = stored_obj.examine(user)
- if(get_dist(user,src)<=2)
- . += "It glows with a strange light!"
+/mob/living/simple_animal/hostile/guardian/bomb/proc/on_failure(atom/bomb)
+ to_chat(src, "Failure! Your trap didn't catch anyone this time.")
diff --git a/code/modules/mob/living/simple_animal/guardian/types/standard.dm b/code/modules/mob/living/simple_animal/guardian/types/standard.dm
index 2285167df5..d7970daa29 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/standard.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/standard.dm
@@ -3,7 +3,7 @@
melee_damage_lower = 20
melee_damage_upper = 20
obj_damage = 80
- next_move_modifier = 0.5 //attacks 50% faster
+ action_cooldown_mod = 0.5 //attacks 50% faster
environment_smash = ENVIRONMENT_SMASH_WALLS
playstyle_string = "As a standard type you have no special abilities, but take half damage and have powerful attack capable of smashing through walls."
magic_fluff_string = "..And draw the Assistant, faceless and generic, but never to be underestimated."
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index 5dbf3e8e3b..da16ec581b 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -29,8 +29,11 @@
var/armored = FALSE
obj_damage = 60
- melee_damage_lower = 20
- melee_damage_upper = 30
+ melee_damage_lower = 15 // i know it's like half what it used to be, but bears cause bleeding like crazy now so it works out
+ melee_damage_upper = 15
+ wound_bonus = -5
+ bare_wound_bonus = 10 // BEAR wound bonus am i right
+ sharpness = SHARP_EDGED
attack_verb_continuous = "claws"
attack_verb_simple = "claw"
attack_sound = 'sound/weapons/bladeslice.ogg'
@@ -69,8 +72,9 @@
icon_dead = "combatbear_dead"
faction = list("russian")
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/bear = 5, /obj/item/clothing/head/bearpelt = 1, /obj/item/bear_armor = 1)
- melee_damage_lower = 25
- melee_damage_upper = 35
+ melee_damage_lower = 18
+ melee_damage_upper = 20
+ wound_bonus = 0
armour_penetration = 20
health = 120
maxHealth = 120
@@ -99,8 +103,9 @@
A.maxHealth += 60
A.health += 60
A.armour_penetration += 20
- A.melee_damage_lower += 5
+ A.melee_damage_lower += 3
A.melee_damage_upper += 5
+ A.wound_bonus += 5
A.update_icons()
to_chat(user, "You strap the armor plating to [A] and sharpen [A.p_their()] claws with the nail filer. This was a great idea.")
qdel(src)
@@ -131,7 +136,7 @@ mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Seve
if(health < maxHealth)
heal_overall_damage(10) //Fast life regen, makes it hard for you to get eaten to death.
-/mob/living/simple_animal/hostile/bear/butter/attack_hand(mob/living/L) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER.
+/mob/living/simple_animal/hostile/bear/butter/on_attack_hand(mob/living/L) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER.
..()
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
L.reagents.add_reagent(/datum/reagent/consumable/nutriment, 1)
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 945842d5ed..5ed3cd0cdd 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -523,9 +523,9 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega
if(ranged && ranged_cooldown <= world.time)
target = A
OpenFire(A)
- ..()
-
-
+ DelayNextAction()
+ . = ..()
+ return TRUE
////// AI Status ///////
/mob/living/simple_animal/hostile/proc/AICanContinue(var/list/possible_targets)
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
index 51f61fa158..55046d6555 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
@@ -81,7 +81,7 @@
/obj/structure/leaper_bubble/Initialize()
. = ..()
- float(on = TRUE)
+ INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()
@@ -136,7 +136,7 @@
target = A
if(!isturf(loc))
return
- if(next_move > world.time)
+ if(!CheckActionCooldown())
return
if(hopping)
return
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index 3ef4ef9be9..5c1229c130 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -70,7 +70,7 @@ Difficulty: Medium
/obj/item/melee/transforming/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
target.add_stun_absorption("miner", 10, INFINITY)
- ..()
+ . = ..()
target.stun_absorption -= "miner"
/obj/item/projectile/kinetic/miner
@@ -86,8 +86,8 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
var/adjustment_amount = amount * 0.1
- if(world.time + adjustment_amount > next_move)
- changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
+ if(world.time + adjustment_amount > next_action)
+ DelayNextAction(adjustment_amount, considered_action = FALSE, flush = TRUE) //attacking it interrupts it attacking, but only briefly
. = ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
@@ -109,7 +109,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
if(QDELETED(target))
return
- if(next_move > world.time || !Adjacent(target)) //some cheating
+ if(!CheckActionCooldown() || !Adjacent(target)) //some cheating
INVOKE_ASYNC(src, .proc/quick_attack_loop)
return
face_atom(target)
@@ -125,8 +125,8 @@ Difficulty: Medium
adjustHealth(-(L.maxHealth * 0.5))
L.gib()
return TRUE
- changeNext_move(CLICK_CD_MELEE)
- miner_saw.melee_attack_chain(src, target)
+ miner_saw.melee_attack_chain(src, target, null, ATTACK_IGNORE_CLICKDELAY)
+ FlushCurrentAction()
if(guidance)
adjustHealth(-2)
transform_weapon()
@@ -161,19 +161,19 @@ Difficulty: Medium
face_atom(target)
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
Shoot(target)
- changeNext_move(CLICK_CD_RANGE)
+ DelayNextAction(CLICK_CD_RANGE, flush = TRUE)
//I'm still of the belief that this entire proc needs to be wiped from existence.
// do not take my touching of it to be endorsement of it. ~mso
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
- while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
+ while(!QDELETED(target) && !CheckActionCooldown()) //this is done this way because next_move can change to be sooner while we sleep.
stoplag(1)
- sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
+ sleep((next_action - world.time) * 1.5) //but don't ask me what the fuck this is about
if(QDELETED(target))
return
- if(dashing || next_move > world.time || !Adjacent(target))
- if(dashing && next_move <= world.time)
- next_move = world.time + 1
+ if(dashing || !CheckActionCooldown() || !Adjacent(target))
+ if(dashing && next_action <= world.time)
+ SetNextAction(1, considered_action = FALSE, immediate = FALSE, flush = TRUE)
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
return
AttackingTarget()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index aa4ff328b5..18abb019d3 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -385,10 +385,7 @@ Difficulty: Very Hard
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
-/obj/machinery/anomalous_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/machinery/anomalous_crystal/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
ActivationReaction(user, ACTIVATE_TOUCH)
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 062a4c9a43..a1ecde40b8 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -4,6 +4,11 @@
#define SWOOP_DAMAGEABLE 1
#define SWOOP_INVULNERABLE 2
+///used whenever the drake generates a hotspot
+#define DRAKE_FIRE_TEMP 500
+///used whenever the drake generates a hotspot
+#define DRAKE_FIRE_EXPOSURE 50
+
/*
ASH DRAKE
@@ -148,7 +153,7 @@ Difficulty: Medium
break
range--
new /obj/effect/hotspot(J)
- J.hotspot_expose(700,50,1)
+ J.hotspot_expose(DRAKE_FIRE_TEMP, DRAKE_FIRE_EXPOSURE, 1)
for(var/mob/living/L in J.contents - hit_things)
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
continue
@@ -404,7 +409,7 @@ Difficulty: Medium
if(istype(T, /turf/closed))
break
new /obj/effect/hotspot(T)
- T.hotspot_expose(700,50,1)
+ T.hotspot_expose(DRAKE_FIRE_TEMP,DRAKE_FIRE_EXPOSURE,1)
for(var/mob/living/L in T.contents)
if(L in hit_list || L == source)
continue
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index a66ee7b1de..c00d7c3130 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -643,7 +643,7 @@ Difficulty: Normal
to_chat(L, "You're struck by a [name]!")
var/limb_to_hit = L.get_bodypart(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
var/armor = L.run_armor_check(limb_to_hit, "melee", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 50, "Your armor was penetrated by [src]!")
- L.apply_damage(damage, BURN, limb_to_hit, armor)
+ L.apply_damage(damage, BURN, limb_to_hit, armor, wound_bonus=CANT_WOUND)
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L //mobs find and damage you...
if(H.stat == CONSCIOUS && !H.target && H.AIStatus != AI_OFF && !H.client)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
index 4da8a90b23..78c02fb7a7 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -52,6 +52,8 @@ Difficulty: Medium
elimination = 1
appearance_flags = 0
mouse_opacity = MOUSE_OPACITY_ICON
+ wound_bonus = -40
+ bare_wound_bonus = 20
/mob/living/simple_animal/hostile/megafauna/legion/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
index ed189f052d..869f29951b 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
@@ -129,7 +129,7 @@ Difficulty: Hard
to_chat(L, "[src]'s ground slam shockwave sends you flying!")
var/turf/thrownat = get_ranged_target_turf_direct(src, L, 8, rand(-10, 10))
L.throw_at(thrownat, 8, 2, src, TRUE) //, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
- L.apply_damage(20, BRUTE)
+ L.apply_damage(20, BRUTE, wound_bonus=CANT_WOUND)
shake_camera(L, 2, 1)
all_turfs -= T
sleep(delay)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
index c4f78b6e26..11cc0fe67e 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
@@ -105,7 +105,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L, attackchain_flags = NONE, damage_multiplier = 1)
if(L != set_target)
- L.changeNext_move(I.click_delay) //pre_attacked_by not called
+ I.ApplyAttackCooldown(L, src)
return
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index 982b91c2c9..87ec79abcf 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -148,7 +148,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
desc = "You're not quite sure how a signal can be menacing."
invisibility = 100
-/obj/structure/elite_tumor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/elite_tumor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(ishuman(user))
switch(activity)
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 4c9afd3784..9101430ccc 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -170,7 +170,7 @@
Bruise()
..()
-/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
+/mob/living/simple_animal/hostile/mushroom/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) // the attack was blocked
return
diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
index 3620e3ee5f..e21e3e0693 100644
--- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm
+++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
@@ -86,7 +86,7 @@
.=..()
START_PROCESSING(SSprocessing, src)
-/obj/structure/spawner/nether/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/spawner/nether/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
user.visible_message("[user] is violently pulled into the link!", \
"Touching the portal, you are quickly pulled through into a world of unimaginable horror!")
contents.Add(user)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index 03aac4037a..dec2159dc0 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -37,6 +37,10 @@
var/banana_type = /obj/item/grown/bananapeel
var/attack_reagent
+/mob/living/simple_animal/hostile/retaliate/clown/Initialize(mapload)
+ . = ..()
+ faction |= "clown"
+
/mob/living/simple_animal/hostile/retaliate/clown/handle_temperature_damage()
if(bodytemperature < minbodytemp)
adjustBruteLoss(10)
@@ -47,7 +51,7 @@
else
clear_alert("temp")
-/mob/living/simple_animal/hostile/retaliate/clown/attack_hand(mob/living/carbon/human/M)
+/mob/living/simple_animal/hostile/retaliate/clown/on_attack_hand(mob/living/carbon/human/M)
..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 9a362b680d..fd37bb26aa 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -77,6 +77,9 @@
/mob/living/simple_animal/hostile/syndicate/melee
melee_damage_lower = 15
melee_damage_upper = 15
+ wound_bonus = -10
+ bare_wound_bonus = 20
+ sharpness = SHARP_EDGED
icon_state = "syndicate_knife"
icon_living = "syndicate_knife"
loot = list(/obj/effect/gibspawner/human)
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index de8a6fb6a0..4fcb1ed5bf 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -271,7 +271,7 @@
* Attack responces
*/
//Humans, monkeys, aliens
-/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M)
+/mob/living/simple_animal/parrot/on_attack_hand(mob/living/carbon/M)
..()
if(client)
return
diff --git a/code/modules/mob/living/simple_animal/pickle.dm b/code/modules/mob/living/simple_animal/pickle.dm
index c5469024e6..78c524fed9 100644
--- a/code/modules/mob/living/simple_animal/pickle.dm
+++ b/code/modules/mob/living/simple_animal/pickle.dm
@@ -20,12 +20,12 @@
laugher.emote("laugh")
/mob/living/simple_animal/pickle/death()
- ..()
if(original_body)
original_body.adjustOrganLoss(ORGAN_SLOT_BRAIN, 200) //to be fair, you have to have a very high iq to understand-
original_body.forceMove(get_turf(src))
if(mind)
mind.transfer_to(original_body)
+ ..()
/mob/living/simple_animal/pickle/wabbajack_act() //restore users name before its used on the new mob
if(original_body)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 1a646ea73e..706bcc46f5 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -140,6 +140,13 @@
///What kind of footstep this mob should have. Null if it shouldn't have any.
var/footstep_type
+ //How much wounding power it has
+ var/wound_bonus = CANT_WOUND
+ //How much bare wounding power it has
+ var/bare_wound_bonus = 0
+ //If the attacks from this are sharp
+ var/sharpness = SHARP_NONE
+
/mob/living/simple_animal/Initialize()
. = ..()
GLOB.simple_animals[AIStatus] += src
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index f7876b3516..1bdd988694 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -296,7 +296,7 @@
discipline_slime(user)
return ..()
-/mob/living/simple_animal/slime/attack_hand(mob/living/carbon/human/M)
+/mob/living/simple_animal/slime/on_attack_hand(mob/living/carbon/human/M)
if(buckled)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if(buckled == M)
@@ -356,7 +356,7 @@
attacked += 10
if(prob(25))
user.do_attack_animation(src)
- user.changeNext_move(CLICK_CD_MELEE)
+ W.ApplyAttackCooldown(user, src)
to_chat(user, "[W] passes right through [src]!")
return
if(Discipline && prob(50)) // wow, buddy, why am I getting attacked??
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 0029300936..87fd0cf609 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -500,6 +500,15 @@
S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
return S
+///////////////////////////////// OFF BALANCE/SHOVIES ////////////////////////
+/mob/living/proc/ShoveOffBalance(amount)
+ var/datum/status_effect/off_balance/B = has_status_effect(STATUS_EFFECT_OFF_BALANCE)
+ if(B)
+ B.duration = max(world.time + amount, B.duration)
+ else if(amount > 0)
+ B = apply_status_effect(STATUS_EFFECT_OFF_BALANCE, amount)
+ return B
+
///////////////////////////////// FROZEN /////////////////////////////////////
/mob/living/proc/IsFrozen()
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index b7546becd8..31bfb5621f 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -13,9 +13,7 @@
hud_used.show_hud(hud_used.hud_version)
hud_used.update_ui_style(ui_style2icon(client.prefs.UI_style))
- next_move = 1
-
- ..()
+ . = ..()
reset_perspective(loc)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index dbf7b7f350..03a3ab1001 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -11,6 +11,10 @@
blocks_emissive = EMISSIVE_BLOCK_GENERIC
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
+
+ attack_hand_is_action = TRUE
+ attack_hand_unwieldlyness = CLICK_CD_MELEE
+ attack_hand_speed = 0
/// What receives our keyboard input. src by default.
var/datum/focus
@@ -35,7 +39,6 @@
var/list/logging = list()
var/atom/machine = null
- var/next_move = null
var/create_area_cooldown
/// Whether or not the mob is currently being transformed into another mob or into another state of being. This will prevent it from moving or doing realistically anything.
/// Don't you DARE use this for a cheap way to ensure someone is stunned in your code.
@@ -123,6 +126,9 @@
var/list/progressbars = null //for stacking do_after bars
+ ///For storing what do_after's someone has, in case we want to restrict them to only one of a certain do_after at a time
+ var/list/do_afters
+
var/list/mousemove_intercept_objects
var/datum/click_intercept
@@ -155,4 +161,4 @@
/// The timer that will remove our indicator for early aborts (like when an user finishes their message)
var/typing_indicator_timerid
/// Current state of our typing indicator. Used for cut overlay, DO NOT RUNTIME ASSIGN OTHER THAN FROM SHOW/CLEAR. Used to absolutely ensure we do not get stuck overlays.
- var/typing_indicator_current
+ var/mutable_appearance/typing_indicator_current
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 3ceafe4a11..7d97270808 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -43,6 +43,11 @@
if(GLOB.say_disabled) //This is here to try to identify lag problems
to_chat(usr, "Speech is currently admin-disabled.")
return
+
+ if(length(message) > MAX_MESSAGE_LEN)
+ to_chat(usr, message)
+ to_chat(usr, "^^^----- The preceeding message has been DISCARDED for being over the maximum length of [MAX_MESSAGE_LEN]. It has NOT been sent! -----^^^")
+ return
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
clear_typing_indicator() // clear it immediately!
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 5ed24af726..5db3ccf216 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -37,7 +37,7 @@ proc/get_top_level_mob(var/mob/S)
to_chat(user, "You cannot send IC messages (muted).")
return FALSE
else if(!params)
- var/subtle_emote = stripped_multiline_input(user, "Choose an emote to display.", "Subtle", null, MAX_MESSAGE_LEN)
+ var/subtle_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Subtle", null, MAX_MESSAGE_LEN)
if(subtle_emote && !check_invalid(user, subtle_emote))
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
switch(type)
@@ -98,7 +98,7 @@ proc/get_top_level_mob(var/mob/S)
to_chat(user, "You cannot send IC messages (muted).")
return FALSE
else if(!params)
- var/subtle_emote = stripped_multiline_input(user, "Choose an emote to display.", "Subtler" , null, MAX_MESSAGE_LEN)
+ var/subtle_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Subtler" , null, MAX_MESSAGE_LEN)
if(subtle_emote && !check_invalid(user, subtle_emote))
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
switch(type)
diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm
index f28cbe4385..6154828f4d 100644
--- a/code/modules/mob/typing_indicator.dm
+++ b/code/modules/mob/typing_indicator.dm
@@ -15,13 +15,23 @@ GLOBAL_LIST_EMPTY(typing_indicator_overlays)
/mob/proc/get_typing_indicator_icon_state()
return typing_indicator_state
+/// Generates the mutable appearance for typing indicator. Should prevent stuck overlays.
+/mob/proc/generate_typing_indicator()
+ var/state = get_typing_indicator_icon_state()
+ if(ispath(state))
+ var/atom/thing = new state(null)
+ var/mutable_appearance/generated = new(thing)
+ return generated
+ else
+ CRASH("Unsupported typing indicator state: [state]")
+
/**
* Displays typing indicator.
* @param timeout_override - Sets how long until this will disappear on its own without the user finishing their message or logging out. Defaults to src.typing_indicator_timeout
* @param state_override - Sets the state that we will fetch. Defaults to src.get_typing_indicator_icon_state()
* @param force - shows even if src.typing_indcator_enabled is FALSE.
*/
-/mob/proc/display_typing_indicator(timeout_override = TYPING_INDICATOR_TIMEOUT, state_override = get_typing_indicator_icon_state(), force = FALSE)
+/mob/proc/display_typing_indicator(timeout_override = TYPING_INDICATOR_TIMEOUT, state_override = generate_typing_indicator(), force = FALSE)
if((!typing_indicator_enabled && !force) || typing_indicator_current)
return
typing_indicator_current = state_override
diff --git a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm
index eeb5212aeb..b5f3bae53d 100644
--- a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm
+++ b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm
@@ -73,4 +73,4 @@
add_status_message("[client.username] has changed channel title from [title] to [newtitle]")
title = newtitle
-#undef MAX_CHANNELS
\ No newline at end of file
+#undef MAX_CHANNELS
diff --git a/code/modules/modular_computers/computers/_modular_computer_shared.dm b/code/modules/modular_computers/computers/_modular_computer_shared.dm
new file mode 100644
index 0000000000..8ca93e8347
--- /dev/null
+++ b/code/modules/modular_computers/computers/_modular_computer_shared.dm
@@ -0,0 +1,64 @@
+
+/obj/proc/is_modular_computer()
+ return
+
+/obj/proc/get_modular_computer_part(part_type)
+ return null
+
+/obj/item/modular_computer/is_modular_computer()
+ return TRUE
+
+/obj/item/modular_computer/get_modular_computer_part(part_type)
+ if(!part_type)
+ stack_trace("get_modular_computer_part() called without a valid part_type")
+ return null
+ return all_components[part_type]
+
+
+/obj/machinery/modular_computer/is_modular_computer()
+ return TRUE
+
+/obj/machinery/modular_computer/get_modular_computer_part(part_type)
+ if(!part_type)
+ stack_trace("get_modular_computer_part() called without a valid part_type")
+ return null
+ return cpu?.all_components[part_type]
+
+
+/obj/proc/get_modular_computer_parts_examine(mob/user)
+ . = list()
+ if(!is_modular_computer())
+ return
+
+ var/user_is_adjacent = Adjacent(user) //don't reveal full details unless they're close enough to see it on the screen anyway.
+
+ var/obj/item/computer_hardware/ai_slot/ai_slot = get_modular_computer_part(MC_AI)
+ if(ai_slot)
+ if(ai_slot.stored_card)
+ if(user_is_adjacent)
+ . += "It has a slot installed for an intelliCard which contains: [ai_slot.stored_card.name]"
+ else
+ . += "It has a slot installed for an intelliCard, which appears to be occupied."
+ . += "Alt-click to eject the intelliCard."
+ else
+ . += "It has a slot installed for an intelliCard."
+
+ var/obj/item/computer_hardware/card_slot/card_slot = get_modular_computer_part(MC_CARD)
+ if(card_slot)
+ if(card_slot.stored_card || card_slot.stored_card2)
+ var/obj/item/card/id/first_ID = card_slot.stored_card
+ var/obj/item/card/id/second_ID = card_slot.stored_card2
+ var/multiple_cards = istype(first_ID) && istype(second_ID)
+ if(user_is_adjacent)
+ . += "It has two slots for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]."
+ else
+ . += "It has two slots for identification cards installed, [multiple_cards ? "both of which appear" : "and one of them appears"] to be occupied."
+ . += "Alt-click [src] to eject the identification card[multiple_cards ? "s":""]."
+ else
+ . += "It has two slots installed for identification cards."
+
+ var/obj/item/computer_hardware/printer/printer_slot = get_modular_computer_part(MC_PRINT)
+ if(printer_slot)
+ . += "It has a printer installed."
+ if(user_is_adjacent)
+ . += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].]"
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index d722197bd9..67c04de13f 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -7,6 +7,7 @@
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
+ var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0
@@ -98,7 +99,7 @@
if(issilicon(usr))
return
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
- if(usr.canUseTopic(src))
+ if(usr.canUseTopic(src, BE_CLOSE))
card_slot.try_eject(null, usr)
// Eject ID card from computer, if it has ID slot with card inside.
@@ -109,7 +110,7 @@
if(issilicon(usr))
return
var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI]
- if(usr.canUseTopic(src))
+ if(usr.canUseTopic(src, BE_CLOSE))
ai_slot.try_eject(null, usr,1)
@@ -121,17 +122,17 @@
if(issilicon(usr))
return
- if(usr.canUseTopic(src))
+ if(usr.canUseTopic(src, BE_CLOSE))
var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD]
if(uninstall_component(portable_drive, usr))
portable_drive.verb_pickup()
/obj/item/modular_computer/AltClick(mob/user)
- . = ..()
+ ..()
if(issilicon(user))
return
- if(user.canUseTopic(src))
+ if(user.canUseTopic(src, BE_CLOSE))
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI]
var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD]
@@ -143,7 +144,7 @@
return
if(ai_slot)
ai_slot.try_eject(null, user)
- return TRUE
+
// Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs.
/obj/item/modular_computer/GetAccess()
@@ -175,7 +176,7 @@
/obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
var/mob/M = usr
- if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src))
+ if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src, BE_CLOSE))
return attack_self(M)
return ..()
@@ -195,12 +196,22 @@
/obj/item/modular_computer/emag_act(mob/user)
. = ..()
- if(obj_flags & EMAGGED)
- to_chat(user, "\The [src] was already emagged.")
- return
- obj_flags |= EMAGGED
- to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.")
- return TRUE
+ if(!enabled)
+ to_chat(user, "You'd need to turn the [src] on first.")
+ return FALSE
+ obj_flags |= EMAGGED //Mostly for consistancy purposes; the programs will do their own emag handling
+ var/newemag = FALSE
+ var/obj/item/computer_hardware/hard_drive/drive = all_components[MC_HDD]
+ for(var/datum/computer_file/program/app in drive.stored_files)
+ if(!istype(app))
+ continue
+ if(app.run_emag())
+ newemag = TRUE
+ if(newemag)
+ to_chat(user, "You swipe \the [src]. A console window momentarily fills the screen, with white text rapidly scrolling past.")
+ return TRUE
+ to_chat(user, "You swipe \the [src]. A console window fills the screen, but it quickly closes itself after only a few lines are written to it.")
+ return FALSE
/obj/item/modular_computer/examine(mob/user)
. = ..()
@@ -209,13 +220,14 @@
else if(obj_integrity < max_integrity)
. += "It is damaged."
+ . += get_modular_computer_parts_examine(user)
+
/obj/item/modular_computer/update_icon_state()
if(!enabled)
icon_state = icon_state_unpowered
else
icon_state = icon_state_powered
-
/obj/item/modular_computer/update_overlays()
. = ..()
if(!display_overlays)
@@ -306,6 +318,8 @@
/obj/item/modular_computer/proc/get_header_data()
var/list/data = list()
+ data["PC_device_theme"] = device_theme
+
var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL]
var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
@@ -407,17 +421,17 @@
if(install_component(W, user))
return
- if(istype(W, /obj/item/wrench))
+ if(W.tool_behaviour == TOOL_WRENCH)
if(all_components.len)
to_chat(user, "Remove all components from \the [src] before disassembling it.")
return
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
- physical.visible_message("\The [src] has been disassembled by [user].")
+ physical.visible_message("\The [src] is disassembled by [user].")
relay_qdel()
qdel(src)
return
- if(istype(W, /obj/item/weldingtool))
+ if(W.tool_behaviour == TOOL_WELDER)
if(obj_integrity == max_integrity)
to_chat(user, "\The [src] does not require repairs.")
return
@@ -431,7 +445,7 @@
to_chat(user, "You repair \the [src].")
return
- if(istype(W, /obj/item/screwdriver))
+ if(W.tool_behaviour == TOOL_SCREWDRIVER)
if(!all_components.len)
to_chat(user, "This device doesn't have any components installed.")
return
@@ -440,7 +454,7 @@
var/obj/item/computer_hardware/H = all_components[h]
component_names.Add(H.name)
- var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names
+ var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in sortList(component_names)
if(!choice)
return
diff --git a/code/modules/modular_computers/computers/item/computer_damage.dm b/code/modules/modular_computers/computers/item/computer_damage.dm
index 6664b449bd..b510f8aded 100644
--- a/code/modules/modular_computers/computers/item/computer_damage.dm
+++ b/code/modules/modular_computers/computers/item/computer_damage.dm
@@ -18,13 +18,13 @@
/obj/item/modular_computer/proc/break_apart()
if(!(flags_1 & NODECONSTRUCT_1))
- physical.visible_message("\The [src] breaks apart!")
+ physical.visible_message("\The [src] breaks apart!")
var/turf/newloc = get_turf(src)
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
for(var/C in all_components)
var/obj/item/computer_hardware/H = all_components[C]
if(QDELETED(H))
- return
+ continue
uninstall_component(H)
H.forceMove(newloc)
if(prob(25))
diff --git a/code/modules/modular_computers/computers/item/computer_power.dm b/code/modules/modular_computers/computers/item/computer_power.dm
index d3c65f86ec..b5188f43d9 100644
--- a/code/modules/modular_computers/computers/item/computer_power.dm
+++ b/code/modules/modular_computers/computers/item/computer_power.dm
@@ -28,8 +28,7 @@
/obj/item/modular_computer/get_cell()
var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL]
- if(battery_module && battery_module.battery)
- return battery_module.battery
+ return battery_module?.get_cell()
// Used in following function to reduce copypaste
/obj/item/modular_computer/proc/power_failure()
diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm
index 6266daad2b..fd017e2b0f 100644
--- a/code/modules/modular_computers/computers/item/computer_ui.dm
+++ b/code/modules/modular_computers/computers/item/computer_ui.dm
@@ -3,7 +3,7 @@
ui_interact(user)
// Operates TGUI
-/obj/item/modular_computer/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)
+/obj/item/modular_computer/ui_interact(mob/user, datum/tgui/ui)
if(!enabled)
if(ui)
ui.close()
@@ -14,7 +14,7 @@
return 0
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
- if(!screen_on && !hasSiliconAccessInArea(user))
+ if(!screen_on && !issilicon(user))
if(ui)
ui.close()
return 0
@@ -33,19 +33,17 @@
to_chat(user, "\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning.")
return // No HDD, No HDD files list or no stored files. Something is very broken.
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
- var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
- assets.send(user)
- assets = get_asset_datum(/datum/asset/simple/arcade)
- assets.send(user)
- ui = new(user, src, ui_key, "NtosMain", "NtOS Main menu", 400, 500, master_ui, state)
+ ui = new(user, src, "NtosMain")
+ ui.set_autoupdate(TRUE)
ui.open()
- ui.set_autoupdate(state = 1)
+ ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
/obj/item/modular_computer/ui_data(mob/user)
var/list/data = get_header_data()
+ data["device_theme"] = device_theme
data["programs"] = list()
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
for(var/datum/computer_file/program/P in hard_drive.stored_files)
@@ -143,6 +141,7 @@
set_light(comp_light_luminosity, 1, comp_light_color)
else
set_light(0)
+ return TRUE
if("PC_light_color")
var/mob/user = usr
diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm
index 4e4c1fcdce..5927d57a0b 100644
--- a/code/modules/modular_computers/computers/item/laptop.dm
+++ b/code/modules/modular_computers/computers/item/laptop.dm
@@ -7,6 +7,7 @@
icon_state_powered = "laptop"
icon_state_unpowered = "laptop-off"
icon_state_menu = "menu"
+ display_overlays = FALSE
hardware_flag = PROGRAM_LAPTOP
max_hardware_size = 2
@@ -18,8 +19,8 @@
screen_on = 0 // Starts closed
var/start_open = TRUE // unless this var is set to 1
var/icon_state_closed = "laptop-closed"
- display_overlays = FALSE
var/w_class_open = WEIGHT_CLASS_BULKY
+ var/slowdown_open = TRUE
/obj/item/modular_computer/laptop/examine(mob/user)
. = ..()
@@ -38,6 +39,13 @@
else
. = ..()
+/obj/item/modular_computer/laptop/update_overlays()
+ if(screen_on)
+ return ..()
+ else
+ cut_overlays()
+ icon_state = icon_state_closed
+
/obj/item/modular_computer/laptop/attack_self(mob/user)
if(!screen_on)
try_toggle_open(user)
@@ -64,10 +72,8 @@
return
M.put_in_hand(src, H.held_index)
-/obj/item/modular_computer/laptop/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/modular_computer/laptop/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
- if(.)
- return
if(screen_on && isturf(loc))
return attack_self(user)
@@ -76,7 +82,7 @@
return
if(!isturf(loc) && !ismob(loc)) // No opening it in backpack.
return
- if(!user.canUseTopic(src))
+ if(!user.canUseTopic(src, BE_CLOSE))
return
toggle_open(user)
@@ -85,15 +91,17 @@
/obj/item/modular_computer/laptop/AltClick(mob/user)
if(screen_on) // Close it.
try_toggle_open(user)
- return TRUE
- return ..()
+ else
+ return ..()
/obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null)
if(screen_on)
to_chat(user, "You close \the [src].")
+ slowdown = initial(slowdown)
w_class = initial(w_class)
else
to_chat(user, "You open \the [src].")
+ slowdown = slowdown_open
w_class = w_class_open
screen_on = !screen_on
diff --git a/code/modules/modular_computers/computers/item/laptop_presets.dm b/code/modules/modular_computers/computers/item/laptop_presets.dm
index e50392e3b3..6bc2919bea 100644
--- a/code/modules/modular_computers/computers/item/laptop_presets.dm
+++ b/code/modules/modular_computers/computers/item/laptop_presets.dm
@@ -20,4 +20,3 @@
/obj/item/modular_computer/laptop/preset/civilian/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
- hard_drive.store_file(new/datum/computer_file/program/nttransfer())
diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm
index 81e2cb95e6..c79d7a9361 100644
--- a/code/modules/modular_computers/computers/item/processor.dm
+++ b/code/modules/modular_computers/computers/item/processor.dm
@@ -1,4 +1,5 @@
// Held by /obj/machinery/modular_computer to reduce amount of copy-pasted code.
+//TODO: REFACTOR THIS SPAGHETTI CODE, MAKE IT A COMPUTER_HARDWARE COMPONENT OR REMOVE IT
/obj/item/modular_computer/processor
name = "processing unit"
desc = "You shouldn't see this. If you do, report it."
@@ -11,19 +12,22 @@
var/obj/machinery/modular_computer/machinery_computer = null
/obj/item/modular_computer/processor/Destroy()
- . = ..()
if(machinery_computer && (machinery_computer.cpu == src))
machinery_computer.cpu = null
+ machinery_computer.UnregisterSignal(src, COMSIG_ATOM_UPDATED_ICON)
machinery_computer = null
-
-/obj/item/modular_computer/processor/Initialize(mapload)
. = ..()
- if(!loc || !istype(loc, /obj/machinery/modular_computer))
+
+/obj/item/modular_computer/processor/New(comp) //intentional new probably
+ ..()
+ STOP_PROCESSING(SSobj, src) // Processed by its machine
+
+ if(!comp || !istype(comp, /obj/machinery/modular_computer))
CRASH("Inapropriate type passed to obj/item/modular_computer/processor/New()! Aborting.")
// Obtain reference to machinery computer
all_components = list()
idle_threads = list()
- machinery_computer = loc
+ machinery_computer = comp
machinery_computer.cpu = src
hardware_flag = machinery_computer.hardware_flag
max_hardware_size = machinery_computer.max_hardware_size
@@ -39,7 +43,7 @@
qdel(machinery_computer)
// This thing is not meant to be used on it's own, get topic data from our machinery owner.
-//obj/item/modular_computer/processor/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
+//obj/item/modular_computer/processor/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
// if(!machinery_computer)
// return 0
@@ -69,3 +73,6 @@
machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_disk
if(MC_AI)
machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_card
+
+/obj/item/modular_computer/processor/attack_ghost(mob/user)
+ ui_interact(user)
diff --git a/code/modules/modular_computers/computers/item/tablet.dm b/code/modules/modular_computers/computers/item/tablet.dm
index a371e97ec6..41a256467f 100644
--- a/code/modules/modular_computers/computers/item/tablet.dm
+++ b/code/modules/modular_computers/computers/item/tablet.dm
@@ -5,6 +5,7 @@
icon_state_unpowered = "tablet"
icon_state_powered = "tablet"
icon_state_menu = "menu"
+ //worn_icon_state = "tablet"
hardware_flag = PROGRAM_TABLET
max_hardware_size = 1
w_class = WEIGHT_CLASS_SMALL
@@ -32,3 +33,17 @@
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
comp_light_luminosity = 6.3
has_variants = FALSE
+
+/// Given to Nuke Ops members.
+/obj/item/modular_computer/tablet/nukeops
+ icon_state = "tablet-syndicate"
+ comp_light_luminosity = 6.3
+ has_variants = FALSE
+ device_theme = "syndicate"
+
+/obj/item/modular_computer/tablet/nukeops/emag_act(mob/user)
+ if(!enabled)
+ to_chat(user, "You'd need to turn the [src] on first.")
+ return FALSE
+ to_chat(user, "You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\".")
+ return FALSE
diff --git a/code/modules/modular_computers/computers/item/tablet_presets.dm b/code/modules/modular_computers/computers/item/tablet_presets.dm
index f516d3802f..7cca8ea5b4 100644
--- a/code/modules/modular_computers/computers/item/tablet_presets.dm
+++ b/code/modules/modular_computers/computers/item/tablet_presets.dm
@@ -22,23 +22,38 @@
/obj/item/modular_computer/tablet/preset/cargo/Initialize()
. = ..()
+ var/obj/item/computer_hardware/hard_drive/small/hard_drive = new
install_component(new /obj/item/computer_hardware/processor_unit/small)
install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
- install_component(new /obj/item/computer_hardware/hard_drive/small)
+ install_component(hard_drive)
install_component(new /obj/item/computer_hardware/network_card)
install_component(new /obj/item/computer_hardware/printer/mini)
+ hard_drive.store_file(new /datum/computer_file/program/bounty)
+ //hard_drive.store_file(new /datum/computer_file/program/shipping)
-/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize() // Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink.
+/// Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink.
+/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize()
. = ..()
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = new
var/datum/computer_file/program/contract_uplink/uplink = new
+
active_program = uplink
uplink.program_state = PROGRAM_STATE_ACTIVE
uplink.computer = src
+
hard_drive.store_file(uplink)
+
install_component(new /obj/item/computer_hardware/processor_unit/small)
install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
install_component(hard_drive)
install_component(new /obj/item/computer_hardware/network_card)
install_component(new /obj/item/computer_hardware/card_slot)
- install_component(new /obj/item/computer_hardware/printer/mini)
\ No newline at end of file
+ install_component(new /obj/item/computer_hardware/printer/mini)
+
+/// Given to Nuke Ops members.
+/obj/item/modular_computer/tablet/nukeops/Initialize()
+ . = ..()
+ install_component(new /obj/item/computer_hardware/processor_unit/small)
+ install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
+ install_component(new /obj/item/computer_hardware/hard_drive/small/nukeops)
+ install_component(new /obj/item/computer_hardware/network_card)
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index 066f1fb98b..9d29b23e76 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -46,16 +46,12 @@
desc = "A stationary computer. This one comes preloaded with research programs."
_has_ai = TRUE
-/obj/machinery/modular_computer/console/preset/research/examine(mob/user)
- . = ..()
- . += "Alt-click to eject the intelliCard."
-
/obj/machinery/modular_computer/console/preset/research/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor())
- hard_drive.store_file(new/datum/computer_file/program/nttransfer())
hard_drive.store_file(new/datum/computer_file/program/chatclient())
hard_drive.store_file(new/datum/computer_file/program/aidiag())
+ hard_drive.store_file(new/datum/computer_file/program/robocontrol())
// ===== COMMAND CONSOLE =====
@@ -66,15 +62,27 @@
_has_id_slot = TRUE
_has_printer = TRUE
-/obj/machinery/modular_computer/console/preset/command/examine(mob/user)
- . = ..()
- . += "Alt-click [src] to eject the identification card."
-
/obj/machinery/modular_computer/console/preset/command/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
hard_drive.store_file(new/datum/computer_file/program/card_mod())
+
+// ===== IDENTIFICATION CONSOLE =====
+/obj/machinery/modular_computer/console/preset/id
+ console_department = "Identification"
+ name = "identification console"
+ desc = "A stationary computer. This one comes preloaded with identification modification programs."
+ _has_id_slot = TRUE
+ _has_printer = TRUE
+
+/obj/machinery/modular_computer/console/preset/id/install_programs()
+ var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
+ hard_drive.store_file(new/datum/computer_file/program/chatclient())
+ hard_drive.store_file(new/datum/computer_file/program/card_mod())
+ hard_drive.store_file(new/datum/computer_file/program/job_management())
+ hard_drive.store_file(new/datum/computer_file/program/crew_manifest())
+
// ===== CIVILIAN CONSOLE =====
/obj/machinery/modular_computer/console/preset/civilian
console_department = "Civilian"
@@ -84,5 +92,4 @@
/obj/machinery/modular_computer/console/preset/civilian/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
- hard_drive.store_file(new/datum/computer_file/program/nttransfer())
hard_drive.store_file(new/datum/computer_file/program/arcade())
diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm
index 89c6166a0d..6f016ad147 100644
--- a/code/modules/modular_computers/computers/machinery/modular_computer.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm
@@ -36,6 +36,10 @@
QDEL_NULL(cpu)
return ..()
+/obj/machinery/modular_computer/examine(mob/user)
+ . = ..()
+ . += get_modular_computer_parts_examine(user)
+
/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user)
. = ..()
if(.)
@@ -45,31 +49,31 @@
/obj/machinery/modular_computer/emag_act(mob/user)
. = ..()
- if(cpu)
- . |= cpu.emag_act(user)
+ if(!cpu)
+ to_chat(user, "You'd need to turn the [src] on first.")
+ return FALSE
+ return (cpu.emag_act(user))
-/obj/machinery/modular_computer/update_icon_state()
- if(cpu?.enabled)
- icon_state = icon_state_powered
- else if(stat & NOPOWER || !(cpu?.use_power()))
- icon_state = icon_state_unpowered
+/obj/machinery/modular_computer/update_icon()
+ cut_overlays()
+ icon_state = icon_state_powered
-/obj/machinery/modular_computer/update_overlays()
- . = ..()
if(!cpu || !cpu.enabled)
if (!(stat & NOPOWER) && (cpu && cpu.use_power()))
- . += screen_icon_screensaver
+ add_overlay(screen_icon_screensaver)
+ else
+ icon_state = icon_state_unpowered
set_light(0)
else
set_light(light_strength)
if(cpu.active_program)
- . += cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu
+ add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
else
- . += screen_icon_state_menu
+ add_overlay(screen_icon_state_menu)
if(cpu && cpu.obj_integrity <= cpu.integrity_failure * cpu.max_integrity)
- . += "bsod"
- . += "broken"
+ add_overlay("bsod")
+ add_overlay("broken")
// Eject ID card from computer, if it has ID slot with card inside.
/obj/machinery/modular_computer/proc/eject_id()
@@ -96,9 +100,8 @@
cpu.eject_card()
/obj/machinery/modular_computer/AltClick(mob/user)
- . = ..()
if(cpu)
- return cpu.AltClick(user)
+ cpu.AltClick(user)
//ATTACK HAND IGNORING PARENT RETURN VALUE
// On-click handling. Turns on the computer if it's off and opens the GUI.
@@ -131,8 +134,7 @@
stat &= ~NOPOWER
update_icon()
return
- ..()
- update_icon()
+ . = ..()
/obj/machinery/modular_computer/attackby(var/obj/item/W as obj, mob/user)
if(cpu && !(flags_1 & NODECONSTRUCT_1))
@@ -145,6 +147,13 @@
/obj/machinery/modular_computer/ex_act(severity)
if(cpu)
cpu.ex_act(severity)
+ // switch(severity)
+ // if(EXPLODE_DEVASTATE)
+ // SSexplosions.highobj += cpu
+ // if(EXPLODE_HEAVY)
+ // SSexplosions.medobj += cpu
+ // if(EXPLODE_LIGHT)
+ // SSexplosions.lowobj += cpu
..()
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
diff --git a/code/modules/modular_computers/computers/machinery/modular_console.dm b/code/modules/modular_computers/computers/machinery/modular_console.dm
index 3d4ec22e89..5d596f98e4 100644
--- a/code/modules/modular_computers/computers/machinery/modular_console.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_console.dm
@@ -52,4 +52,4 @@
network_card.identification_string = "Unknown Console"
if(cpu)
cpu.screen_on = 1
- update_icon()
\ No newline at end of file
+ update_icon()
diff --git a/code/modules/modular_computers/documentation.md b/code/modules/modular_computers/documentation.md
index 246da7c3d9..88d059da7a 100644
--- a/code/modules/modular_computers/documentation.md
+++ b/code/modules/modular_computers/documentation.md
@@ -1,5 +1,7 @@
# Modular computer programs
+How module computer programs work
+
Ok. so a quick rundown on how to make a program. This is kind of a shitty documentation, but oh well I was asked to.
## Base setup
diff --git a/code/modules/modular_computers/file_system/computer_file.dm b/code/modules/modular_computers/file_system/computer_file.dm
index 7776fc04d0..4e862c4ae3 100644
--- a/code/modules/modular_computers/file_system/computer_file.dm
+++ b/code/modules/modular_computers/file_system/computer_file.dm
@@ -3,8 +3,8 @@
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
var/size = 1 // File size in GQ. Integers only!
var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file.
- var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means.
- var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc.
+ var/unsendable = FALSE // Whether the file may be sent to someone via NTNet transfer or other means.
+ var/undeletable = FALSE // Whether the file may be deleted. Setting to TRUE prevents deletion/renaming/etc.
var/uid // UID of this file
var/static/file_uid = 0
@@ -24,7 +24,7 @@
return ..()
// Returns independent copy of this file.
-/datum/computer_file/proc/clone(rename = 0)
+/datum/computer_file/proc/clone(rename = FALSE)
var/datum/computer_file/temp = new type
temp.unsendable = unsendable
temp.undeletable = undeletable
@@ -34,4 +34,4 @@
else
temp.filename = filename
temp.filetype = filetype
- return temp
\ No newline at end of file
+ return temp
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 6b5390fc60..12e5ef6e95 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -31,15 +31,10 @@
var/available_on_ntnet = 1
/// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
var/available_on_syndinet = 0
- /// ID of TGUI interface
+ /// Name of the tgui interface
var/tgui_id
- /// Default size of TGUI window, in pixels
- var/ui_x = 575
- var/ui_y = 700
/// Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images!
var/ui_header = null
- ///Assets specific to programs
- var/list/special_assets = list()
/datum/computer_file/program/New(obj/item/modular_computer/comp = null)
..()
@@ -69,23 +64,23 @@
/datum/computer_file/program/proc/generate_network_log(text)
if(computer)
return computer.add_log(text)
- return FALSE
+ return 0
/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null)
if(!(hardware_flag & usage_flags))
if(loud && computer && user)
- to_chat(user, "\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.")
- return FALSE
- return TRUE
+ to_chat(user, "\The [computer] flashes a \"Hardware Error - Incompatible software\" warning.")
+ return 0
+ return 1
/datum/computer_file/program/proc/get_signal(specific_action = 0)
if(computer)
return computer.get_ntnet_status(specific_action)
- return FALSE
+ return 0
// Called by Process() on device that runs us, once every tick.
/datum/computer_file/program/proc/process_tick()
- return TRUE
+ return 1
// Check if the user can run program. Only humans can operate computer. Automatically called in run_program()
// User has to wear their ID for ID Scan to work.
@@ -131,7 +126,7 @@
return TRUE
if(loud)
to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.")
- return FALSE
+ return 0
// This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones
// always include the device here in this proc. This proc basically relays the request to whatever is running the program.
@@ -143,11 +138,25 @@
// This is performed on program startup. May be overridden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(mob/living/user)
- if(can_run(user, TRUE))
+ if(can_run(user, 1))
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
- return TRUE
+ return 1
+ return 0
+
+/**
+ *
+ *Called by the device when it is emagged.
+ *
+ *Emagging the device allows certain programs to unlock new functions. However, the program will
+ *need to be downloaded first, and then handle the unlock on their own in their run_emag() proc.
+ *The device will allow an emag to be run multiple times, so the user can re-emag to run the
+ *override again, should they download something new. The run_emag() proc should return TRUE if
+ *the emagging affected anything, and FALSE if no change was made (already emagged, or has no
+ *emag functions).
+**/
+/datum/computer_file/program/proc/run_emag()
return FALSE
// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
@@ -155,20 +164,14 @@
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
- return TRUE
+ return 1
-
-/datum/computer_file/program/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/datum/computer_file/program/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui && tgui_id)
- var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
- assets.send(user)
- for(var/i in special_assets)
- assets = get_asset_datum(i)
- assets.send(user)
-
- ui = new(user, src, ui_key, tgui_id, filedesc, ui_x, ui_y, state = state)
+ ui = new(user, src, tgui_id, filedesc)
ui.open()
+ ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
// Topic calls are automagically forwarded from NanoModule this program contains.
@@ -177,17 +180,17 @@
// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE.
/datum/computer_file/program/ui_act(action,list/params,datum/tgui/ui)
if(..())
- return TRUE
+ return 1
if(computer)
switch(action)
if("PC_exit")
computer.kill_program()
ui.close()
- return TRUE
+ return 1
if("PC_shutdown")
computer.shutdown_computer()
ui.close()
- return TRUE
+ return 1
if("PC_minimize")
var/mob/user = usr
if(!computer.active_program || !computer.all_components[MC_CPU])
diff --git a/code/modules/modular_computers/file_system/program_events.dm b/code/modules/modular_computers/file_system/program_events.dm
index 279d646cfd..3c1daa5af3 100644
--- a/code/modules/modular_computers/file_system/program_events.dm
+++ b/code/modules/modular_computers/file_system/program_events.dm
@@ -13,6 +13,6 @@
/datum/computer_file/program/proc/event_networkfailure(background)
kill_program(forced = TRUE)
if(background)
- computer.visible_message("\The [computer]'s screen displays an \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error")
+ computer.visible_message("\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error")
else
computer.visible_message("\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.")
diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm
index 4e9cd85577..364ad79737 100644
--- a/code/modules/modular_computers/file_system/programs/airestorer.dm
+++ b/code/modules/modular_computers/file_system/programs/airestorer.dm
@@ -9,8 +9,6 @@
transfer_access = ACCESS_HEADS
available_on_ntnet = TRUE
tgui_id = "NtosAiRestorer"
- ui_x = 370
- ui_y = 400
/// Variable dictating if we are in the process of restoring the AI in the inserted intellicard
var/restoring = FALSE
@@ -74,8 +72,8 @@
restoring = FALSE
return
ai_slot.locked =TRUE
- A.adjustOxyLoss(-5, 0)
- A.adjustFireLoss(-5, 0)
+ A.adjustOxyLoss(-5, 0)//, FALSE)
+ A.adjustFireLoss(-5, 0)//, FALSE)
A.adjustToxLoss(-5, 0)
A.adjustBruteLoss(-5, 0)
A.updatehealth()
@@ -113,7 +111,7 @@
data["restoring"] = restoring
data["health"] = (AI.health + 100) / 2
data["isDead"] = AI.stat == DEAD
- data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
+ data["laws"] = AI.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE)
return data
diff --git a/code/modules/modular_computers/file_system/programs/alarm.dm b/code/modules/modular_computers/file_system/programs/alarm.dm
index 34daeff6ca..577fad83d0 100644
--- a/code/modules/modular_computers/file_system/programs/alarm.dm
+++ b/code/modules/modular_computers/file_system/programs/alarm.dm
@@ -8,9 +8,6 @@
network_destination = "alarm monitoring network"
size = 5
tgui_id = "NtosStationAlertConsole"
- ui_x = 315
- ui_y = 500
-
var/has_alert = 0
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
index cf842f086f..3accb8e02d 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
@@ -1,6 +1,6 @@
/datum/computer_file/program/contract_uplink
filename = "contractor uplink"
- filedesc = "Syndicate Contract Uplink"
+ filedesc = "Syndicate Contractor Uplink"
program_icon_state = "assign"
extended_desc = "A standard, Syndicate issued system for handling important contracts while on the field."
size = 10
@@ -9,8 +9,6 @@
unsendable = 1
undeletable = 1
tgui_id = "SyndContractor"
- ui_x = 500
- ui_y = 600
var/error = ""
var/info_screen = TRUE
var/assigned = FALSE
@@ -22,14 +20,18 @@
/datum/computer_file/program/contract_uplink/ui_act(action, params)
if(..())
return TRUE
+
var/mob/living/user = usr
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD]
+
switch(action)
if("PRG_contract-accept")
var/contract_id = text2num(params["contract_id"])
+
// Set as the active contract
hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ACTIVE
hard_drive.traitor_data.contractor_hub.current_contract = hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id]
+
program_icon_state = "single_contract"
return TRUE
if("PRG_login")
@@ -38,26 +40,30 @@
// Bake their data right into the hard drive, or we don't allow non-antags gaining access to an unused
// contract system.
// We also create their contracts at this point.
- if(traitor_data)
+ if (traitor_data)
// Only play greet sound, and handle contractor hub when assigning for the first time.
- if(!traitor_data.contractor_hub)
+ if (!traitor_data.contractor_hub)
user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, FALSE)
traitor_data.contractor_hub = new
traitor_data.contractor_hub.create_hub_items()
+
// Stops any topic exploits such as logging in multiple times on a single system.
- if(!assigned)
+ if (!assigned)
traitor_data.contractor_hub.create_contracts(traitor_data.owner)
+
hard_drive.traitor_data = traitor_data
+
program_icon_state = "contracts"
assigned = TRUE
else
error = "UNAUTHORIZED USER"
return TRUE
if("PRG_call_extraction")
- if(hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING)
- if(hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user))
+ if (hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING)
+ if (hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user))
user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, TRUE)
hard_drive.traitor_data.contractor_hub.current_contract.status = CONTRACT_STATUS_EXTRACTING
+
program_icon_state = "extracted"
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
@@ -65,15 +71,19 @@
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
error = "Already extracting... Place the target into the pod. If the pod was destroyed, this contract is no longer possible."
+
return TRUE
if("PRG_contract_abort")
var/contract_id = hard_drive.traitor_data.contractor_hub.current_contract.id
+
hard_drive.traitor_data.contractor_hub.current_contract = null
hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED
+
program_icon_state = "contracts"
+
return TRUE
if("PRG_redeem_TC")
- if(hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
+ if (hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user),
hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
if(ishuman(user))
@@ -82,13 +92,14 @@
to_chat(H, "Your payment materializes into your hands!")
else
to_chat(user, "Your payment materializes onto the floor.")
+
hard_drive.traitor_data.contractor_hub.contract_TC_payed_out += hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem
hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem = 0
return TRUE
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
return TRUE
- if("PRG_clear_error")
+ if ("PRG_clear_error")
error = ""
return TRUE
if("PRG_set_first_load_finished")
@@ -97,10 +108,11 @@
if("PRG_toggle_info")
info_screen = !info_screen
return TRUE
- if("buy_hub")
- if(hard_drive.traitor_data.owner.current == user)
+ if ("buy_hub")
+ if (hard_drive.traitor_data.owner.current == user)
var/item = params["item"]
- for(var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items)
+
+ for (var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items)
if (hub_item.name == item)
hub_item.handle_purchase(hard_drive.traitor_data.contractor_hub, user)
else
@@ -112,13 +124,15 @@
var/screen_to_be = null
data["first_load"] = first_load
- if(hard_drive && hard_drive.traitor_data != null)
+
+ if (hard_drive && hard_drive.traitor_data != null)
var/datum/antagonist/traitor/traitor_data = hard_drive.traitor_data
data += get_header_data()
- if(traitor_data.contractor_hub.current_contract)
+
+ if (traitor_data.contractor_hub.current_contract)
data["ongoing_contract"] = TRUE
screen_to_be = "single_contract"
- if(traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING)
+ if (traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING)
data["extraction_enroute"] = TRUE
screen_to_be = "extracted"
else
@@ -126,15 +140,19 @@
else
data["ongoing_contract"] = FALSE
data["extraction_enroute"] = FALSE
+
data["logged_in"] = TRUE
data["station_name"] = GLOB.station_name
data["redeemable_tc"] = traitor_data.contractor_hub.contract_TC_to_redeem
data["earned_tc"] = traitor_data.contractor_hub.contract_TC_payed_out
data["contracts_completed"] = traitor_data.contractor_hub.contracts_completed
data["contract_rep"] = traitor_data.contractor_hub.contract_rep
+
data["info_screen"] = info_screen
+
data["error"] = error
- for(var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items)
+
+ for (var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items)
data["contractor_hub_items"] += list(list(
"name" = hub_item.name,
"desc" = hub_item.desc,
@@ -142,7 +160,8 @@
"limited" = hub_item.limited,
"item_icon" = hub_item.item_icon
))
- for(var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts)
+
+ for (var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts)
data["contracts"] += list(list(
"target" = contract.contract.target,
"target_rank" = contract.target_rank,
@@ -155,23 +174,28 @@
))
var/direction
- if(traitor_data.contractor_hub.current_contract)
+ if (traitor_data.contractor_hub.current_contract)
var/turf/curr = get_turf(user)
var/turf/dropoff_turf
data["current_location"] = "[get_area_name(curr, TRUE)]"
- for(var/turf/content in traitor_data.contractor_hub.current_contract.contract.dropoff.contents)
- if(isturf(content))
+
+ for (var/turf/content in traitor_data.contractor_hub.current_contract.contract.dropoff.contents)
+ if (isturf(content))
dropoff_turf = content
break
+
if(curr.z == dropoff_turf.z) //Direction calculations for same z-level only
direction = uppertext(dir2text(get_dir(curr, dropoff_turf))) //Direction text (East, etc). Not as precise, but still helpful.
if(get_area(user) == traitor_data.contractor_hub.current_contract.contract.dropoff)
direction = "LOCATION CONFIRMED"
else
direction = "???"
+
data["dropoff_direction"] = direction
+
else
data["logged_in"] = FALSE
+
program_icon_state = screen_to_be
update_computer_icon()
return data
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
index 9dedc3810f..803dadc0a0 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -8,8 +8,6 @@
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosNetDos"
- ui_x = 400
- ui_y = 250
var/obj/machinery/ntnet_relay/target = null
var/dos_speed = 0
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
index a312815008..2ba3d69fe6 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
@@ -8,9 +8,6 @@
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosRevelation"
- ui_x = 400
- ui_y = 250
-
var/armed = 0
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm
index 87debafd6b..2503073f9a 100644
--- a/code/modules/modular_computers/file_system/programs/arcade.dm
+++ b/code/modules/modular_computers/file_system/programs/arcade.dm
@@ -7,8 +7,6 @@
network_destination = "arcade network"
size = 6
tgui_id = "NtosArcade"
- ui_x = 450
- ui_y = 350
///Returns TRUE if the game is being played.
var/game_active = TRUE
@@ -27,6 +25,7 @@
/datum/computer_file/program/arcade/proc/game_check(mob/user)
sleep(5)
+ //user?.mind?.adjust_experience(/datum/skill/gaming, 1) No gaming(TM) Yet
if(boss_hp <= 0)
heads_up = "You have crushed [boss_name]! Rejoice!"
playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10)
@@ -35,6 +34,7 @@
if(istype(computer))
computer.update_icon()
ticket_count += 1
+ //user?.mind?.adjust_experience(/datum/skill/gaming, 50)
sleep(10)
else if(player_hp <= 0 || player_mp <= 0)
heads_up = "You have been defeated... how will the station survive?"
@@ -43,6 +43,7 @@
program_icon_state = "arcade_off"
if(istype(computer))
computer.update_icon()
+ //user?.mind?.adjust_experience(/datum/skill/gaming, 10)
sleep(10)
/datum/computer_file/program/arcade/proc/enemy_check(mob/user)
@@ -73,14 +74,13 @@
pause_state = FALSE
game_check()
-/datum/computer_file/program/arcade/ui_interact(mob/user, ui_key, datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state)
- . = ..()
- var/datum/asset/assets = get_asset_datum(/datum/asset/simple/arcade)
- assets.send(user)
+/datum/computer_file/program/arcade/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/arcade),
+ )
/datum/computer_file/program/arcade/ui_data(mob/user)
var/list/data = get_header_data()
-
data["Hitpoints"] = boss_hp
data["PlayerHitpoints"] = player_hp
data["PlayerMP"] = player_mp
@@ -98,11 +98,13 @@
if(computer)
printer = computer.all_components[MC_PRINT]
+ //var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming)
+ //var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
switch(action)
if("Attack")
var/attackamt = 0 //Spam prevention.
if(pause_state == FALSE)
- attackamt = rand(2,6)
+ attackamt = rand(2,6)// + rand(0, gamerSkill)
pause_state = TRUE
heads_up = "You attack for [attackamt] damage."
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10)
@@ -115,8 +117,10 @@
var/healamt = 0 //More Spam Prevention.
var/healcost = 0
if(pause_state == FALSE)
- healamt = rand(6,8)
+ healamt = rand(6,8)// + rand(0, gamerSkill)
var/maxPointCost = 3
+ //if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN)
+ // maxPointCost = 2
healcost = rand(1, maxPointCost)
pause_state = TRUE
heads_up = "You heal for [healamt] damage."
@@ -130,7 +134,7 @@
if("Recharge_Power")
var/rechargeamt = 0 //As above.
if(pause_state == FALSE)
- rechargeamt = rand(4, 7)
+ rechargeamt = rand(4,7)// + rand(0, gamerSkill)
pause_state = TRUE
heads_up = "You regain [rechargeamt] magic power."
playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10)
diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm
index fe3833facd..2df751bebd 100644
--- a/code/modules/modular_computers/file_system/programs/atmosscan.dm
+++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm
@@ -6,8 +6,6 @@
network_destination = "atmos scan"
size = 4
tgui_id = "NtosAtmos"
- ui_x = 300
- ui_y = 350
/datum/computer_file/program/atmosscan/ui_data(mob/user)
var/list/data = get_header_data()
@@ -15,16 +13,16 @@
var/turf/T = get_turf(ui_host())
if(T)
var/datum/gas_mixture/environment = T.return_air()
- var/list/env_gases = environment.gases
+ var/list/env_gases = environment.get_gases()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
data["AirPressure"] = round(pressure,0.1)
- data["AirTemp"] = round(environment.temperature-T0C)
+ data["AirTemp"] = round(environment.return_temperature()-T0C)
if (total_moles)
for(var/id in env_gases)
- var/gas_level = env_gases[id][MOLES]/total_moles
+ var/gas_level = environment.get_moles(id)/total_moles
if(gas_level > 0)
- airlist += list(list("name" = "[env_gases[id][GAS_META][META_GAS_NAME]]", "percentage" = round(gas_level*100, 0.01)))
+ airlist += list(list("name" = "[GLOB.meta_gas_names[id]]", "percentage" = round(gas_level*100, 0.01)))
data["AirData"] = airlist
return data
diff --git a/code/modules/modular_computers/file_system/programs/borg_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_monitor.dm
index c493926c65..c2160a0e92 100644
--- a/code/modules/modular_computers/file_system/programs/borg_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/borg_monitor.dm
@@ -9,21 +9,17 @@
network_destination = "cyborg remote monitoring"
size = 5
tgui_id = "NtosCyborgRemoteMonitor"
- ui_x = 600
- ui_y = 800
/datum/computer_file/program/borg_monitor/ui_data(mob/user)
var/list/data = get_header_data()
data["card"] = FALSE
- if(computer.GetID())
+ if(checkID())
data["card"] = TRUE
data["cyborgs"] = list()
for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs)
- if((get_turf(computer)).z != (get_turf(R)).z)
- continue
- if(R.scrambledcodes)
+ if(!evaluate_borg(R))
continue
var/list/upgrade
@@ -36,7 +32,7 @@
var/list/cyborg_data = list(
name = R.name,
- locked_down = R.locked_down,
+ locked_down = R.lockcharge,
status = R.stat,
shell_discon = shell,
charge = R.cell ? round(R.cell.percent()) : null,
@@ -56,14 +52,53 @@
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
if(!istype(R))
return
- var/obj/item/card/id/ID = computer.GetID()
+ var/ID = checkID()
if(!ID)
return
var/message = stripped_input(usr, message = "Enter message to be sent to remote cyborg.", title = "Send Message")
if(!message)
return
- to_chat(R, "
Message from [ID.registered_name] -- \"[message]\" ")
+ to_chat(R, "
Message from [ID.registered_name] to [R] -- \"[message]\" ")
+ to_chat(R.connected_ai, "
Message from [ID] to [R] -- \"[message]\" ")
SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg')
+ usr.log_talk(message, LOG_PDA, tag="Cyborg Monitor Program: ID name \"[ID]\" to [R]")
+
+///This proc is used to determin if a borg should be shown in the list (based on the borg's scrambledcodes var). Syndicate version overrides this to show only syndicate borgs.
+/datum/computer_file/program/borg_monitor/proc/evaluate_borg(mob/living/silicon/robot/R)
+ if((get_turf(computer)).z != (get_turf(R)).z)
+ return FALSE
+ if(R.scrambledcodes)
+ return FALSE
+ return TRUE
+
+///Gets the ID's name, if one is inserted into the device. This is a seperate proc solely to be overridden by the syndicate version of the app.
+/datum/computer_file/program/borg_monitor/proc/checkID()
+ var/obj/item/card/id/ID = computer.GetID()
+ if(!ID)
+ return FALSE
+ return ID.registered_name
+
+/datum/computer_file/program/borg_monitor/syndicate
+ filename = "scyborgmonitor"
+ filedesc = "Mission-Specific Cyborg Remote Monitoring"
+ ui_header = "borg_mon.gif"
+ program_icon_state = "generic"
+ extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs."
+ requires_ntnet = FALSE
+ available_on_ntnet = FALSE
+ available_on_syndinet = TRUE
+ transfer_access = null
+ network_destination = "cyborg remote monitoring"
+ tgui_id = "NtosCyborgRemoteMonitorSyndicate"
+
+/datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R)
+ if((get_turf(computer)).z != (get_turf(R)).z)
+ return FALSE
+ if(!R.scrambledcodes)
+ return FALSE
+ return TRUE
+
+/datum/computer_file/program/borg_monitor/syndicate/checkID()
+ return "\[CLASSIFIED\]" //no ID is needed for the syndicate version's message function, and the borg will see "[CLASSIFIED]" as the message sender.
diff --git a/code/modules/modular_computers/file_system/programs/bounty_board.dm b/code/modules/modular_computers/file_system/programs/bounty_board.dm
new file mode 100644
index 0000000000..46fde84f65
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/bounty_board.dm
@@ -0,0 +1,120 @@
+/datum/computer_file/program/bounty_board
+ filename = "bountyboard"
+ filedesc = "Bounty Board Request Network"
+ program_icon_state = "bountyboard"
+ extended_desc = "A multi-platform network for placing requests across the station, with payment across the network being possible.."
+ requires_ntnet = TRUE
+ network_destination = "bounty board interface"
+ size = 10
+ tgui_id = "NtosRequestKiosk"
+ ///Reference to the currently logged in user.
+ var/datum/bank_account/current_user
+ ///The station request datum being affected by UI actions.
+ var/datum/station_request/active_request
+ ///Value of the currently bounty input
+ var/bounty_value = 1
+ ///Text of the currently written bounty
+ var/bounty_text = ""
+ ///Has the app been added to the network yet?
+ var/networked = FALSE
+
+/datum/computer_file/program/bounty_board/ui_data(mob/user)
+ var/list/data = get_header_data()
+ var/list/formatted_requests = list()
+ var/list/formatted_applicants = list()
+ var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
+ if(!networked)
+ GLOB.allbountyboards += computer
+ networked = TRUE
+ if(card_slot && card_slot.stored_card && card_slot.stored_card.registered_account)
+ current_user = card_slot.stored_card.registered_account
+ for(var/i in GLOB.request_list)
+ if(!i)
+ continue
+ var/datum/station_request/request = i
+ formatted_requests += list(list("owner" = request.owner, "value" = request.value, "description" = request.description, "acc_number" = request.req_number))
+ if(request.applicants)
+ for(var/datum/bank_account/j in request.applicants)
+ formatted_applicants += list(list("name" = j.account_holder, "request_id" = request.owner_account.account_id, "requestee_id" = j.account_id))
+ if(current_user)
+ data["accountName"] = current_user.account_holder
+ data["requests"] = formatted_requests
+ data["applicants"] = formatted_applicants
+ data["bountyValue"] = bounty_value
+ data["bountyText"] = bounty_text
+ return data
+
+/datum/computer_file/program/bounty_board/ui_act(action, list/params)
+ if(..())
+ return
+ var/current_ref_num = params["request"]
+ var/current_app_num = params["applicant"]
+ var/datum/bank_account/request_target
+ if(current_ref_num)
+ for(var/datum/station_request/i in GLOB.request_list)
+ if("[i.req_number]" == "[current_ref_num]")
+ active_request = i
+ break
+ if(active_request)
+ for(var/datum/bank_account/j in active_request.applicants)
+ if("[j.account_id]" == "[current_app_num]")
+ request_target = j
+ break
+ switch(action)
+ if("createBounty")
+ if(!current_user || !bounty_text)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 20, TRUE)
+ return TRUE
+ for(var/datum/station_request/i in GLOB.request_list)
+ if("[i.req_number]" == "[current_user.account_id]")
+ computer.say("Account already has active bounty.")
+ return
+ var/datum/station_request/curr_request = new /datum/station_request(current_user.account_holder, bounty_value,bounty_text,current_user.account_id, current_user)
+ GLOB.request_list += list(curr_request)
+ for(var/obj/i in GLOB.allbountyboards)
+ i.say("New bounty has been added!")
+ playsound(i.loc, 'sound/effects/cashregister.ogg', 30, TRUE)
+ return TRUE
+ if("apply")
+ if(!current_user)
+ computer.say("Please swipe a valid ID first.")
+ return TRUE
+ if(current_user.account_holder == active_request.owner)
+ playsound(computer, 'sound/machines/buzz-sigh.ogg', 20, TRUE)
+ return TRUE
+ active_request.applicants += list(current_user)
+ if("payApplicant")
+ if(!current_user)
+ return
+ if(!current_user.has_money(active_request.value) || (current_user.account_holder != active_request.owner))
+ playsound(computer, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
+ return
+ request_target.transfer_money(current_user, active_request.value)
+ computer.say("Paid out [active_request.value] credits.")
+ return TRUE
+ if("clear")
+ if(current_user)
+ current_user = null
+ computer.say("Account Reset.")
+ return TRUE
+ if("deleteRequest")
+ if(!current_user)
+ playsound(computer, 'sound/machines/buzz-sigh.ogg', 20, TRUE)
+ return TRUE
+ if(active_request.owner != current_user.account_holder)
+ playsound(computer, 'sound/machines/buzz-sigh.ogg', 20, TRUE)
+ return TRUE
+ computer.say("Deleted current request.")
+ GLOB.request_list.Remove(active_request)
+ return TRUE
+ if("bountyVal")
+ bounty_value = text2num(params["bountyval"])
+ if(!bounty_value)
+ bounty_value = 1
+ if("bountyText")
+ bounty_text = (params["bountytext"])
+ . = TRUE
+
+/datum/computer_file/program/bounty_board/Destroy()
+ GLOB.allbountyboards -= computer
+ . = ..()
diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm
index 07d39438d8..842d6e2588 100644
--- a/code/modules/modular_computers/file_system/programs/card.dm
+++ b/code/modules/modular_computers/file_system/programs/card.dm
@@ -15,8 +15,6 @@
requires_ntnet = 0
size = 8
tgui_id = "NtosCard"
- ui_x = 450
- ui_y = 520
var/is_centcom = FALSE
var/minor = FALSE
@@ -275,7 +273,7 @@
departments = list("CentCom" = get_all_centcom_jobs())
else if(isnull(departments))
departments = list(
- CARDCON_DEPARTMENT_COMMAND = list("Captain"),
+ CARDCON_DEPARTMENT_COMMAND = list("Captain"),//lol
CARDCON_DEPARTMENT_ENGINEERING = GLOB.engineering_positions,
CARDCON_DEPARTMENT_MEDICAL = GLOB.medical_positions,
CARDCON_DEPARTMENT_SCIENCE = GLOB.science_positions,
diff --git a/code/modules/modular_computers/file_system/programs/cargobounty.dm b/code/modules/modular_computers/file_system/programs/cargobounty.dm
new file mode 100644
index 0000000000..d9bc65c98d
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/cargobounty.dm
@@ -0,0 +1,48 @@
+/datum/computer_file/program/bounty
+ filename = "bounty"
+ filedesc = "Nanotrasen Bounty Hunter"
+ program_icon_state = "bounty"
+ extended_desc = "A basic interface for supply personnel to check and claim bounties."
+ requires_ntnet = TRUE
+ transfer_access = ACCESS_CARGO
+ network_destination = "cargo claims interface"
+ size = 10
+ tgui_id = "NtosBountyConsole"
+ ///cooldown var for printing paper sheets.
+ var/printer_ready = 0
+ ///The cargo account for grabbing the cargo account's credits.
+ var/static/datum/bank_account/cargocash
+
+/datum/computer_file/program/bounty/proc/print_paper()
+ new /obj/item/paper/bounty_printout(get_turf(computer))
+
+/datum/computer_file/program/bounty/ui_interact(mob/user, datum/tgui/ui)
+ if(!GLOB.bounties_list.len)
+ setup_bounties()
+ printer_ready = world.time + PRINTER_TIMEOUT
+ cargocash = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ . = ..()
+
+/datum/computer_file/program/bounty/ui_data(mob/user)
+ var/list/data = get_header_data()
+ var/list/bountyinfo = list()
+ for(var/datum/bounty/B in GLOB.bounties_list)
+ bountyinfo += list(list("name" = B.name, "description" = B.description, "reward_string" = B.reward_string(), "completion_string" = B.completion_string() , "claimed" = B.claimed, "can_claim" = B.can_claim(), "priority" = B.high_priority, "bounty_ref" = REF(B)))
+ data["stored_cash"] = cargocash.account_balance
+ data["bountydata"] = bountyinfo
+ return data
+
+/datum/computer_file/program/bounty/ui_act(action,params)
+ if(..())
+ return
+ switch(action)
+ if("ClaimBounty")
+ var/datum/bounty/cashmoney = locate(params["bounty"]) in GLOB.bounties_list
+ if(cashmoney)
+ cashmoney.claim()
+ return TRUE
+ if("Print")
+ if(printer_ready < world.time)
+ printer_ready = world.time + PRINTER_TIMEOUT
+ print_paper()
+ return
diff --git a/code/modules/modular_computers/file_system/programs/cargoship.dm b/code/modules/modular_computers/file_system/programs/cargoship.dm
index 39543adfa5..3ba08a3719 100644
--- a/code/modules/modular_computers/file_system/programs/cargoship.dm
+++ b/code/modules/modular_computers/file_system/programs/cargoship.dm
@@ -6,11 +6,9 @@
network_destination = "ship scanner"
size = 6
tgui_id = "NtosShipping"
- ui_x = 450
- ui_y = 350
///Account used for creating barcodes.
var/datum/bank_account/payments_acc
- ///The amount which the tagger will recieve for the sale.
+ ///The amount which the tagger will receive for the sale.
var/percent_cut = 20
/datum/computer_file/program/shipping/ui_data(mob/user)
diff --git a/code/modules/modular_computers/file_system/programs/configurator.dm b/code/modules/modular_computers/file_system/programs/configurator.dm
index 76da58ea11..fae06544d5 100644
--- a/code/modules/modular_computers/file_system/programs/configurator.dm
+++ b/code/modules/modular_computers/file_system/programs/configurator.dm
@@ -10,8 +10,6 @@
unsendable = 1
undeletable = 1
size = 4
- ui_x = 420
- ui_y = 630
available_on_ntnet = 0
requires_ntnet = 0
tgui_id = "NtosConfiguration"
diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm
index 662c867a39..a1503ce3a8 100644
--- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm
+++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm
@@ -7,12 +7,10 @@
requires_ntnet = FALSE
size = 4
tgui_id = "NtosCrewManifest"
- ui_x = 400
- ui_y = 480
/datum/computer_file/program/crew_manifest/ui_static_data(mob/user)
var/list/data = list()
- data["manifest"] = GLOB.data_core.get_manifest()
+ data["manifest"] = GLOB.data_core.get_manifest_tg()
return data
/datum/computer_file/program/crew_manifest/ui_data(mob/user)
@@ -41,9 +39,9 @@
if(computer && printer) //This option should never be called if there is no printer
var/contents = {"
Crew Manifest
- [GLOB.data_core ? GLOB.data_core.get_manifest_html(0) : ""]
+ [GLOB.data_core ? GLOB.data_core.get_manifest() : ""]
"}
- if(!printer.print_text(contents,text("crew manifest ([])", station_time_timestamp())))
+ if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss", world.time))))
to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.")
return
else
diff --git a/code/modules/modular_computers/file_system/programs/jobmanagement.dm b/code/modules/modular_computers/file_system/programs/jobmanagement.dm
index 7b847c123e..bccc6e4dbe 100644
--- a/code/modules/modular_computers/file_system/programs/jobmanagement.dm
+++ b/code/modules/modular_computers/file_system/programs/jobmanagement.dm
@@ -7,8 +7,6 @@
requires_ntnet = 0
size = 4
tgui_id = "NtosJobManager"
- ui_x = 400
- ui_y = 620
var/change_position_cooldown = 30
//Jobs you cannot open new positions for
diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
index 352f13f305..6401d6207f 100644
--- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm
+++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
@@ -11,8 +11,6 @@
available_on_ntnet = 0
ui_header = "downloader_finished.gif"
tgui_id = "NtosNetDownloader"
- ui_x = 480
- ui_y = 735
var/datum/computer_file/program/downloaded_file = null
var/hacked_download = 0
@@ -20,6 +18,21 @@
var/download_netspeed = 0
var/downloaderror = ""
var/obj/item/modular_computer/my_computer = null
+ var/emagged = FALSE
+ var/list/main_repo
+ var/list/antag_repo
+
+/datum/computer_file/program/ntnetdownload/run_program()
+ . = ..()
+ main_repo = SSnetworks.station_network.available_station_software
+ antag_repo = SSnetworks.station_network.available_antag_software
+
+/datum/computer_file/program/ntnetdownload/run_emag()
+ if(emagged)
+ return FALSE
+ emagged = TRUE
+ return TRUE
+
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
if(downloaded_file)
@@ -30,8 +43,8 @@
if(!PRG || !istype(PRG))
return 0
- // Attempting to download antag only program, but without having emagged computer. No.
- if(PRG.available_on_syndinet && !(computer.obj_flags & EMAGGED))
+ // Attempting to download antag only program, but without having emagged/syndicate computer. No.
+ if(PRG.available_on_syndinet && !emagged)
return 0
var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
@@ -41,10 +54,10 @@
ui_header = "downloader_running.gif"
- if(PRG in SSnetworks.station_network.available_station_software)
+ if(PRG in main_repo)
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
hacked_download = 0
- else if(PRG in SSnetworks.station_network.available_antag_software)
+ else if(PRG in antag_repo)
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
hacked_download = 1
else
@@ -130,7 +143,7 @@
data["disk_size"] = hard_drive.max_capacity
data["disk_used"] = hard_drive.used_capacity
var/list/all_entries[0]
- for(var/A in SSnetworks.station_network.available_station_software)
+ for(var/A in main_repo)
var/datum/computer_file/program/P = A
// Only those programs our user can run will show in the list
if(!P.can_run(user,transfer = 1) || hard_drive.find_file_by_name(P.filename))
@@ -143,9 +156,9 @@
"size" = P.size,
)))
data["hackedavailable"] = FALSE
- if(computer.obj_flags & EMAGGED) // If we are running on emagged computer we have access to some "bonus" software
+ if(emagged) // If we are running on emagged computer we have access to some "bonus" software
var/list/hacked_programs[0]
- for(var/S in SSnetworks.station_network.available_antag_software)
+ for(var/S in antag_repo)
var/datum/computer_file/program/P = S
if(hard_drive.find_file_by_name(P.filename))
continue
@@ -172,3 +185,24 @@
/datum/computer_file/program/ntnetdownload/kill_program(forced)
abort_file_download()
return ..(forced)
+
+////////////////////////
+//Syndicate Downloader//
+////////////////////////
+
+/// This app only lists programs normally found in the emagged section of the normal downloader app
+
+/datum/computer_file/program/ntnetdownload/syndicate
+ filename = "syndownloader"
+ filedesc = "Software Download Tool"
+ program_icon_state = "generic"
+ extended_desc = "This program allows downloads of software from shared Syndicate repositories"
+ requires_ntnet = 0
+ ui_header = "downloader_finished.gif"
+ tgui_id = "NtosNetDownloader"
+ emagged = TRUE
+
+/datum/computer_file/program/ntnetdownload/syndicate/run_program()
+ . = ..()
+ main_repo = SSnetworks.station_network.available_antag_software
+ antag_repo = null
diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
index 4ae5bd326b..df9b02d8ec 100644
--- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
@@ -10,9 +10,6 @@
ui_header = "ntnrc_idle.gif"
available_on_ntnet = 1
tgui_id = "NtosNetChat"
- ui_x = 900
- ui_y = 675
-
var/last_message // Used to generate the toolbar icon
var/username
var/active_channel
diff --git a/code/modules/modular_computers/file_system/programs/nttransfer.dm b/code/modules/modular_computers/file_system/programs/nttransfer.dm
deleted file mode 100644
index 698e557941..0000000000
--- a/code/modules/modular_computers/file_system/programs/nttransfer.dm
+++ /dev/null
@@ -1,183 +0,0 @@
-/datum/computer_file/program/nttransfer
- filename = "nttransfer"
- filedesc = "P2P Transfer Client"
- extended_desc = "This program allows for simple file transfer via direct peer to peer connection."
- program_icon_state = "comm_logs"
- size = 7
- requires_ntnet = 1
- requires_ntnet_feature = NTNET_PEERTOPEER
- network_destination = "other device via P2P tunnel"
- available_on_ntnet = 1
- tgui_id = "ntos_net_transfer"
-
- var/error = "" // Error screen
- var/server_password = "" // Optional password to download the file.
- var/datum/computer_file/provided_file = null // File which is provided to clients.
- var/datum/computer_file/downloaded_file = null // File which is being downloaded
- var/list/connected_clients = list() // List of connected clients.
- var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from.
- var/download_completion = 0 // Download progress in GQ
- var/download_netspeed = 0 // Our connectivity speed in GQ/s
- var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed.
- var/unique_token // UID of this program
- var/upload_menu = 0 // Whether we show the program list and upload menu
- var/static/nttransfer_uid = 0
-
-/datum/computer_file/program/nttransfer/New()
- unique_token = nttransfer_uid++
- ..()
-
-/datum/computer_file/program/nttransfer/process_tick()
- // Server mode
- update_netspeed()
- if(provided_file)
- for(var/datum/computer_file/program/nttransfer/C in connected_clients)
- // Transfer speed is limited by device which uses slower connectivity.
- // We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer
- // so they can all run on same speed.
- C.actual_netspeed = min(C.download_netspeed, download_netspeed)
- C.download_completion += C.actual_netspeed
- if(C.download_completion >= provided_file.size)
- C.finish_download()
- else if(downloaded_file) // Client mode
- if(!remote)
- crash_download("Connection to remote server lost")
-
-/datum/computer_file/program/nttransfer/kill_program(forced = FALSE)
- if(downloaded_file) // Client mode, clean up variables for next use
- finalize_download()
-
- if(provided_file) // Server mode, disconnect all clients
- for(var/datum/computer_file/program/nttransfer/P in connected_clients)
- P.crash_download("Connection terminated by remote server")
- downloaded_file = null
- ..(forced)
-
-/datum/computer_file/program/nttransfer/proc/update_netspeed()
- download_netspeed = 0
- switch(ntnet_status)
- if(1)
- download_netspeed = NTNETSPEED_LOWSIGNAL
- if(2)
- download_netspeed = NTNETSPEED_HIGHSIGNAL
- if(3)
- download_netspeed = NTNETSPEED_ETHERNET
-
-// Finishes download and attempts to store the file on HDD
-/datum/computer_file/program/nttransfer/proc/finish_download()
- var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
- if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file))
- error = "I/O Error: Unable to save file. Check your hard drive and try again."
- finalize_download()
-
-// Crashes the download and displays specific error message
-/datum/computer_file/program/nttransfer/proc/crash_download(var/message)
- error = message ? message : "An unknown error has occurred during download"
- finalize_download()
-
-// Cleans up variables for next use
-/datum/computer_file/program/nttransfer/proc/finalize_download()
- if(remote)
- remote.connected_clients.Remove(src)
- downloaded_file = null
- remote = null
- download_completion = 0
-
-/datum/computer_file/program/nttransfer/ui_act(action, params)
- if(..())
- return 1
- switch(action)
- if("PRG_downloadfile")
- for(var/datum/computer_file/program/nttransfer/P in SSnetworks.station_network.fileservers)
- if("[P.unique_token]" == params["id"])
- remote = P
- break
- if(!remote || !remote.provided_file)
- return
- if(remote.server_password)
- var/pass = reject_bad_text(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
- if(pass != remote.server_password)
- error = "Incorrect Password"
- return
- downloaded_file = remote.provided_file.clone()
- remote.connected_clients.Add(src)
- return 1
- if("PRG_reset")
- error = ""
- upload_menu = 0
- finalize_download()
- if(src in SSnetworks.station_network.fileservers)
- SSnetworks.station_network.fileservers.Remove(src)
- for(var/datum/computer_file/program/nttransfer/T in connected_clients)
- T.crash_download("Remote server has forcibly closed the connection")
- provided_file = null
- return 1
- if("PRG_setpassword")
- var/pass = reject_bad_text(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
- if(!pass)
- return
- if(pass == "none")
- server_password = ""
- return
- server_password = pass
- return 1
- if("PRG_uploadfile")
- var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
- for(var/datum/computer_file/F in hard_drive.stored_files)
- if("[F.uid]" == params["id"])
- if(F.unsendable)
- error = "I/O Error: File locked."
- return
- if(istype(F, /datum/computer_file/program))
- var/datum/computer_file/program/P = F
- if(!P.can_run(usr,transfer = 1))
- error = "Access Error: Insufficient rights to upload file."
- provided_file = F
- SSnetworks.station_network.fileservers.Add(src)
- return
- error = "I/O Error: Unable to locate file on hard drive."
- return 1
- if("PRG_uploadmenu")
- upload_menu = 1
-
-
-/datum/computer_file/program/nttransfer/ui_data(mob/user)
-
- var/list/data = get_header_data()
-
- if(error)
- data["error"] = error
- else if(downloaded_file)
- data["downloading"] = 1
- data["download_size"] = downloaded_file.size
- data["download_progress"] = download_completion
- data["download_netspeed"] = actual_netspeed
- data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]"
- else if (provided_file)
- data["uploading"] = 1
- data["upload_uid"] = unique_token
- data["upload_clients"] = connected_clients.len
- data["upload_haspassword"] = server_password ? 1 : 0
- data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]"
- else if (upload_menu)
- var/list/all_files[0]
- var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
- for(var/datum/computer_file/F in hard_drive.stored_files)
- all_files.Add(list(list(
- "uid" = F.uid,
- "filename" = "[F.filename].[F.filetype]",
- "size" = F.size
- )))
- data["upload_filelist"] = all_files
- else
- var/list/all_servers[0]
- for(var/datum/computer_file/program/nttransfer/P in SSnetworks.station_network.fileservers)
- all_servers.Add(list(list(
- "uid" = P.unique_token,
- "filename" = "[P.provided_file.filename].[P.provided_file.filetype]",
- "size" = P.provided_file.size,
- "haspassword" = P.server_password ? 1 : 0
- )))
- data["servers"] = all_servers
-
- return data
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/powermonitor.dm b/code/modules/modular_computers/file_system/programs/powermonitor.dm
index d2d57b1447..bd11474858 100644
--- a/code/modules/modular_computers/file_system/programs/powermonitor.dm
+++ b/code/modules/modular_computers/file_system/programs/powermonitor.dm
@@ -12,8 +12,6 @@
network_destination = "power monitoring system"
size = 9
tgui_id = "NtosPowerMonitor"
- ui_x = 550
- ui_y = 700
var/has_alert = 0
var/obj/structure/cable/attached_wire
diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm
index 7a6e80267c..9b0e09ef99 100644
--- a/code/modules/modular_computers/file_system/programs/radar.dm
+++ b/code/modules/modular_computers/file_system/programs/radar.dm
@@ -2,31 +2,49 @@
filename = "genericfinder"
filedesc = "debug_finder"
ui_header = "borg_mon.gif" //DEBUG -- new icon before PR
- program_icon_state = "generic"
- extended_desc = "generic"
+ program_icon_state = "radarntos"
requires_ntnet = TRUE
transfer_access = null
available_on_ntnet = FALSE
+ usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET
network_destination = "tracking program"
size = 5
tgui_id = "NtosRadar"
- ui_x = 800
- ui_y = 600
- special_assets = list(
- /datum/asset/simple/radar_assets,
- )
///List of trackable entities. Updated by the scan() proc.
var/list/objects
///Ref of the last trackable object selected by the user in the tgui window. Updated in the ui_act() proc.
var/atom/selected
///Used to store when the next scan is available. Updated by the scan() proc.
var/next_scan = 0
+ ///Used to keep track of the last value program_icon_state was set to, to prevent constant unnecessary update_icon() calls
+ var/last_icon_state = ""
+ ///Used by the tgui interface, themed NT or Syndicate.
+ var/arrowstyle = "ntosradarpointer.png"
+ ///Used by the tgui interface, themed for NT or Syndicate colors.
+ var/pointercolor = "green"
+
+/datum/computer_file/program/radar/run_program(mob/living/user)
+ . = ..()
+ if(.)
+ START_PROCESSING(SSfastprocess, src)
+ return
+ return FALSE
/datum/computer_file/program/radar/kill_program(forced = FALSE)
objects = list()
selected = null
+ STOP_PROCESSING(SSfastprocess, src)
return ..()
+/datum/computer_file/program/radar/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/datum/computer_file/program/radar/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/radar_assets),
+ )
+
/datum/computer_file/program/radar/ui_data(mob/user)
var/list/data = get_header_data()
data["selected"] = selected
@@ -65,7 +83,37 @@
*
*/
/datum/computer_file/program/radar/proc/track()
- return
+ var/atom/movable/signal = find_atom()
+ if(!trackable(signal))
+ return
+
+ var/turf/here_turf = (get_turf(computer))
+ var/turf/target_turf = (get_turf(signal))
+ var/userot = FALSE
+ var/rot = 0
+ var/pointer="crosshairs"
+ var/locx = (target_turf.x - here_turf.x) + 24
+ var/locy = (here_turf.y - target_turf.y) + 24
+
+ if(get_dist_euclidian(here_turf, target_turf) > 24)
+ userot = TRUE
+ rot = round(Get_Angle(here_turf, target_turf))
+ else
+ if(target_turf.z > here_turf.z)
+ pointer="caret-up"
+ else if(target_turf.z < here_turf.z)
+ pointer="caret-down"
+
+ var/list/trackinfo = list(
+ "locx" = locx,
+ "locy" = locy,
+ "userot" = userot,
+ "rot" = rot,
+ "arrowstyle" = arrowstyle,
+ "color" = pointercolor,
+ "pointer" = pointer,
+ )
+ return trackinfo
/**
*
@@ -77,10 +125,12 @@
**arg1 is the atom being evaluated.
*/
/datum/computer_file/program/radar/proc/trackable(atom/movable/signal)
- if(!signal)
+ if(!signal || !computer)
return FALSE
var/turf/here = get_turf(computer)
var/turf/there = get_turf(signal)
+ if(!here || !there)
+ return FALSE //I was still getting a runtime even after the above check while scanning, so fuck it
return (there.z == here.z) || (is_station_level(here.z) && is_station_level(there.z))
/**
@@ -98,6 +148,59 @@
/datum/computer_file/program/radar/proc/scan()
return
+/**
+ *
+ *Finds the atom in the appropriate list that the `selected` var indicates
+ *
+ *The `selected` var holds a REF, which is a string. A mob REF may be
+ *something like "mob_209". In order to find the actual atom, we need
+ *to search the appropriate list for the REF string. This is dependant
+ *on the program (Lifeline uses GLOB.human_list, while Fission360 uses
+ *GLOB.poi_list), but the result will be the same; evaluate the string and
+ *return an atom reference.
+*/
+/datum/computer_file/program/radar/proc/find_atom()
+ return
+
+//We use SSfastprocess for the program icon state because it runs faster than process_tick() does.
+/datum/computer_file/program/radar/process()
+ if(computer.active_program != src)
+ STOP_PROCESSING(SSfastprocess, src) //We're not the active program, it's time to stop.
+ return
+ if(!selected)
+ return
+
+ var/atom/movable/signal = find_atom()
+ if(!trackable(signal))
+ program_icon_state = "[initial(program_icon_state)]lost"
+ if(last_icon_state != program_icon_state)
+ computer.update_icon()
+ last_icon_state = program_icon_state
+ return
+
+ var/here_turf = get_turf(computer)
+ var/target_turf = get_turf(signal)
+ var/trackdistance = get_dist_euclidian(here_turf, target_turf)
+ switch(trackdistance)
+ if(0)
+ program_icon_state = "[initial(program_icon_state)]direct"
+ if(1 to 12)
+ program_icon_state = "[initial(program_icon_state)]close"
+ if(13 to 24)
+ program_icon_state = "[initial(program_icon_state)]medium"
+ if(25 to INFINITY)
+ program_icon_state = "[initial(program_icon_state)]far"
+
+ if(last_icon_state != program_icon_state)
+ computer.update_icon()
+ last_icon_state = program_icon_state
+ computer.setDir(get_dir(here_turf, target_turf))
+
+//We can use process_tick to restart fast processing, since the computer will be running this constantly either way.
+/datum/computer_file/program/radar/process_tick()
+ if(computer.active_program == src)
+ START_PROCESSING(SSfastprocess, src)
+
///////////////////
//Suit Sensor App//
///////////////////
@@ -106,44 +209,13 @@
/datum/computer_file/program/radar/lifeline
filename = "Lifeline"
filedesc = "Lifeline"
- program_icon_state = "generic"
extended_desc = "This program allows for tracking of crew members via their suit sensors."
requires_ntnet = TRUE
transfer_access = ACCESS_MEDICAL
available_on_ntnet = TRUE
-/datum/computer_file/program/radar/lifeline/track()
- var/mob/living/carbon/human/humanoid = locate(selected) in GLOB.human_list
- if(!istype(humanoid) || !trackable(humanoid))
- return
-
- var/turf/here_turf = (get_turf(computer))
- var/turf/target_turf = (get_turf(humanoid))
- var/userot = FALSE
- var/rot = 0
- var/pointer="crosshairs"
- var/locx = (target_turf.x - here_turf.x)
- var/locy = (here_turf.y - target_turf.y)
- if(get_dist_euclidian(here_turf, target_turf) > 24) //If they're too far away, we need the angle for the arrow along the edge of the radar display
- userot = TRUE
- rot = round(Get_Angle(here_turf, target_turf))
- else
- locx = locx + 24
- locy = locy + 24
- if(target_turf.z > here_turf.z)
- pointer="caret-up"
- else if(target_turf.z < here_turf.z)
- pointer="caret-down"
- var/list/trackinfo = list(
- locx = locx,
- locy = locy,
- userot = userot,
- rot = rot,
- arrowstyle = "ntosradarpointer.png", //For the rotation arrow, it's stupid I know
- color = "green",
- pointer = pointer,
- )
- return trackinfo
+/datum/computer_file/program/radar/lifeline/find_atom()
+ return locate(selected) in GLOB.human_list
/datum/computer_file/program/radar/lifeline/scan()
if(world.time < next_scan)
@@ -184,46 +256,18 @@
/datum/computer_file/program/radar/fission360
filename = "Fission360"
filedesc = "Fission360"
- program_icon_state = "generic"
+ program_icon_state = "radarsyndicate"
extended_desc = "This program allows for tracking of nuclear authorization disks and warheads."
requires_ntnet = FALSE
transfer_access = null
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosRadarSyndicate"
+ arrowstyle = "ntosradarpointerS.png"
+ pointercolor = "red"
-/datum/computer_file/program/radar/fission360/track()
- var/obj/nuke = locate(selected) in GLOB.poi_list
- if(!trackable(nuke))
- return
-
- var/turf/here_turf = (get_turf(computer))
- var/turf/target_turf = (get_turf(nuke))
- var/userot = FALSE
- var/rot = 0
- var/pointer="crosshairs"
- var/locx = (target_turf.x - here_turf.x)
- var/locy = (here_turf.y - target_turf.y)
- if(get_dist_euclidian(here_turf, target_turf) > 24) //If they're too far away, we need the angle for the arrow along the edge of the radar display
- userot = TRUE
- rot = round(Get_Angle(here_turf, target_turf))
- else
- locx = locx + 24
- locy = locy + 24
- if(target_turf.z > here_turf.z)
- pointer="caret-up"
- else if(target_turf.z < here_turf.z)
- pointer="caret-down"
- var/list/trackinfo = list(
- locx = locx,
- locy = locy,
- userot = userot,
- rot = rot,
- arrowstyle = "ntosradarpointerS.png",
- color = "red",
- pointer = pointer,
- )
- return trackinfo
+/datum/computer_file/program/radar/fission360/find_atom()
+ return locate(selected) in GLOB.poi_list
/datum/computer_file/program/radar/fission360/scan()
if(world.time < next_scan)
diff --git a/code/modules/modular_computers/file_system/programs/robocontrol.dm b/code/modules/modular_computers/file_system/programs/robocontrol.dm
index 910f923327..8644ce09b4 100644
--- a/code/modules/modular_computers/file_system/programs/robocontrol.dm
+++ b/code/modules/modular_computers/file_system/programs/robocontrol.dm
@@ -9,8 +9,6 @@
network_destination = "robotics control network"
size = 12
tgui_id = "NtosRoboControl"
- ui_x = 550
- ui_y = 550
///Number of simple robots on-station.
var/botcount = 0
///Used to find the location of the user for the purposes of summoning robots.
diff --git a/code/modules/modular_computers/file_system/programs/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
index 0a675a7abc..32ad102871 100644
--- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
@@ -9,8 +9,6 @@
network_destination = "supermatter monitoring system"
size = 5
tgui_id = "NtosSupermatterMonitor"
- ui_x = 600
- ui_y = 350
var/last_status = SUPERMATTER_INACTIVE
var/list/supermatters
var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal.
diff --git a/code/modules/modular_computers/hardware/CPU.dm b/code/modules/modular_computers/hardware/CPU.dm
index d08d65ff8b..f13081e1f3 100644
--- a/code/modules/modular_computers/hardware/CPU.dm
+++ b/code/modules/modular_computers/hardware/CPU.dm
@@ -37,4 +37,4 @@
icon_state = "cpu_super"
w_class = WEIGHT_CLASS_TINY
power_usage = 75
- max_idle_programs = 2
\ No newline at end of file
+ max_idle_programs = 2
diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm
index 37f3fc434e..b33442f99b 100644
--- a/code/modules/modular_computers/hardware/_hardware.dm
+++ b/code/modules/modular_computers/hardware/_hardware.dm
@@ -32,28 +32,29 @@
/obj/item/computer_hardware/attackby(obj/item/I, mob/living/user)
- // Multitool. Runs diagnostics
- if(istype(I, /obj/item/multitool))
- to_chat(user, "***** DIAGNOSTICS REPORT *****")
- diagnostics(user)
- to_chat(user, "******************************")
- return 1
-
// Cable coil. Works as repair method, but will probably require multiple applications and more cable.
if(istype(I, /obj/item/stack/cable_coil))
+ var/obj/item/stack/S = I
if(obj_integrity == max_integrity)
to_chat(user, "\The [src] doesn't seem to require repairs.")
return 1
- if(I.use_tool(src, user, 0, 1))
+ if(S.use(1))
to_chat(user, "You patch up \the [src] with a bit of \the [I].")
obj_integrity = min(obj_integrity + 10, max_integrity)
return 1
if(try_insert(I, user))
- return 1
+ return TRUE
return ..()
+/obj/item/computer_hardware/multitool_act(mob/living/user, obj/item/I)
+ ..()
+ to_chat(user, "***** DIAGNOSTICS REPORT *****")
+ diagnostics(user)
+ to_chat(user, "******************************")
+ return TRUE
+
// Called on multitool click, prints diagnostic information to the user.
/obj/item/computer_hardware/proc/diagnostics(var/mob/user)
to_chat(user, "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]")
diff --git a/code/modules/modular_computers/hardware/ai_slot.dm b/code/modules/modular_computers/hardware/ai_slot.dm
index 8428467a87..0ad157afcb 100644
--- a/code/modules/modular_computers/hardware/ai_slot.dm
+++ b/code/modules/modular_computers/hardware/ai_slot.dm
@@ -9,6 +9,10 @@
var/obj/item/aicard/stored_card = null
var/locked = FALSE
+/obj/item/computer_hardware/ai_slot/handle_atom_del(atom/A)
+ if(A == stored_card)
+ try_eject(0, null, TRUE)
+ . = ..()
/obj/item/computer_hardware/ai_slot/examine(mob/user)
. = ..()
@@ -41,13 +45,6 @@
/obj/item/computer_hardware/ai_slot/try_eject(slot=0,mob/living/user = null,forced = 0)
- if (get_dist(src,user) > 1)
- if (iscarbon(user))
- var/mob/living/carbon/H = user
- if (!(H.dna && H.dna.check_mutation(TK) && tkMaxRangeCheck(src,H)))
- return FALSE
- else
- return FALSE
if(!stored_card)
to_chat(user, "There is no card in \the [src].")
return FALSE
@@ -57,19 +54,21 @@
return FALSE
if(stored_card)
- stored_card.forceMove(get_turf(src))
+ to_chat(user, "You remove [stored_card] from [src].")
locked = FALSE
- stored_card.verb_pickup()
+ if(user)
+ user.put_in_hands(stored_card)
+ else
+ stored_card.forceMove(drop_location())
stored_card = null
- to_chat(user, "You remove the card from \the [src].")
return TRUE
return FALSE
/obj/item/computer_hardware/ai_slot/attackby(obj/item/I, mob/living/user)
if(..())
return
- if(istype(I, /obj/item/screwdriver))
+ if(I.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, "You press down on the manual eject button with \the [I].")
try_eject(,user,1)
- return
\ No newline at end of file
+ return
diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm
index e03427cc9c..6e3193abfd 100644
--- a/code/modules/modular_computers/hardware/battery_module.dm
+++ b/code/modules/modular_computers/hardware/battery_module.dm
@@ -7,6 +7,9 @@
var/obj/item/stock_parts/cell/battery = null
device_type = MC_CELL
+/obj/item/computer_hardware/battery/get_cell()
+ return battery
+
/obj/item/computer_hardware/battery/New(loc, battery_type = null)
if(battery_type)
battery = new battery_type(src)
@@ -16,6 +19,11 @@
. = ..()
QDEL_NULL(battery)
+/obj/item/computer_hardware/battery/handle_atom_del(atom/A)
+ if(A == battery)
+ try_eject(0, null, TRUE)
+ . = ..()
+
/obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null)
if(!holder)
return FALSE
@@ -45,7 +53,10 @@
to_chat(user, "There is no power cell connected to \the [src].")
return FALSE
else
- battery.forceMove(get_turf(src))
+ if(user)
+ user.put_in_hands(battery)
+ else
+ battery.forceMove(drop_location())
to_chat(user, "You detach \the [battery] from \the [src].")
battery = null
diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm
index e4bc45dbc5..18b423a42e 100644
--- a/code/modules/modular_computers/hardware/card_slot.dm
+++ b/code/modules/modular_computers/hardware/card_slot.dm
@@ -9,6 +9,13 @@
var/obj/item/card/id/stored_card = null
var/obj/item/card/id/stored_card2 = null
+/obj/item/computer_hardware/card_slot/handle_atom_del(atom/A)
+ if(A == stored_card)
+ try_eject(1, null, TRUE)
+ if(A == stored_card2)
+ try_eject(2, null, TRUE)
+ . = ..()
+
/obj/item/computer_hardware/card_slot/Destroy()
try_eject()
return ..()
@@ -67,19 +74,15 @@
else
stored_card2 = I
to_chat(user, "You insert \the [I] into \the [src].")
- playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
+ playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.sec_hud_set_ID()
return TRUE
/obj/item/computer_hardware/card_slot/try_eject(slot=0, mob/living/user = null, forced = 0)
- if (get_dist(src,user) > 1)
- if (iscarbon(user))
- var/mob/living/carbon/H = user
- if (!(H.dna && H.dna.check_mutation(TK) && tkMaxRangeCheck(src,H)))
- return FALSE
- else
- return FALSE
if(!stored_card && !stored_card2)
to_chat(user, "There are no cards in \the [src].")
return FALSE
@@ -89,7 +92,7 @@
if(user)
user.put_in_hands(stored_card)
else
- stored_card.forceMove(get_turf(src))
+ stored_card.forceMove(drop_location())
stored_card = null
ejected++
@@ -97,7 +100,7 @@
if(user)
user.put_in_hands(stored_card2)
else
- stored_card2.forceMove(get_turf(src))
+ stored_card2.forceMove(drop_location())
stored_card2 = null
ejected++
@@ -109,16 +112,18 @@
for(var/I in holder.idle_threads)
var/datum/computer_file/program/P = I
P.event_idremoved(1, slot)
-
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.sec_hud_set_ID()
to_chat(user, "You remove the card[ejected>1 ? "s" : ""] from \the [src].")
- playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
+ playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
return TRUE
return FALSE
/obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user)
if(..())
return
- if(istype(I, /obj/item/screwdriver))
+ if(I.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, "You press down on the manual eject button with \the [I].")
try_eject(0,user)
return
diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm
index e27eaa53ae..b8b9624388 100644
--- a/code/modules/modular_computers/hardware/hard_drive.dm
+++ b/code/modules/modular_computers/hardware/hard_drive.dm
@@ -157,18 +157,30 @@
max_capacity = 64
icon_state = "ssd_mini"
w_class = WEIGHT_CLASS_TINY
- custom_price = PRICE_ABOVE_NORMAL
+ custom_price = 150
-/obj/item/computer_hardware/hard_drive/small/syndicate // Syndicate variant - very slight better
+// Syndicate variant - very slight better
+/obj/item/computer_hardware/hard_drive/small/syndicate
desc = "An efficient SSD for portable devices developed by a rival organisation."
power_usage = 8
max_capacity = 70
var/datum/antagonist/traitor/traitor_data // Syndicate hard drive has the user's data baked directly into it on creation
+/// For tablets given to nuke ops
+/obj/item/computer_hardware/hard_drive/small/nukeops
+ power_usage = 8
+ max_capacity = 70
+
+/obj/item/computer_hardware/hard_drive/small/nukeops/install_default_programs()
+ store_file(new/datum/computer_file/program/computerconfig(src))
+ store_file(new/datum/computer_file/program/ntnetdownload/syndicate(src)) // Syndicate version; automatic access to syndicate apps and no NT apps
+ store_file(new/datum/computer_file/program/filemanager(src))
+ store_file(new/datum/computer_file/program/radar/fission360(src)) //I am legitimately afraid if I don't do this, Ops players will think they just don't get a pinpointer anymore.
+
/obj/item/computer_hardware/hard_drive/micro
name = "micro solid state drive"
desc = "A highly efficient SSD chip for portable devices."
power_usage = 2
max_capacity = 32
icon_state = "ssd_micro"
- w_class = WEIGHT_CLASS_TINY
\ No newline at end of file
+ w_class = WEIGHT_CLASS_TINY
diff --git a/code/modules/modular_computers/hardware/printer.dm b/code/modules/modular_computers/hardware/printer.dm
index 36c666e5d6..ebe40c1922 100644
--- a/code/modules/modular_computers/hardware/printer.dm
+++ b/code/modules/modular_computers/hardware/printer.dm
@@ -10,14 +10,14 @@
/obj/item/computer_hardware/printer/diagnostics(mob/living/user)
..()
- to_chat(user, "Paper level: [stored_paper]/[max_paper].")
+ to_chat(user, "Paper level: [stored_paper]/[max_paper].")
/obj/item/computer_hardware/printer/examine(mob/user)
. = ..()
. += "Paper level: [stored_paper]/[max_paper]."
-/obj/item/computer_hardware/printer/proc/print_text(var/text_to_print, var/paper_title = "")
+/obj/item/computer_hardware/printer/proc/print_text(text_to_print, paper_title = "")
if(!stored_paper)
return FALSE
if(!check_functionality())
@@ -27,11 +27,12 @@
// Damaged printer causes the resulting paper to be somewhat harder to read.
if(damage > damage_malfunction)
- P.setText(stars(text_to_print, 100-malfunction_probability))
+ P.info = stars(text_to_print, 100-malfunction_probability)
else
- P.setText(text_to_print)
+ P.info = text_to_print
if(paper_title)
P.name = paper_title
+ P.update_icon()
stored_paper--
P = null
return TRUE
diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm
index ee9def4191..a8d30bad21 100644
--- a/code/modules/modular_computers/laptop_vendor.dm
+++ b/code/modules/modular_computers/laptop_vendor.dm
@@ -27,9 +27,6 @@
var/dev_printer = 0 // 0: None, 1: Standard
var/dev_card = 0 // 0: None, 1: Standard
- ui_x = 500
- ui_y = 400
-
// Removes all traces of old order and allows you to begin configuration from scratch.
/obj/machinery/lapvend/proc/reset_order()
state = 0
@@ -224,15 +221,15 @@
return TRUE
return FALSE
-/obj/machinery/lapvend/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)
+/obj/machinery/lapvend/ui_interact(mob/user, datum/tgui/ui)
if(stat & (BROKEN | NOPOWER | MAINT))
if(ui)
ui.close()
return FALSE
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
- ui = new(user, src, ui_key, "ComputerFabricator", "Personal Computer Vendor", ui_x, ui_y, state = state)
+ ui = new(user, src, "ComputerFabricator")
ui.open()
/obj/machinery/lapvend/attackby(obj/item/I, mob/user)
@@ -241,7 +238,7 @@
if(!user.temporarilyRemoveItemFromInventory(c))
return
credits += c.value
- visible_message("[user] inserts [c.value] credits into [src].")
+ visible_message("[user] inserts [c.value] cr into [src].")
qdel(c)
return
else if(istype(I, /obj/item/holochip))
@@ -257,10 +254,10 @@
var/datum/bank_account/account = ID.registered_account
var/target_credits = total_price - credits
if(!account.adjust_money(-target_credits))
- say("Insufficient money on card to purchase!")
+ say("Insufficient credits on card to purchase!")
return
credits += target_credits
- say("[target_credits] cr has been desposited from your account.")
+ say("[target_credits] cr has been deposited from your account.")
return
return ..()
@@ -308,4 +305,4 @@
state = 3
addtimer(CALLBACK(src, .proc/reset_order), 100)
return TRUE
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm
index a338919c4b..3bc4463531 100644
--- a/code/modules/movespeed/_movespeed_modifier.dm
+++ b/code/modules/movespeed/_movespeed_modifier.dm
@@ -199,7 +199,13 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache)
else
continue
. += amt
+ var/old = cached_multiplicative_slowdown // CITAEDL EDIT - To make things a bit less jarring, when in situations where
+ // your delay decreases, "give" the delay back to the client
cached_multiplicative_slowdown = .
+ var/diff = old - cached_multiplicative_slowdown
+ if((diff > 0) && client)
+ if(client.move_delay > world.time + 1.5)
+ client.move_delay -= diff
/// Get the move speed modifiers list of the mob
/mob/proc/get_movespeed_modifiers()
diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm
index a2176ca95e..d17767bb1f 100644
--- a/code/modules/movespeed/modifiers/mobs.dm
+++ b/code/modules/movespeed/modifiers/mobs.dm
@@ -78,9 +78,6 @@
blacklisted_movetypes = FLOATING
variable = TRUE
-/datum/movespeed_modifier/shove
- multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH
-
/datum/movespeed_modifier/human_carry
variable = TRUE
diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm
index e6d53d914f..00cfa94893 100644
--- a/code/modules/ninja/energy_katana.dm
+++ b/code/modules/ninja/energy_katana.dm
@@ -14,7 +14,7 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 50
slot_flags = ITEM_SLOT_BELT
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_integrity = 200
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/datum/effect_system/spark_spread/spark_system
diff --git a/code/modules/ninja/suit/gloves.dm b/code/modules/ninja/suit/gloves.dm
index dbe4c80579..a06b753402 100644
--- a/code/modules/ninja/suit/gloves.dm
+++ b/code/modules/ninja/suit/gloves.dm
@@ -67,6 +67,7 @@
to_chat(H, "Gained [DisplayEnergy(.)] of energy from [A].")
else
to_chat(H, "\The [A] has run dry of energy, you must find another source!")
+ . = INTERRUPT_UNARMED_ATTACK
else
. = FALSE //as to not cancel attack_hand()
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm
index 508722ecf2..57faad9493 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm
@@ -14,5 +14,5 @@
/obj/item/throwing_star/ninja
name = "ninja throwing star"
- throwforce = 30
+ throwforce = 20
embedding = list("pain_mult" = 6, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15)
diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm
index b368589bc3..b8f2c95762 100644
--- a/code/modules/paperwork/filingcabinet.dm
+++ b/code/modules/paperwork/filingcabinet.dm
@@ -137,7 +137,7 @@
virgin = 0 //tabbing here is correct- it's possible for people to try and use it
//before the records have been generated, so we do this inside the loop.
-/obj/structure/filingcabinet/security/attack_hand()
+/obj/structure/filingcabinet/security/on_attack_hand()
populate()
. = ..()
@@ -170,8 +170,7 @@
virgin = 0 //tabbing here is correct- it's possible for people to try and use it
//before the records have been generated, so we do this inside the loop.
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/structure/filingcabinet/medical/attack_hand()
+/obj/structure/filingcabinet/medical/on_attack_hand()
populate()
. = ..()
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 462d50eb45..5d842ef11a 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -1,4 +1,4 @@
-/*
+/**
* Paper
* also scraps of paper
*
@@ -11,12 +11,11 @@
#define MODE_WRITING 1
#define MODE_STAMPING 2
-
/**
- ** This is a custom ui state. All it really does is keep track of pen
- ** being used and if they are editing it or not. This way we can keep
- ** the data with the ui rather than on the paper
- **/
+ * This is a custom ui state. All it really does is keep track of pen
+ * being used and if they are editing it or not. This way we can keep
+ * the data with the ui rather than on the paper
+ */
/datum/ui_state/default/paper_state
/// What edit mode we are in and who is
/// writing on it right now
@@ -33,7 +32,6 @@
var/stamp_name = ""
var/stamp_class = ""
-
/datum/ui_state/default/paper_state/proc/copy_from(datum/ui_state/default/paper_state/from)
switch(from.edit_mode)
if(MODE_READING)
@@ -49,12 +47,11 @@
stamp_class = from.stamp_class
stamp_name = from.stamp_name
-
/**
- ** Paper is now using markdown (like in github pull notes) for ALL rendering
- ** so we do loose a bit of functionality but we gain in easy of use of
- ** paper and getting rid of that crashing bug
- **/
+ * Paper is now using markdown (like in github pull notes) for ALL rendering
+ * so we do loose a bit of functionality but we gain in easy of use of
+ * paper and getting rid of that crashing bug
+ */
/obj/item/paper
name = "paper"
gender = NEUTER
@@ -71,6 +68,8 @@
resistance_flags = FLAMMABLE
max_integrity = 50
dog_fashion = /datum/dog_fashion/head
+ // drop_sound = 'sound/items/handling/paper_drop.ogg'
+ // pickup_sound = 'sound/items/handling/paper_pickup.ogg'
grind_results = list(/datum/reagent/cellulose = 3)
color = "white"
/// What's actually written on the paper.
@@ -89,9 +88,6 @@
var/contact_poison // Reagent ID to transfer on contact
var/contact_poison_volume = 0
- // ui stuff
- var/ui_x = 600
- var/ui_y = 800
// Ok, so WHY are we caching the ui's?
// Since we are not using autoupdate we
// need some way to update the ui's of
@@ -103,7 +99,6 @@
// people look at it
var/list/viewing_ui = list()
-
/// When the sheet can be "filled out"
/// This is an associated list
var/list/form_fields = list()
@@ -116,10 +111,10 @@
. = ..()
/**
- ** This proc copies this sheet of paper to a new
- ** sheet, Makes it nice and easy for carbon and
- ** the copyer machine
- **/
+ * This proc copies this sheet of paper to a new
+ * sheet, Makes it nice and easy for carbon and
+ * the copyer machine
+ */
/obj/item/paper/proc/copy()
var/obj/item/paper/N = new(arglist(args))
N.info = info
@@ -133,10 +128,10 @@
return N
/**
- ** This proc sets the text of the paper and updates the
- ** icons. You can modify the pen_color after if need
- ** be.
- **/
+ * This proc sets the text of the paper and updates the
+ * icons. You can modify the pen_color after if need
+ * be.
+ */
/obj/item/paper/proc/setText(text)
info = text
form_fields = null
@@ -152,30 +147,16 @@
contact_poison = null
. = ..()
-
/obj/item/paper/Initialize()
. = ..()
pixel_y = rand(-8, 8)
pixel_x = rand(-9, 9)
update_icon()
-
/obj/item/paper/update_icon_state()
if(info && show_written_words)
icon_state = "[initial(icon_state)]_words"
-/obj/item/paper/ui_base_html(html)
- /// This might change in a future PR
- var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper)
- . = replacetext(html, "", assets.css_tag())
-
-
-/obj/item/paper/examine_more(mob/user)
- ui_interact(user)
-
-/obj/item/paper/proc/show_content(mob/user)
- user.examinate(src)
-
/obj/item/paper/verb/rename()
set name = "Rename paper"
set category = "Object"
@@ -195,17 +176,14 @@
name = "paper[(n_name ? text("- '[n_name]'") : null)]"
add_fingerprint(usr)
-
/obj/item/paper/suicide_act(mob/user)
user.visible_message("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...")
return (BRUTELOSS)
-
/// ONLY USED FOR APRIL FOOLS
/obj/item/paper/proc/reset_spamflag()
spam_flag = FALSE
-
/obj/item/paper/attack_self(mob/user)
if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
if(!spam_flag)
@@ -214,7 +192,6 @@
addtimer(CALLBACK(src, .proc/reset_spamflag), 20)
. = ..()
-
/obj/item/paper/proc/clearpaper()
info = ""
stamps = null
@@ -222,29 +199,28 @@
cut_overlays()
update_icon_state()
-
-/obj/item/paper/examine(mob/user)
+/obj/item/paper/examine_more(mob/user)
ui_interact(user)
-
+ return list("You try to read [src]...")
/obj/item/paper/can_interact(mob/user)
if(!..())
return FALSE
- if(resistance_flags & ON_FIRE) // Are we on fire? Hard ot read if so
+ // Are we on fire? Hard ot read if so
+ if(resistance_flags & ON_FIRE)
return FALSE
- if(user.is_blind()) // Even harder to read if your blind...braile? humm
+ // Even harder to read if your blind...braile? humm
+ if(user.is_blind())
return FALSE
- return user.can_read(src) // checks if the user can read.
-
+ // checks if the user can read.
+ return user.can_read(src)
/**
- ** This creates the ui, since we are using a custom state but not much else
- ** just makes it easyer to make it. Also we make a custom ui_key as I am
- ** not sure how tgui handles many producers?
-**/
+ * This creates the ui, since we are using a custom state but not much else
+ * just makes it easyer to make it.
+ */
/obj/item/paper/proc/create_ui(mob/user, datum/ui_state/default/paper_state/state)
- ui_interact(user, "main", null, FALSE, null, state)
-
+ ui_interact(user, state = state)
/obj/item/proc/burn_paper_product_attackby_check(obj/item/I, mob/living/user, bypass_clumsy)
var/ignition_message = I.ignition_effect(src, user)
@@ -297,6 +273,7 @@
var/datum/ui_state/default/paper_state/state = new
state.edit_mode = MODE_STAMPING // we are read only becausse the sheet is full
state.stamp_icon_state = P.icon_state
+ state.stamp_name = P.name
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
state.stamp_class = sheet.icon_class_name(P.icon_state)
@@ -319,24 +296,27 @@
if(.)
info = "[stars(info)]"
-/obj/item/paper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/default/paper_state/state = new)
- ui_key = "main-[REF(user)]"
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/paper/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/simple/paper),
+ )
+
+/obj/item/paper/ui_interact(mob/user, datum/tgui/ui,
+ datum/ui_state/default/paper_state/state)
+ // Update the state
+ ui = ui || SStgui.get_open_ui(user, src)
+ if(ui && state)
+ var/datum/ui_state/default/paper_state/current_state = ui.state
+ current_state.copy_from(state)
+ // Update the UI
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper)
- assets.send(user)
- // The x size is because we double the width for the editor
- ui = new(user, src, ui_key, "PaperSheet", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "PaperSheet", name)
+ state = new
+ ui.set_state(state)
ui.set_autoupdate(FALSE)
viewing_ui[user] = ui
ui.open()
- else
- var/datum/ui_state/default/paper_state/last_state = ui.state
- if(last_state)
- last_state.copy_from(state)
- else
- ui.state = state
-
/obj/item/paper/ui_close(mob/user)
/// close the editing window and change the mode
@@ -346,7 +326,7 @@
// Again, we have to do this as autoupdate is off
/obj/item/paper/proc/update_all_ui()
for(var/datum/tgui/ui in viewing_ui)
- ui.update()
+ ui.process(force = TRUE)
// Again, we have to do this as autoupdate is off
/obj/item/paper/proc/close_all_ui()
@@ -382,7 +362,6 @@
return data
-
/obj/item/paper/ui_act(action, params, datum/tgui/ui, datum/ui_state/default/paper_state/state)
if(..())
return
@@ -444,21 +423,18 @@
. = TRUE
-
-/*
+/**
* Construction paper
*/
-
/obj/item/paper/construction
/obj/item/paper/construction/Initialize()
. = ..()
color = pick("FF0000", "#33cc33", "#ffb366", "#551A8B", "#ff80d5", "#4d94ff")
-/*
+/**
* Natural paper
*/
-
/obj/item/paper/natural/Initialize()
. = ..()
color = "#FFF5ED"
diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm
index 770a6682e0..3937720f74 100644
--- a/code/modules/paperwork/paper_cutter.dm
+++ b/code/modules/paperwork/paper_cutter.dm
@@ -66,10 +66,7 @@
return
..()
-/obj/item/papercutter/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/item/papercutter/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
if(!storedcutter)
to_chat(user, "The cutting blade is gone! You can't use [src] now.")
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index d1141c9f70..28cb5ffae9 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -11,6 +11,8 @@
throw_speed = 3
throw_range = 7
pressure_resistance = 8
+ attack_hand_speed = CLICK_CD_RAPID
+ attack_hand_is_action = TRUE
var/papertype = /obj/item/paper
var/total_paper = 30
var/list/papers = list()
@@ -60,11 +62,9 @@
/obj/item/paper_bin/attack_paw(mob/user)
return attack_hand(user)
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/paper_bin/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/paper_bin/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.lying)
return
- user.changeNext_move(CLICK_CD_MELEE)
if(bin_pen)
var/obj/item/pen/P = bin_pen
P.add_fingerprint(user)
@@ -148,7 +148,7 @@
papertype = /obj/item/paper/natural
resistance_flags = FLAMMABLE
-/obj/item/paper_bin/bundlenatural/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/paper_bin/bundlenatural/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
..()
if(total_paper < 1)
qdel(src)
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 08252d4e05..997ada6b21 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -28,6 +28,7 @@
var/degrees = 0
var/font = PEN_FONT
embedding = list()
+ sharpness = SHARP_POINTY
/obj/item/pen/suicide_act(mob/user)
user.visible_message("[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...")
@@ -84,7 +85,7 @@
throw_speed = 4
colour = "crimson"
custom_materials = list(/datum/material/gold = 750)
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
resistance_flags = FIRE_PROOF
unique_reskin = list("Oak" = "pen-fountain-o",
"Gold" = "pen-fountain-g",
@@ -180,7 +181,7 @@
*/
/obj/item/pen/edagger
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") //these wont show up if the pen is off
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
var/on = FALSE
embedding = list(embed_chance = EMBED_CHANCE)
diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm
index 3e76fc874a..b925c67940 100644
--- a/code/modules/photography/camera/camera.dm
+++ b/code/modules/photography/camera/camera.dm
@@ -221,4 +221,4 @@
p.set_picture(picture, TRUE, TRUE)
if(CONFIG_GET(flag/picture_logging_camera))
- picture.log_to_file()
\ No newline at end of file
+ picture.log_to_file()
diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm
index 6f7bc643c8..d306c46815 100644
--- a/code/modules/photography/photos/frame.dm
+++ b/code/modules/photography/photos/frame.dm
@@ -21,8 +21,7 @@
to_chat(user, "\The [src] already contains a photo.")
..()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/wallframe/picture/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/wallframe/picture/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.get_inactive_held_item() != src)
..()
return
@@ -141,10 +140,7 @@
..()
-/obj/structure/sign/picture_frame/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/structure/sign/picture_frame/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(framed)
framed.show(user)
diff --git a/code/modules/photography/photos/photo.dm b/code/modules/photography/photos/photo.dm
index 07f765c123..5c78709e9b 100644
--- a/code/modules/photography/photos/photo.dm
+++ b/code/modules/photography/photos/photo.dm
@@ -51,6 +51,8 @@
user.examinate(src)
/obj/item/photo/attackby(obj/item/P, mob/user, params)
+ if(try_burn(P, user))
+ return
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
if(!user.is_literate())
to_chat(user, "You scribble illegibly on [src]!")
@@ -60,6 +62,26 @@
scribble = txt
..()
+/obj/item/photo/proc/try_burn(obj/item/I, mob/living/user)
+ var/ignition_message = I.ignition_effect(src, user)
+ if(!ignition_message)
+ return
+ . = TRUE
+ if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10) && Adjacent(user))
+ user.visible_message("[user] accidentally ignites [user.p_them()]self!", \
+ "You miss [src] and accidentally light yourself on fire!")
+ if(user.is_holding(I)) //checking if they're holding it in case TK is involved
+ user.dropItemToGround(I)
+ user.adjust_fire_stacks(1)
+ user.IgniteMob()
+ return
+
+ if(user.is_holding(src)) //no TK shit here.
+ user.dropItemToGround(src)
+ user.visible_message(ignition_message)
+ add_fingerprint(user)
+ fire_act(I.get_temperature())
+
/obj/item/photo/examine(mob/user)
. = ..()
if(in_range(src, user))
diff --git a/code/modules/pool/pool_drain.dm b/code/modules/pool/pool_drain.dm
index 8deb9b1ffe..527c25b9f0 100644
--- a/code/modules/pool/pool_drain.dm
+++ b/code/modules/pool/pool_drain.dm
@@ -154,7 +154,7 @@
else
new /mob/living/simple_animal/hostile/shark/laser(loc)
-/obj/machinery/pool/filter/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/pool/filter/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
to_chat(user, "You search the filter.")
for(var/obj/O in contents)
O.forceMove(loc)
diff --git a/code/modules/pool/pool_main.dm b/code/modules/pool/pool_main.dm
index 30d1744b57..98189cc8a4 100644
--- a/code/modules/pool/pool_main.dm
+++ b/code/modules/pool/pool_main.dm
@@ -177,7 +177,7 @@
else
return ..()
-/turf/open/pool/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/turf/open/pool/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
diff --git a/code/modules/pool/pool_structures.dm b/code/modules/pool/pool_structures.dm
index 6b71e95639..ec5d455958 100644
--- a/code/modules/pool/pool_structures.dm
+++ b/code/modules/pool/pool_structures.dm
@@ -11,7 +11,7 @@
layer = ABOVE_MOB_LAYER
dir = EAST
-/obj/structure/pool/ladder/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/pool/ladder/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
@@ -52,7 +52,7 @@
user.pixel_x = initial_px
user.pixel_y = initial_py
-/obj/structure/pool/Lboard/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/pool/Lboard/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(iscarbon(user))
var/mob/living/carbon/jumper = user
if(jumping)
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 19e32bae0b..65b3c0a2e4 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -38,6 +38,8 @@
#define APC_CHARGING 1
#define APC_FULLY_CHARGED 2
+#define MAXIMUM_COG_REGAIN 100 //How much charge drained by an integration cog can be priority-recharged in one processing-tick
+
// the Area Power Controller (APC), formerly Power Distribution Unit (PDU)
// one per area, needs wire connection to power network through a terminal
@@ -94,6 +96,7 @@
var/mob/living/silicon/ai/occupier = null
var/transfer_in_progress = FALSE //Is there an AI being transferred out of us?
var/obj/item/clockwork/integration_cog/integration_cog //Is there a cog siphoning power?
+ var/cog_drained = 0 //How much of the cell's charge was drained by an integration cog, recovering this amount takes priority over the normal APC cell recharge calculations, but comes after powering Essentials.
var/longtermpower = 10
var/auto_name = 0
var/failure_timer = 0
@@ -499,6 +502,7 @@
cell.forceMove(T)
cell.update_icon()
cell = null
+ cog_drained = 0 //No more cell means no more averting celldrain
charging = APC_NOT_CHARGING
update_icon()
return
@@ -701,7 +705,7 @@
START_PROCESSING(SSfastprocess, W)
playsound(src, 'sound/machines/clockcult/steam_whoosh.ogg', 50, FALSE)
opened = APC_COVER_CLOSED
- locked = FALSE
+ locked = TRUE //Clockies get full APC access on cogged APCs, but they can't lock or unlock em unless they steal some ID to give all of them APC access, soo this is pretty much just QoL for them and makes cogs a tiny bit more stealthy
update_icon()
return
else if(panel_open && !opened && is_wire_tool(W))
@@ -833,10 +837,47 @@
// attack with hand - remove cell (if cover open) or interact with the APC
-/obj/machinery/power/apc/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/machinery/power/apc/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+ if(isethereal(user))
+ var/mob/living/carbon/human/H = user
+ if(H.a_intent == INTENT_HARM)
+ if(cell.charge <= (cell.maxcharge / 2)) // if charge is under 50% you shouldnt drain it
+ to_chat(H, "The APC doesn't have much power, you probably shouldn't drain any.")
+ return
+ var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
+ if(stomach.crystal_charge > 145)
+ to_chat(H, "Your charge is full!")
+ return
+ to_chat(H, "You start channeling some power through the APC into your body.")
+ if(do_after(user, 75, target = src))
+ if(cell.charge <= (cell.maxcharge / 2) || (stomach.crystal_charge > 145))
+ return
+ if(istype(stomach))
+ to_chat(H, "You receive some charge from the APC.")
+ stomach.adjust_charge(10)
+ cell.charge -= 10
+ else
+ to_chat(H, "You can't receive charge from the APC!")
+ return
+ if(H.a_intent == INTENT_GRAB)
+ if(cell.charge == cell.maxcharge)
+ to_chat(H, "The APC is full!")
+ return
+ var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
+ if(stomach.crystal_charge < 10)
+ to_chat(H, "Your charge is too low!")
+ return
+ to_chat(H, "You start channeling power through your body into the APC.")
+ if(do_after(user, 75, target = src))
+ if(cell.charge == cell.maxcharge || (stomach.crystal_charge < 10))
+ return
+ if(istype(stomach))
+ to_chat(H, "You transfer some power to the APC.")
+ stomach.adjust_charge(-10)
+ cell.charge += 10
+ else
+ to_chat(H, "You can't transfer power to the APC!")
+ return
if(opened && (!issilicon(user)))
if(cell)
user.visible_message("[user] removes \the [cell] from [src]!","You remove \the [cell].")
@@ -849,26 +890,19 @@
if((stat & MAINT) && !opened) //no board; no interface
return
-/obj/machinery/power/apc/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
-
+/obj/machinery/power/apc/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Apc", name, 480, 460, master_ui, state)
+ ui = new(user, src, "Apc", name)
ui.open()
/obj/machinery/power/apc/ui_data(mob/user)
- var/obj/item/implant/hijack/H = user.getImplant(/obj/item/implant/hijack)
- var/abilitiesavail = FALSE
- if (H && !H.stealthmode && H.toggled)
- abilitiesavail = TRUE
var/list/data = list(
"locked" = locked,
- "lock_nightshift" = nightshift_requires_auth,
"failTime" = failure_timer,
"isOperating" = operating,
"externalPower" = main_status,
- "powerCellStatus" = (cell?.percent() || null),
+ "powerCellStatus" = cell ? cell.percent() : null,
"chargeMode" = chargemode,
"chargingStatus" = charging,
"totalLoad" = DisplayPower(lastused_total),
@@ -877,10 +911,7 @@
"malfStatus" = get_malf_status(user),
"emergencyLights" = !emergency_lights,
"nightshiftLights" = nightshift_lights,
- "hijackable" = HAS_TRAIT(user,TRAIT_HIJACKER),
- "hijacker" = hijacker == user ? TRUE : FALSE,
- "drainavail" = cell && cell.percent() >= 85 && abilitiesavail,
- "lockdownavail" = cell && cell.percent() >= 35 && abilitiesavail,
+
"powerChannels" = list(
list(
"title" = "Equipment",
@@ -935,6 +966,9 @@
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
/obj/machinery/power/apc/proc/update()
+ var/old_light = area.power_light
+ var/old_equip = area.power_equip
+ var/old_environ = area.power_environ
if(operating && !shorted && !failure_timer)
area.power_light = (lighting > 1)
area.power_equip = (equipment > 1)
@@ -943,7 +977,8 @@
area.power_light = FALSE
area.power_equip = FALSE
area.power_environ = FALSE
- area.power_change()
+ if(old_light != area.power_light || old_equip != area.power_equip || old_environ != area.power_environ)
+ area.power_change()
/obj/machinery/power/apc/proc/can_use(mob/user, loud = 0) //used by attack_hand() and Topic()
if(IsAdminGhost(user))
@@ -974,43 +1009,32 @@
. = UI_INTERACTIVE
/obj/machinery/power/apc/ui_act(action, params)
- if(..() || !can_use(usr, 1))
- return
- if(failure_timer)
- if(action == "reboot")
- failure_timer = 0
- update_icon()
- update()
- if(action == "hijack" && can_use(usr, 1)) //don't need auth for hijack button
- hijack(usr)
- return
- var/authorized = (!locked || area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE) || (integration_cog && (is_servant_of_ratvar(usr))))
- if((action == "toggle_nightshift") && (!nightshift_requires_auth || authorized))
- toggle_nightshift_lights()
- return TRUE
- if(!authorized)
+ if(..() || !can_use(usr, 1) || (locked && area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE) && !failure_timer && action != "toggle_nightshift") || (integration_cog && (is_servant_of_ratvar(usr))))
return
switch(action)
if("lock")
if(area.hasSiliconAccessInArea(usr))
if((obj_flags & EMAGGED) || (stat & (BROKEN|MAINT)))
- to_chat(usr, "The APC does not respond to the command.")
+ to_chat(usr, "The APC does not respond to the command!")
else
locked = !locked
update_icon()
- return TRUE
+ . = TRUE
if("cover")
coverlocked = !coverlocked
- return TRUE
+ . = TRUE
if("breaker")
- toggle_breaker()
- return TRUE
+ toggle_breaker(usr)
+ . = TRUE
+ if("toggle_nightshift")
+ toggle_nightshift_lights()
+ . = TRUE
if("charge")
chargemode = !chargemode
if(!chargemode)
charging = APC_NOT_CHARGING
update_icon()
- return TRUE
+ . = TRUE
if("channel")
if(params["eqp"])
equipment = setsubsystem(text2num(params["eqp"]))
@@ -1024,23 +1048,24 @@
environ = setsubsystem(text2num(params["env"]))
update_icon()
update()
- return TRUE
+ . = TRUE
if("overload")
- if(area.hasSiliconAccessInArea(usr))
+ if(area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE)) //usr.has_unlimited_silicon_privilege)
overload_lighting()
- return TRUE
+ . = TRUE
if("hack")
if(get_malf_status(usr))
malfhack(usr)
- return TRUE
if("occupy")
if(get_malf_status(usr))
malfoccupy(usr)
- return TRUE
if("deoccupy")
if(get_malf_status(usr))
malfvacate()
- return TRUE
+ if("reboot")
+ failure_timer = 0
+ update_icon()
+ update()
if("emergency_lighting")
emergency_lights = !emergency_lights
for(var/obj/machinery/light/L in area)
@@ -1048,31 +1073,14 @@
L.no_emergency = emergency_lights
INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE)
CHECK_TICK
- if("drain")
- cell.use(cell.charge)
- hijacker.toggleSiliconAccessArea(area)
- hijacker = null
- set_hijacked_lighting()
- update_icon()
- var/obj/item/implant/hijack/H = usr.getImplant(/obj/item/implant/hijack)
- H.stealthcooldown = world.time + 2 MINUTES
- energy_fail(30 SECONDS * (cell.charge / cell.maxcharge))
- if("lockdown")
- var/celluse = rand(20,35)
- celluse = celluse /100
- for (var/obj/machinery/door/D in GLOB.airlocks)
- if (get_area(D) == area)
- INVOKE_ASYNC(D,/obj/machinery/door.proc/hostile_lockdown,usr, FALSE)
- addtimer(CALLBACK(D,/obj/machinery/door.proc/disable_lockdown, FALSE), 30 SECONDS)
- cell.charge -= cell.maxcharge*celluse
- var/obj/item/implant/hijack/H = usr.getImplant(/obj/item/implant/hijack)
- H.stealthcooldown = world.time + 3 MINUTES
return TRUE
-/obj/machinery/power/apc/proc/toggle_breaker()
+/obj/machinery/power/apc/proc/toggle_breaker(mob/user)
if(!is_operational() || failure_timer)
return
operating = !operating
+ add_hiddenprint(user) //delete when runtime
+ log_game("[key_name(user)] turned [operating ? "on" : "off"] the [src] in [AREACOORD(src)]")
update()
update_icon()
@@ -1310,6 +1318,11 @@
cur_used -= lastused_light
lighting_satisfied = TRUE
+ //If drained by an integration cog: Forcefully avert as much of the powerdrain as possible, though a maximum of MAXIMUM_COG_REGAIN
+ if(cur_excess && cog_drained && cell)
+ var/cog_regain = cell.give(min(min(cog_drained, cur_excess), MAXIMUM_COG_REGAIN))
+ cur_excess -= cog_regain
+ cog_drained = max(0, cog_drained - cog_regain)
// next: take from or charge to the cell, depending on how much is left
if(cell && !shorted)
@@ -1572,6 +1585,8 @@
#undef APC_UPOVERLAY_LOCKED
#undef APC_UPOVERLAY_OPERATING
+#undef MAXIMUM_COG_REGAIN
+
/*Power module, used for APC construction*/
/obj/item/electronics/apc
name = "power control module"
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index c8b02669e8..6dcb08512c 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -564,10 +564,7 @@ By design, d1 is the smallest direction and d2 is the highest
icon_state = "[initial(item_state)][amount < 3 ? amount : ""]"
name = "cable [amount < 3 ? "piece" : "coil"]"
-/obj/item/stack/cable_coil/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/item/stack/cable_coil/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
var/obj/item/stack/cable_coil/new_cable = ..()
if(istype(new_cable))
new_cable.color = color
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index ba6311a94d..6425feac31 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -151,6 +151,27 @@
if(prob(25))
corrupt()
+/obj/item/stock_parts/cell/attack_self(mob/user)
+ if(isethereal(user))
+ var/mob/living/carbon/human/H = user
+ if(charge < 100)
+ to_chat(H, "The [src] doesn't have enough power!")
+ return
+ var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
+ if(stomach.crystal_charge > 146)
+ to_chat(H, "Your charge is full!")
+ return
+ to_chat(H, "You clumsily channel power through the [src] and into your body, wasting some in the process.")
+ if(do_after(user, 5, target = src))
+ if((charge < 100) || (stomach.crystal_charge > 146))
+ return
+ if(istype(stomach))
+ to_chat(H, "You receive some charge from the [src].")
+ stomach.adjust_charge(3)
+ charge -= 100 //you waste way more than you receive, so that ethereals cant just steal one cell and forget about hunger
+ else
+ to_chat(H, "You can't receive charge from the [src]!")
+ return
/obj/item/stock_parts/cell/blob_act(obj/structure/blob/B)
ex_act(EXPLODE_DEVASTATE)
diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm
index 2bd4c04402..466030b83c 100644
--- a/code/modules/power/floodlight.dm
+++ b/code/modules/power/floodlight.dm
@@ -92,10 +92,7 @@
else
. = ..()
-/obj/machinery/power/floodlight/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/machinery/power/floodlight/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
var/current = setting
if(current == 1)
current = light_setting_list.len
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index 76154907ae..e37ae56e71 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -80,7 +80,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
/obj/machinery/gravity_generator/part/get_status()
return main_part?.get_status()
-/obj/machinery/gravity_generator/part/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/gravity_generator/part/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
return main_part.attack_hand(user)
/obj/machinery/gravity_generator/part/set_broken()
@@ -116,8 +116,6 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
sprite_number = 8
use_power = IDLE_POWER_USE
interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE
- ui_x = 400
- ui_y = 165
var/on = TRUE
var/breaker = TRUE
var/list/parts = list()
@@ -222,11 +220,10 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
return
return ..()
-/obj/machinery/gravity_generator/main/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/gravity_generator/main/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "GravityGenerator", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "GravityGenerator", name)
ui.open()
/obj/machinery/gravity_generator/main/ui_data(mob/user)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index f911a6a4e4..4c76c4b5b1 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -595,11 +595,9 @@
// attack with hand - remove tube/bulb
// if hands aren't protected and the light is on, burn the player
-/obj/machinery/light/attack_hand(mob/living/carbon/human/user)
+/obj/machinery/light/on_attack_hand(mob/living/carbon/human/user)
. = ..()
- if(.)
- return
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
add_fingerprint(user)
if(status == LIGHT_EMPTY)
@@ -612,7 +610,18 @@
var/mob/living/carbon/human/H = user
if(istype(H))
-
+ var/datum/species/ethereal/eth_species = H.dna?.species
+ if(istype(eth_species))
+ to_chat(H, "You start channeling some power through the [fitting] into your body.")
+ if(do_after(user, 50, target = src))
+ var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
+ if(istype(stomach))
+ to_chat(H, "You receive some charge from the [fitting].")
+ stomach.adjust_charge(2)
+ else
+ to_chat(H, "You can't receive charge from the [fitting]!")
+ return
+
if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
if(G.max_heat_protection_temperature)
@@ -812,11 +821,11 @@
return
/obj/item/light/attack(mob/living/M, mob/living/user, def_zone)
- ..()
+ . = ..()
shatter()
/obj/item/light/attack_obj(obj/O, mob/living/user)
- ..()
+ . = ..()
shatter()
/obj/item/light/proc/shatter()
diff --git a/code/modules/power/monitor.dm b/code/modules/power/monitor.dm
index 974fb1b9e2..393d403c4d 100644
--- a/code/modules/power/monitor.dm
+++ b/code/modules/power/monitor.dm
@@ -11,8 +11,6 @@
active_power_usage = 100
circuit = /obj/item/circuitboard/computer/powermonitor
tgui_id = "PowerMonitor"
- ui_x = 550
- ui_y = 700
var/obj/structure/cable/attached_wire
var/obj/machinery/power/apc/local_apc
@@ -84,11 +82,10 @@
if(demand.len > record_size)
demand.Cut(1, 2)
-/obj/machinery/computer/monitor/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/monitor/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "PowerMonitor", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "PowerMonitor", name)
ui.open()
/obj/machinery/computer/monitor/ui_data()
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index d4e0df8359..e2f8c4e58a 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -7,8 +7,6 @@
density = TRUE
anchored = FALSE
use_power = NO_POWER_USE
- ui_x = 450
- ui_y = 340
var/active = FALSE
var/power_gen = 5000
@@ -219,11 +217,10 @@
/obj/machinery/power/port_gen/pacman/attack_paw(mob/user)
interact(user)
-/obj/machinery/power/port_gen/pacman/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "PortableGenerator", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "PortableGenerator", name)
ui.open()
/obj/machinery/power/port_gen/pacman/ui_data()
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index 4cc9cbe34f..256b13ee72 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -176,6 +176,7 @@
/obj/machinery/power/rad_collector/analyzer_act(mob/living/user, obj/item/I)
if(loaded_tank)
loaded_tank.analyzer_act(user, I)
+ return TRUE
/obj/machinery/power/rad_collector/examine(mob/user)
. = ..()
diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm
index 5ef66e26d9..dfb51df9cf 100644
--- a/code/modules/power/singularity/containment_field.dm
+++ b/code/modules/power/singularity/containment_field.dm
@@ -21,8 +21,7 @@
FG2.fields -= src
return ..()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/machinery/field/containment/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/field/containment/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(get_dist(src, user) > 1)
return FALSE
else
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 0d182e0a1b..50dae7d6bb 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -315,6 +315,9 @@
/obj/machinery/power/emitter/proc/integrate(obj/item/gun/energy/E,mob/user)
if(istype(E, /obj/item/gun/energy))
+ if(!E.can_emitter)
+ to_chat(user, "[E] cannot fit into emitters.")
+ return
if(!user.transferItemToLoc(E, src))
return
gun = E
diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
index e33116b02c..528a3abb8b 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
@@ -103,7 +103,6 @@
did_something = TRUE
if(did_something)
- user.changeNext_move(CLICK_CD_MELEE)
update_state()
update_icon()
return
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index beaf4bfc43..96c8d9a263 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -10,8 +10,6 @@
active_power_usage = 10000
dir = NORTH
mouse_opacity = MOUSE_OPACITY_OPAQUE
- ui_x = 350
- ui_y = 185
var/strength_upper_limit = 2
var/interface_control = TRUE
var/list/obj/structure/particle_accelerator/connected_parts
@@ -246,7 +244,6 @@
did_something = TRUE
if(did_something)
- user.changeNext_move(CLICK_CD_MELEE)
update_state()
update_icon()
return
@@ -276,11 +273,10 @@
return ..()
return UI_CLOSE
-/obj/machinery/particle_accelerator/control_box/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/particle_accelerator/control_box/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "ParticleAccelerator", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "ParticleAccelerator", name)
ui.open()
/obj/machinery/particle_accelerator/control_box/ui_data(mob/user)
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 96f8b4e996..cc3a19cf55 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -59,7 +59,7 @@
last_failed_movement = direct
return 0
-/obj/singularity/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/singularity/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
consume(user)
return TRUE
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index fcc7faa29e..a4fc7d0641 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -21,8 +21,6 @@
density = TRUE
use_power = NO_POWER_USE
circuit = /obj/item/circuitboard/machine/smes
- ui_x = 340
- ui_y = 350
var/capacity = 5e6 // maximum charge
var/charge = 0 // actual charge
@@ -202,7 +200,7 @@
/obj/machinery/power/smes/update_overlays()
. = ..()
- if((stat & BROKEN) || panel_open)
+ if(stat & BROKEN)
return
if(panel_open)
@@ -318,11 +316,10 @@
return
-/obj/machinery/power/smes/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/power/smes/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Smes", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "Smes", name)
ui.open()
/obj/machinery/power/smes/ui_data()
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 2c258c1f49..cf526f083d 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -115,9 +115,6 @@
panel.icon_state = "solar_panel-b"
else
panel.icon_state = "solar_panel"
-#if DM_VERSION <= 512
- . += new /mutable_appearance(panel)
-#endif
/obj/machinery/power/solar/proc/queue_turn(azimuth)
needs_to_turn = TRUE
@@ -346,11 +343,10 @@
else
. += mutable_appearance(icon, icon_screen)
-/obj/machinery/power/solar_control/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/power/solar_control/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "SolarControl", name, 380, 230, master_ui, state)
+ ui = new(user, src, "SolarControl", name)
ui.open()
/obj/machinery/power/solar_control/ui_data()
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 823ba75e43..8559b8ba45 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -571,7 +571,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal/attack_ai(mob/user)
return
-/obj/machinery/power/supermatter_crystal/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/power/supermatter_crystal/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm
index e7a97c554f..a9acea719c 100644
--- a/code/modules/power/turbine.dm
+++ b/code/modules/power/turbine.dm
@@ -56,8 +56,6 @@
resistance_flags = FIRE_PROOF
CanAtmosPass = ATMOS_PASS_DENSITY
circuit = /obj/item/circuitboard/machine/power_turbine
- ui_x = 310
- ui_y = 150
var/opened = 0
var/obj/machinery/power/compressor/compressor
var/turf/outturf
@@ -249,11 +247,10 @@
default_deconstruction_crowbar(I)
-/obj/machinery/power/turbine/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/power/turbine/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "TurbineComputer", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "TurbineComputer", name)
ui.open()
/obj/machinery/power/turbine/ui_data(mob/user)
@@ -292,8 +289,6 @@
icon_screen = "turbinecomp"
icon_keyboard = "tech_key"
circuit = /obj/item/circuitboard/computer/turbine_computer
- ui_x = 310
- ui_y = 150
var/obj/machinery/power/compressor/compressor
var/id = 0
@@ -313,11 +308,10 @@
else
compressor = locate(/obj/machinery/power/compressor) in range(7, src)
-/obj/machinery/computer/turbine_computer/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/turbine_computer/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "TurbineComputer", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "TurbineComputer", name)
ui.open()
/obj/machinery/computer/turbine_computer/ui_data(mob/user)
diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm
index ee6a25d8e4..6a73d9a366 100644
--- a/code/modules/projectiles/ammunition/_ammunition.dm
+++ b/code/modules/projectiles/ammunition/_ammunition.dm
@@ -16,7 +16,8 @@
var/variance = 0 //Variance for inaccuracy fundamental to the casing
var/randomspread = 0 //Randomspread for automatics
var/delay = 0 //Delay for energy weapons
- var/click_cooldown_override = 0 //Override this to make your gun have a faster fire rate, in tenths of a second. 4 is the default gun cooldown.
+ /// Override this to make the gun check for a different cooldown rather than CLICK_CD_RANGE, which is 4 deciseconds.
+ var/click_cooldown_override
var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the ammo is fired.
var/heavy_metal = TRUE
var/harmful = TRUE //pacifism check for boolet, set to FALSE if bullet is non-lethal
diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm
index 340cfc2e98..0ef4c680aa 100644
--- a/code/modules/projectiles/ammunition/_firing.dm
+++ b/code/modules/projectiles/ammunition/_firing.dm
@@ -16,10 +16,7 @@
AddComponent(/datum/component/pellet_cloud, projectile_type, pellets)
SEND_SIGNAL(src, COMSIG_PELLET_CLOUD_INIT, target, user, fired_from, randomspread, spread, zone_override, params, distro)
- if(click_cooldown_override)
- user.changeNext_move(click_cooldown_override)
- else
- user.changeNext_move(CLICK_CD_RANGE)
+ user.DelayNextAction(considered_action = TRUE, immediate = FALSE)
user.newtonian_move(get_dir(target, user))
update_icon()
return 1
diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
index ea84e23d01..b6fdef69e2 100644
--- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm
+++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
@@ -8,6 +8,18 @@
projectile_type = /obj/item/projectile/bullet/shotgun_slug
custom_materials = list(/datum/material/iron=4000)
+obj/item/ammo_casing/shotgun/executioner
+ name = "executioner slug"
+ desc = "A 12 gauge lead slug purpose built to annihilate flesh on impact."
+ icon_state = "stunshell"
+ projectile_type = /obj/item/projectile/bullet/shotgun_slug/executioner
+
+/obj/item/ammo_casing/shotgun/pulverizer
+ name = "pulverizer slug"
+ desc = "A 12 gauge lead slug purpose built to annihilate bones on impact."
+ icon_state = "stunshell"
+ projectile_type = /obj/item/projectile/bullet/shotgun_slug/pulverizer
+
/obj/item/ammo_casing/shotgun/beanbag
name = "beanbag slug"
desc = "A weak beanbag slug for riot control."
diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm
index 174645dd11..05c47fc3bb 100644
--- a/code/modules/projectiles/ammunition/energy/laser.dm
+++ b/code/modules/projectiles/ammunition/energy/laser.dm
@@ -37,6 +37,11 @@
select_name = "anti-vehicle"
fire_sound = 'sound/weapons/lasercannonfire.ogg'
+/obj/item/ammo_casing/energy/laser/hellfire
+ projectile_type = /obj/item/projectile/beam/laser/hellfire
+ e_cost = 130
+ select_name = "maim"
+
/obj/item/ammo_casing/energy/laser/pulse
projectile_type = /obj/item/projectile/beam/pulse
e_cost = 200
diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
index e4674f4f4c..987efc0404 100644
--- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
+++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
@@ -47,7 +47,7 @@
/obj/item/ammo_box/c38/dumdum
name = "speed loader (.38 DumDum)"
- desc = "Designed to quickly reload revolvers. DumDum bullets shatter on impact and shred the target's innards, likely getting caught inside."
+ desc = "Designed to quickly reload revolvers. These rounds expand on impact, allowing them to shred the target and cause massive bleeding. Very weak against armor and distant targets."
ammo_type = /obj/item/ammo_casing/c38/dumdum
/obj/item/ammo_box/c38/match
diff --git a/code/modules/projectiles/boxes_magazines/external/shotgun.dm b/code/modules/projectiles/boxes_magazines/external/shotgun.dm
index 1001937678..ed41375aee 100644
--- a/code/modules/projectiles/boxes_magazines/external/shotgun.dm
+++ b/code/modules/projectiles/boxes_magazines/external/shotgun.dm
@@ -1,5 +1,5 @@
/obj/item/ammo_box/magazine/m12g
- name = "shotgun magazine (12g buckshot slugs)"
+ name = "shotgun magazine (12g buckshot)"
desc = "A drum magazine."
icon_state = "m12gb"
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
@@ -17,7 +17,7 @@
/obj/item/ammo_box/magazine/m12g/slug
name = "shotgun magazine (12g slugs)"
- icon_state = "m12gb" //this may need an unique sprite
+ icon_state = "m12gsl"
ammo_type = /obj/item/ammo_casing/shotgun
/obj/item/ammo_box/magazine/m12g/dragon
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index b90f0aee0d..c3248bab2f 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -17,6 +17,7 @@
force = 5
item_flags = NEEDS_PERMIT
attack_verb = list("struck", "hit", "bashed")
+ attack_speed = CLICK_CD_RANGE
var/fire_sound = "gunshot"
var/suppressed = null //whether or not a message is displayed when fired
@@ -28,6 +29,13 @@
trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers
var/sawn_desc = null //description change if weapon is sawn-off
var/sawn_off = FALSE
+
+ /// can we be put into a turret
+ var/can_turret = TRUE
+ /// can we be put in a circuit
+ var/can_circuit = TRUE
+ /// can we be put in an emitter
+ var/can_emitter = TRUE
/// Weapon is burst fire if this is above 1
var/burst_size = 1
@@ -166,6 +174,8 @@
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
+ if(!CheckAttackCooldown(user, target))
+ return
process_afterattack(target, user, flag, params)
/obj/item/gun/proc/process_afterattack(atom/target, mob/living/user, flag, params)
@@ -174,16 +184,19 @@
if(firing)
return
var/stamloss = user.getStaminaLoss()
- if(stamloss >= STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
- var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_GUN_DELAY
- user.changeNext_move(CLICK_CD_RANGE+(CLICK_CD_RANGE*penalty))
if(flag) //It's adjacent, is the user, or is on the user's person
if(target in user.contents) //can't shoot stuff inside us.
return
if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack
return
- if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected)
+ if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH && (user.a_intent != INTENT_DISARM)) //so we can't shoot ourselves (unless mouth selected or disarm intent)
return
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ for(var/i in C.all_wounds)
+ var/datum/wound/W = i
+ if(W.try_treating(src, user))
+ return // another coward cured!
if(istype(user))//Check if the user can use the gun, if the user isn't alive(turrets) assume it can.
var/mob/living/L = user
@@ -213,6 +226,8 @@
to_chat(user, "You need both hands free to fire \the [src]!")
return
+ user.DelayNextAction()
+
//DUAL (or more!) WIELDING
var/bonus_spread = 0
var/loop_counter = 0
@@ -243,6 +258,17 @@
to_chat(user, " [src] is lethally chambered! You don't want to risk harming anyone...")
return FALSE
+/obj/item/gun/CheckAttackCooldown(mob/user, atom/target)
+ if((user.a_intent == INTENT_HARM) && user.Adjacent(target)) //melee
+ return user.CheckActionCooldown(CLICK_CD_MELEE)
+ return user.CheckActionCooldown(get_clickcd())
+
+/obj/item/gun/proc/get_clickcd()
+ return isnull(chambered?.click_cooldown_override)? CLICK_CD_RANGE : chambered.click_cooldown_override
+
+/obj/item/gun/GetEstimatedAttackSpeed()
+ return get_clickcd()
+
/obj/item/gun/proc/handle_pins(mob/living/user)
if(no_pin_required)
return TRUE
@@ -357,17 +383,14 @@
if(user.a_intent == INTENT_HARM) //Flogging
if(bayonet)
M.attackby(bayonet, user)
- attack_delay_done = TRUE
return
else
return ..()
- attack_delay_done = TRUE //we are firing the gun, not bashing people with its butt.
/obj/item/gun/attack_obj(obj/O, mob/user)
if(user.a_intent == INTENT_HARM)
if(bayonet)
- O.attackby(bayonet, user)
- return TRUE
+ return O.attackby(bayonet, user)
return ..()
/obj/item/gun/attackby(obj/item/I, mob/user, params)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index e5dc056011..fa8099a257 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -97,8 +97,7 @@
w_class += S.w_class //so pistols do not fit in pockets when suppressed
update_icon()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/gun/ballistic/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/gun/ballistic/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(loc == user)
if(suppressed && can_unsuppress)
var/obj/item/suppressor/S = suppressed
@@ -180,13 +179,11 @@
#undef BRAINS_BLOWN_THROW_SPEED
#undef BRAINS_BLOWN_THROW_RANGE
-
-
/obj/item/gun/ballistic/proc/sawoff(mob/user)
if(sawn_off)
to_chat(user, "\The [src] is already shortened!")
return
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
user.visible_message("[user] begins to shorten \the [src].", "You begin to shorten \the [src]...")
//if there's any live ammo inside the gun, makes it go off
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 89e30e765b..b31fd2d1e0 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -327,8 +327,7 @@
. = ..()
update_icon()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/gun/ballistic/automatic/l6_saw/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(loc != user)
..()
return //let them pick it up
diff --git a/code/modules/projectiles/guns/ballistic/laser_gatling.dm b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
index c2dd5bb42d..244bc5b124 100644
--- a/code/modules/projectiles/guns/ballistic/laser_gatling.dm
+++ b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
@@ -29,8 +29,7 @@
/obj/item/minigunpack/process()
overheat = max(0, overheat - heat_diffusion)
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/minigunpack/attack_hand(var/mob/living/carbon/user)
+/obj/item/minigunpack/on_attack_hand(var/mob/living/carbon/user)
if(src.loc == user)
if(!armed)
if(user.get_item_by_slot(SLOT_BACK) == src)
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index 289b43a669..a5ed45dd48 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -84,6 +84,11 @@
. = ..()
. += "[get_ammo(0,0)] of those are live rounds."
+/obj/item/gun/ballistic/revolver/syndicate
+ unique_reskin = list("Default" = "revolver",
+ "Silver" = "russianrevolver",
+ "Robust" = "revolvercit")
+
/obj/item/gun/ballistic/revolver/detective
name = "\improper .38 Mars Special"
desc = "A cheap Martian knock-off of a classic law enforcement firearm. Uses .38-special rounds."
@@ -486,4 +491,4 @@
for(var/i = 0, i < ratio, i++)
var/mutable_appearance/charge_bar = mutable_appearance(icon, "[initial(icon_state)]_charge", color = batt_color)
charge_bar.pixel_x = i
- . += charge_bar
\ No newline at end of file
+ . += charge_bar
diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm
index 5cdd773894..1f66cfdf8a 100644
--- a/code/modules/projectiles/guns/ballistic/toy.dm
+++ b/code/modules/projectiles/guns/ballistic/toy.dm
@@ -56,6 +56,7 @@
item_flags = NONE
casing_ejector = FALSE
can_suppress = FALSE
+ weapon_weight = WEAPON_MEDIUM
/obj/item/gun/ballistic/shotgun/toy/process_chamber(mob/living/user, empty_chamber = 0)
..()
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 72ac9620b5..8e61221cc8 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -44,6 +44,12 @@
ammo_type = list(/obj/item/ammo_casing/energy/lasergun/old)
ammo_x_offset = 3
+/obj/item/gun/energy/laser/hellgun
+ name ="hellfire laser gun"
+ desc = "A relic of a weapon, built before NT began installing regulators on its laser weaponry. This pattern of laser gun became infamous for the gruesome burn wounds it caused, and was quietly discontinued once it began to affect NT's reputation."
+ icon_state = "hellgun"
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/hellfire)
+
/obj/item/gun/energy/laser/captain
name = "antique laser gun"
icon_state = "caplaser"
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 6489920b98..20e847326e 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -125,7 +125,7 @@
flags_1 = CONDUCT_1
attack_verb = list("attacked", "slashed", "cut", "sliced")
force = 12
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
inaccuracy_modifier = 0.25
can_charge = 0
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index d700db817c..6c75ac2d4d 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -24,7 +24,7 @@
ammo_x_offset = 2
// Not enough guns have altfire systems like this yet for this to be a universal framework.
var/last_altfire = 0
- var/altfire_delay = 15
+ var/altfire_delay = CLICK_CD_RANGE
/obj/item/gun/energy/e_gun/advtaser/altafterattack(atom/target, mob/user, proximity_flag, params)
. = TRUE
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index b23b059d89..6ebdc5e7b8 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -83,7 +83,7 @@
force = 20
armour_penetration = 75
block_chance = 50
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
max_charges = 4
/obj/item/gun/magic/staff/spellblade/Initialize()
diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm
index bcb074023f..fd09aa7f9d 100644
--- a/code/modules/projectiles/guns/misc/beam_rifle.dm
+++ b/code/modules/projectiles/guns/misc/beam_rifle.dm
@@ -29,6 +29,8 @@
ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan)
cell_type = /obj/item/stock_parts/cell/beam_rifle
canMouseDown = TRUE
+ can_turret = FALSE
+ can_circuit = FALSE
//Cit changes: beam rifle stats.
slowdown = 1
item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND | NEEDS_PERMIT
@@ -418,10 +420,10 @@
var/wall_devastate = 0
var/aoe_structure_range = 0
var/aoe_structure_damage = 0
- var/aoe_fire_range = 0
- var/aoe_fire_chance = 0
- var/aoe_mob_range = 0
- var/aoe_mob_damage = 0
+ var/aoe_fire_range = 2
+ var/aoe_fire_chance = 100
+ var/aoe_mob_range = 2
+ var/aoe_mob_damage = 30
var/impact_structure_damage = 0
var/impact_direct_damage = 0
var/turf/cached
diff --git a/code/modules/projectiles/guns/misc/medbeam.dm b/code/modules/projectiles/guns/misc/medbeam.dm
index e841422893..6864dad33e 100644
--- a/code/modules/projectiles/guns/misc/medbeam.dm
+++ b/code/modules/projectiles/guns/misc/medbeam.dm
@@ -47,7 +47,7 @@
if(current_target)
LoseTarget()
- if(!isliving(target))
+ if(!isliving(target) || (user == target))
return
current_target = target
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 7c988ca730..43384280d4 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -49,7 +49,7 @@
var/pixel_move_interrupted = FALSE
/// Pixels moved per second.
- var/pixels_per_second = TILES_TO_PIXELS(12.5)
+ var/pixels_per_second = TILES_TO_PIXELS(17.5)
/// The number of pixels we increment by. THIS IS NOT SPEED, DO NOT TOUCH THIS UNLESS YOU KNOW WHAT YOU ARE DOING. In general, lower values means more linetrace accuracy up to a point at cost of performance.
var/pixel_increment_amount
@@ -149,15 +149,25 @@
var/temporary_unstoppable_movement = FALSE
- ///If defined, on hit we create an item of this type then call hitby() on the hit target with this
+ ///If defined, on hit we create an item of this type then call hitby() on the hit target with this, mainly used for embedding items (bullets) in targets
var/shrapnel_type
///If TRUE, hit mobs even if they're on the floor and not our target
var/hit_stunned_targets = FALSE
+ wound_bonus = CANT_WOUND
+ ///How much we want to drop both wound_bonus and bare_wound_bonus (to a minimum of 0 for the latter) per tile, for falloff purposes
+ var/wound_falloff_tile
+ ///How much we want to drop the embed_chance value, if we can embed, per tile, for falloff purposes
+ var/embed_falloff_tile
+ /// For telling whether we want to roll for bone breaking or lacerations if we're bothering with wounds
+ sharpness = SHARP_NONE
+
/obj/item/projectile/Initialize()
. = ..()
permutated = list()
decayedRange = range
+ if(embedding)
+ updateEmbedding()
/**
* Artificially modified to be called at around every world.icon_size pixels of movement.
@@ -165,6 +175,11 @@
*/
/obj/item/projectile/proc/Range()
range--
+ if(wound_bonus != CANT_WOUND)
+ wound_bonus += wound_falloff_tile
+ bare_wound_bonus = max(0, bare_wound_bonus + wound_falloff_tile)
+ if(embedding)
+ embedding["embed_chance"] += embed_falloff_tile
if(range <= 0 && loc)
on_range()
@@ -619,7 +634,7 @@
pixel_x = trajectory.return_px()
pixel_y = trajectory.return_py()
else if(T != loc)
- var/safety = CEILING(pixel_increment_amount / world.icon_size, 1) * 2 + 1
+ var/safety = CEILING(pixel_increment_amount / world.icon_size, 1) * 5 + 1
while(T != loc)
if(!--safety)
CRASH("[type] took too long (allowed: [CEILING(pixel_increment_amount/world.icon_size,1)*2] moves) to get to its location.")
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 2f12f0f69b..4ba72a1935 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -14,11 +14,25 @@
ricochets_max = 50 //Honk!
ricochet_chance = 80
is_reflectable = TRUE
+ wound_bonus = -20
+ bare_wound_bonus = 10
/obj/item/projectile/beam/laser
tracer_type = /obj/effect/projectile/tracer/laser
muzzle_type = /obj/effect/projectile/muzzle/laser
impact_type = /obj/effect/projectile/impact/laser
+ wound_bonus = -30
+ bare_wound_bonus = 40
+
+//overclocked laser, does a bit more damage but has much higher wound power (-0 vs -20)
+/obj/item/projectile/beam/laser/hellfire
+ name = "hellfire laser"
+ wound_bonus = 0
+ damage = 25
+
+/obj/item/projectile/beam/laser/hellfire/Initialize()
+ . = ..()
+ transform *= 2
/obj/item/projectile/beam/laser/heavylaser
name = "heavy laser"
@@ -90,6 +104,7 @@
tracer_type = /obj/effect/projectile/tracer/pulse
muzzle_type = /obj/effect/projectile/muzzle/pulse
impact_type = /obj/effect/projectile/impact/pulse
+ wound_bonus = 10
/obj/item/projectile/beam/pulse/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -116,6 +131,8 @@
damage = 30
impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
light_color = LIGHT_COLOR_GREEN
+ wound_bonus = -40
+ bare_wound_bonus = 70
/obj/item/projectile/beam/emitter/singularity_pull()
return
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 6d03012315..b408957aa7 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -8,3 +8,12 @@
flag = "bullet"
hitsound_wall = "ricochet"
impact_effect_type = /obj/effect/temp_visual/impact_effect
+ sharpness = SHARP_POINTY
+ shrapnel_type = /obj/item/shrapnel/bullet
+ embedding = list(embed_chance=15, fall_chance=2, jostle_chance=0, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=3, rip_time=10)
+ wound_falloff_tile = -5
+ embed_falloff_tile = -5
+
+/obj/item/projectile/bullet/smite
+ name = "divine retribution"
+ damage = 10
diff --git a/code/modules/projectiles/projectile/bullets/lmg.dm b/code/modules/projectiles/projectile/bullets/lmg.dm
index 2ea1fe7c9a..e3eff6dcb0 100644
--- a/code/modules/projectiles/projectile/bullets/lmg.dm
+++ b/code/modules/projectiles/projectile/bullets/lmg.dm
@@ -25,8 +25,10 @@
/obj/item/projectile/bullet/mm195x129
name = "1.95x129mm bullet"
- damage = 45
+ damage = 40
armour_penetration = 5
+ wound_bonus = -50
+ wound_falloff_tile = 0
/obj/item/projectile/bullet/mm195x129_ap
name = "1.95x129mm armor-piercing bullet"
@@ -35,8 +37,12 @@
/obj/item/projectile/bullet/mm195x129_hp
name = "1.95x129mm hollow-point bullet"
- damage = 60
+ damage = 50
armour_penetration = -60
+ sharpness = SHARP_EDGED
+ wound_bonus = -40
+ bare_wound_bonus = 30
+ wound_falloff_tile = -8
/obj/item/projectile/bullet/incendiary/mm195x129
name = "1.95x129mm incendiary bullet"
diff --git a/code/modules/projectiles/projectile/bullets/pistol.dm b/code/modules/projectiles/projectile/bullets/pistol.dm
index 38c9c9f7d9..23a749415c 100644
--- a/code/modules/projectiles/projectile/bullets/pistol.dm
+++ b/code/modules/projectiles/projectile/bullets/pistol.dm
@@ -3,11 +3,13 @@
/obj/item/projectile/bullet/c9mm
name = "9mm bullet"
damage = 20
+ embedding = list(embed_chance=15, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
/obj/item/projectile/bullet/c9mm_ap
name = "9mm armor-piercing bullet"
damage = 15
armour_penetration = 40
+ embedding = null
/obj/item/projectile/bullet/incendiary/c9mm
name = "9mm incendiary bullet"
diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm
index 5643804ac1..95d43ba1ce 100644
--- a/code/modules/projectiles/projectile/bullets/revolver.dm
+++ b/code/modules/projectiles/projectile/bullets/revolver.dm
@@ -19,6 +19,9 @@
ricochet_chance = 50
ricochet_auto_aim_angle = 10
ricochet_auto_aim_range = 3
+ wound_bonus = -20
+ bare_wound_bonus = 10
+ embedding = list(embed_chance=15, fall_chance=2, jostle_chance=2, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=5, rip_time=10)
/obj/item/projectile/bullet/c38/match
name = ".38 Match bullet"
@@ -29,6 +32,7 @@
ricochet_incidence_leeway = 50
ricochet_decay_chance = 1
ricochet_decay_damage = 1
+ wound_bonus = 0
/obj/item/projectile/bullet/c38/match/bouncy
name = ".38 Rubber bullet"
@@ -40,13 +44,21 @@
ricochet_chance = 130
ricochet_decay_damage = 0.8
shrapnel_type = NONE
+ sharpness = SHARP_NONE
+ embedding = null
+// premium .38 ammo from cargo, weak against armor, lower base damage, but excellent at embedding and causing slice wounds at close range
/obj/item/projectile/bullet/c38/dumdum
name = ".38 DumDum bullet"
damage = 15
armour_penetration = -30
ricochets_max = 0
- shrapnel_type = /obj/item/shrapnel/bullet/c38/dumdum
+ sharpness = SHARP_EDGED
+ wound_bonus = 20
+ bare_wound_bonus = 20
+ embedding = list(embed_chance=75, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
+ wound_falloff_tile = -5
+ embed_falloff_tile = -15
/obj/item/projectile/bullet/c38/rubber
name = ".38 rubber bullet"
@@ -99,6 +111,7 @@
/obj/item/projectile/bullet/a357
name = ".357 bullet"
damage = 60
+ wound_bonus = -70
/obj/item/projectile/bullet/a357/ap
name = ".357 armor-piercing bullet"
diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm
index ae1611cb00..ce30f5e787 100644
--- a/code/modules/projectiles/projectile/bullets/rifle.dm
+++ b/code/modules/projectiles/projectile/bullets/rifle.dm
@@ -3,12 +3,15 @@
/obj/item/projectile/bullet/a556
name = "5.56mm bullet"
damage = 35
+ wound_bonus = -40
// 7.62 (Nagant Rifle)
/obj/item/projectile/bullet/a762
name = "7.62 bullet"
damage = 60
+ wound_bonus = -35
+ wound_falloff_tile = 0
/obj/item/projectile/bullet/a762_enchanted
name = "enchanted 7.62 bullet"
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index 264df22c76..69f976d213 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -1,11 +1,26 @@
/obj/item/projectile/bullet/shotgun_slug
name = "12g shotgun slug"
- damage = 60
+ damage = 50
+ sharpness = SHARP_POINTY
+ wound_bonus = 0
+
+/obj/item/projectile/bullet/shotgun_slug/executioner
+ name = "executioner slug" // admin only, can dismember limbs
+ sharpness = SHARP_EDGED
+ wound_bonus = 80
+
+/obj/item/projectile/bullet/shotgun_slug/pulverizer
+ name = "pulverizer slug" // admin only, can crush bones
+ sharpness = SHARP_NONE
+ wound_bonus = 80
/obj/item/projectile/bullet/shotgun_beanbag
name = "beanbag slug"
- damage = 5
+ damage = 10
stamina = 70
+ wound_bonus = 20
+ sharpness = SHARP_NONE
+ embedding = null
/obj/item/projectile/bullet/incendiary/shotgun
name = "incendiary slug"
@@ -71,17 +86,22 @@
return BULLET_ACT_HIT
/obj/item/projectile/bullet/pellet
- var/tile_dropoff = 0.75
+ var/tile_dropoff = 0.45
var/tile_dropoff_s = 1.25
/obj/item/projectile/bullet/pellet/shotgun_buckshot
name = "buckshot pellet"
- damage = 12.5
+ damage = 7.5
+ wound_bonus = 5
+ bare_wound_bonus = 5
+ wound_falloff_tile = -2.5 // low damage + additional dropoff will already curb wounding potential anything past point blank
/obj/item/projectile/bullet/pellet/shotgun_rubbershot
name = "rubbershot pellet"
damage = 2
stamina = 15
+ sharpness = SHARP_NONE
+ embedding = null
/obj/item/projectile/bullet/pellet/Range()
..()
@@ -93,8 +113,10 @@
qdel(src)
/obj/item/projectile/bullet/pellet/shotgun_improvised
- tile_dropoff = 0.55 //Come on it does 6 damage don't be like that.
+ tile_dropoff = 0.35 //Come on it does 6 damage don't be like that.
damage = 6
+ wound_bonus = 0
+ bare_wound_bonus = 7.5
/obj/item/projectile/bullet/pellet/shotgun_improvised/Initialize()
. = ..()
diff --git a/code/modules/projectiles/projectile/bullets/smg.dm b/code/modules/projectiles/projectile/bullets/smg.dm
index eb4c8e9776..5c9d5b92a3 100644
--- a/code/modules/projectiles/projectile/bullets/smg.dm
+++ b/code/modules/projectiles/projectile/bullets/smg.dm
@@ -3,6 +3,8 @@
/obj/item/projectile/bullet/c45
name = ".45 bullet"
damage = 30
+ wound_bonus = -10
+ wound_falloff_tile = -10
/obj/item/projectile/bullet/c45_cleaning
name = ".45 bullet"
@@ -51,11 +53,15 @@
/obj/item/projectile/bullet/c46x30mm
name = "4.6x30mm bullet"
damage = 15
+ wound_bonus = -5
+ bare_wound_bonus = 5
+ embed_falloff_tile = -4
/obj/item/projectile/bullet/c46x30mm_ap
name = "4.6x30mm armor-piercing bullet"
damage = 12.5
armour_penetration = 40
+ embedding = null
/obj/item/projectile/bullet/incendiary/c46x30mm
name = "4.6x30mm incendiary bullet"
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index da33f935da..db16a10d1d 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -177,11 +177,10 @@
beaker = null
update_icon()
-/obj/machinery/chem_dispenser/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/chem_dispenser/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "ChemDispenser", name, 565, 550, master_ui, state)
+ ui = new(user, src, "ChemDispenser", name)
if(user.hallucinating())
ui.set_autoupdate(FALSE) //to not ruin the immersion by constantly changing the fake chemicals
ui.open()
@@ -216,7 +215,7 @@
data["beakerTransferAmounts"] = null
data["beakerCurrentpH"] = null
- var/list/chemicals = list()
+ var/chemicals[0]
var/is_hallucinating = FALSE
if(user.hallucinating())
is_hallucinating = TRUE
@@ -275,7 +274,7 @@
. = TRUE
if("eject")
replace_beaker(usr)
- . = TRUE //no afterattack
+ . = TRUE
if("dispense_recipe")
if(!is_operational() || QDELETED(cell))
return
@@ -326,9 +325,9 @@
for(var/reagent in recording_recipe)
var/reagent_id = GLOB.name2reagent[translate_legacy_chem_id(reagent)]
if(!dispensable_reagents.Find(reagent_id))
- visible_message("[src] buzzes.", "You hear a faint buzz.")
+ visible_message("[src] buzzes.", "You hear a faint buzz.")
to_chat(usr, "[src] cannot find [reagent]!")
- playsound(src, 'sound/machines/buzz-two.ogg', 50, 1)
+ playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE)
return
saved_recipes[name] = recording_recipe
recording_recipe = null
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 5697a2385c..28f0b2366a 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -7,6 +7,7 @@
idle_power_usage = 40
resistance_flags = FIRE_PROOF | ACID_PROOF
circuit = /obj/item/circuitboard/machine/chem_heater
+
var/obj/item/reagent_containers/beaker = null
var/target_temperature = 300
var/heater_coefficient = 0.1
@@ -30,22 +31,20 @@
/obj/machinery/chem_heater/AltClick(mob/living/user)
. = ..()
- if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
replace_beaker(user)
- return TRUE
/obj/machinery/chem_heater/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
+ if(!user)
+ return FALSE
if(beaker)
- beaker.forceMove(drop_location())
- if(user && Adjacent(user) && user.can_hold_items())
- user.put_in_hands(beaker)
+ user.put_in_hands(beaker)
+ beaker = null
if(new_beaker)
beaker = new_beaker
- else
- beaker = null
- update_icon()
- return TRUE
+ update_icon()
+ return TRUE
/obj/machinery/chem_heater/RefreshParts()
heater_coefficient = 0.1
@@ -63,6 +62,7 @@
return
if(on)
if(beaker && beaker.reagents.total_volume)
+ //keep constant with the chemical acclimator please
beaker.reagents.adjust_thermal_energy((target_temperature - beaker.reagents.chem_temp) * heater_coefficient * SPECIFIC_HEAT_DEFAULT * beaker.reagents.total_volume)
beaker.reagents.handle_reactions()
@@ -83,27 +83,16 @@
updateUsrDialog()
update_icon()
return
-
- if(beaker)
- if(istype(I, /obj/item/reagent_containers/dropper))
- var/obj/item/reagent_containers/dropper/D = I
- D.afterattack(beaker, user, 1)
-
- if(istype(I, /obj/item/reagent_containers/syringe))
- var/obj/item/reagent_containers/syringe/S = I
- S.afterattack(beaker, user, 1)
-
return ..()
/obj/machinery/chem_heater/on_deconstruction()
replace_beaker()
return ..()
-/obj/machinery/chem_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.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/chem_heater/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "ChemHeater", name, 300, 400, master_ui, state)
+ ui = new(user, src, "ChemHeater", name)
ui.open()
/obj/machinery/chem_heater/ui_data()
@@ -140,14 +129,7 @@
. = TRUE
if("temperature")
var/target = params["target"]
- var/adjust = text2num(params["adjust"])
- if(target == "input")
- target = input("New target temperature:", name, target_temperature) as num|null
- if(!isnull(target) && !..())
- . = TRUE
- else if(adjust)
- target = target_temperature + adjust
- else if(text2num(target) != null)
+ if(text2num(target) != null)
target = text2num(target)
. = TRUE
if(.)
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index dd9dd7c0bf..207325e1b3 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -12,6 +12,7 @@
idle_power_usage = 20
resistance_flags = FIRE_PROOF | ACID_PROOF
circuit = /obj/item/circuitboard/machine/chem_master
+
var/obj/item/reagent_containers/beaker = null
var/obj/item/storage/pill_bottle/bottle = null
var/mode = 1
@@ -154,19 +155,15 @@
bottle?.forceMove(A)
return ..()
-//Insert our custom spritesheet css link into the html
-/obj/machinery/chem_master/ui_base_html(html)
- var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills)
- . = replacetext(html, "", assets.css_tag())
+/obj/machinery/chem_master/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/simple/pills),
+ )
-/obj/machinery/chem_master/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/chem_master/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills)
- assets.send(user)
-
- ui = new(user, src, ui_key, "ChemMaster", name, 520, 550, master_ui, state)
+ ui = new(user, src, "ChemMaster", name)
ui.open()
/obj/machinery/chem_master/ui_data(mob/user)
@@ -183,8 +180,8 @@
data["isPillBottleLoaded"] = bottle ? 1 : 0
if(bottle)
var/datum/component/storage/STRB = bottle.GetComponent(/datum/component/storage)
- data["pillBotContent"] = bottle.contents.len
- data["pillBotMaxContent"] = STRB.max_items
+ data["pillBottleCurrentAmount"] = bottle.contents.len
+ data["pillBottleMaxAmount"] = STRB.max_items
var/beakerContents[0]
if(beaker)
@@ -206,213 +203,219 @@
if(..())
return
- switch(action)
- if("eject")
- replace_beaker(usr)
- . = TRUE
+ if(action == "eject")
+ replace_beaker(usr)
+ return TRUE
- if("ejectPillBottle")
- replace_pillbottle(usr)
- . = TRUE
-
- if("transfer")
- if(!beaker)
- return FALSE
- var/reagent = GLOB.name2reagent[params["id"]]
- var/amount = text2num(params["amount"])
- var/to_container = params["to"]
- // Custom amount
- if (amount == -1)
- amount = text2num(input(
- "Enter the amount you want to transfer:",
- name, ""))
- if (amount == null || amount <= 0)
- return FALSE
- if (to_container == "buffer")
- end_fermi_reaction()
- beaker.reagents.trans_id_to(src, reagent, amount)
- return TRUE
- if (to_container == "beaker" && mode)
- end_fermi_reaction()
- reagents.trans_id_to(beaker, reagent, amount)
- return TRUE
- if (to_container == "beaker" && !mode)
- end_fermi_reaction()
- reagents.remove_reagent(reagent, amount)
- return TRUE
+ if(action == "ejectPillBottle")
+ if(!bottle)
return FALSE
+ bottle.forceMove(drop_location())
+ adjust_item_drop_location(bottle)
+ bottle = null
+ return TRUE
- if("toggleMode")
- mode = !mode
- . = TRUE
+ if(action == "transfer")
+ if(!beaker)
+ return FALSE
+ var/reagent = GLOB.name2reagent[params["id"]]
+ var/amount = text2num(params["amount"])
+ var/to_container = params["to"]
+ // Custom amount
+ if (amount == -1)
+ amount = text2num(input(
+ "Enter the amount you want to transfer:",
+ name, ""))
+ if (amount == null || amount <= 0)
+ return FALSE
+ if (to_container == "buffer")
+ end_fermi_reaction()
+ beaker.reagents.trans_id_to(src, reagent, amount)
+ return TRUE
+ if (to_container == "beaker" && mode)
+ end_fermi_reaction()
+ reagents.trans_id_to(beaker, reagent, amount)
+ return TRUE
+ if (to_container == "beaker" && !mode)
+ end_fermi_reaction()
+ reagents.remove_reagent(reagent, amount)
+ return TRUE
+ return FALSE
- if("pillStyle")
- var/id = text2num(params["id"])
- chosenPillStyle = id
+ if(action == "toggleMode")
+ mode = !mode
+ return TRUE
+
+ if(action == "pillStyle")
+ var/id = text2num(params["id"])
+ chosenPillStyle = id
+ return TRUE
+
+ if(action == "create")
+ if(reagents.total_volume == 0)
+ return FALSE
+ var/item_type = params["type"]
+ // Get amount of items
+ var/amount = text2num(params["amount"])
+ if(amount == null)
+ amount = text2num(input(usr,
+ "Max 10. Buffer content will be split evenly.",
+ "How many to make?", 1))
+ amount = clamp(round(amount), 0, 10)
+ if (amount <= 0)
+ return FALSE
+ // Get units per item
+ var/vol_each = text2num(params["volume"])
+ var/vol_each_text = params["volume"]
+ var/vol_each_max = reagents.total_volume / amount
+ if (item_type == "pill")
+ vol_each_max = min(50, vol_each_max)
+ else if (item_type == "patch")
+ vol_each_max = min(40, vol_each_max)
+ else if (item_type == "bottle")
+ vol_each_max = min(30, vol_each_max)
+ else if (item_type == "condimentPack")
+ vol_each_max = min(10, vol_each_max)
+ else if (item_type == "condimentBottle")
+ vol_each_max = min(50, vol_each_max)
+ else if (item_type == "hypoVial")
+ vol_each_max = min(60, vol_each_max)
+ else if (item_type == "smartDart")
+ vol_each_max = min(20, vol_each_max)
+ else
+ return FALSE
+ if(vol_each_text == "auto")
+ vol_each = vol_each_max
+ if(vol_each == null)
+ vol_each = text2num(input(usr,
+ "Maximum [vol_each_max] units per item.",
+ "How many units to fill?",
+ vol_each_max))
+ vol_each = clamp(vol_each, 0, vol_each_max)
+ if(vol_each <= 0)
+ return FALSE
+ // Get item name
+ var/name = params["name"]
+ var/name_has_units = item_type == "pill" || item_type == "patch"
+ if(!name)
+ var/name_default = reagents.get_master_reagent_name()
+ if (name_has_units)
+ name_default += " ([vol_each]u)"
+ name = stripped_input(usr,
+ "Name:",
+ "Give it a name!",
+ name_default,
+ MAX_NAME_LEN)
+ if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
+ return FALSE
+ // Start filling
+ if(item_type == "pill")
+ var/obj/item/reagent_containers/pill/P
+ var/target_loc = drop_location()
+ var/drop_threshold = INFINITY
+ if(bottle)
+ var/datum/component/storage/STRB = bottle.GetComponent(
+ /datum/component/storage)
+ if(STRB)
+ drop_threshold = STRB.max_items - bottle.contents.len
+ for(var/i = 0; i < amount; i++)
+ if(i < drop_threshold)
+ P = new/obj/item/reagent_containers/pill(target_loc)
+ else
+ P = new/obj/item/reagent_containers/pill(drop_location())
+ P.name = trim("[name] pill")
+ if(chosenPillStyle == RANDOM_PILL_STYLE)
+ P.icon_state ="pill[rand(1,21)]"
+ else
+ P.icon_state = "pill[chosenPillStyle]"
+ if(P.icon_state == "pill4")
+ P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
+ adjust_item_drop_location(P)
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ return TRUE
+ if(item_type == "patch")
+ var/obj/item/reagent_containers/pill/patch/P
+ for(var/i = 0; i < amount; i++)
+ P = new/obj/item/reagent_containers/pill/patch(drop_location())
+ P.name = trim("[name] patch")
+ adjust_item_drop_location(P)
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ return TRUE
+ if(item_type == "bottle")
+ var/obj/item/reagent_containers/glass/bottle/P
+ for(var/i = 0; i < amount; i++)
+ P = new/obj/item/reagent_containers/glass/bottle(drop_location())
+ P.name = trim("[name] bottle")
+ adjust_item_drop_location(P)
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ return TRUE
+ if(item_type == "condimentPack")
+ var/obj/item/reagent_containers/food/condiment/pack/P
+ for(var/i = 0; i < amount; i++)
+ P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
+ P.originalname = name
+ P.name = trim("[name] pack")
+ P.desc = "A small condiment pack. The label says it contains [name]."
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ return TRUE
+ if(item_type == "condimentBottle")
+ var/obj/item/reagent_containers/food/condiment/P
+ for(var/i = 0; i < amount; i++)
+ P = new/obj/item/reagent_containers/food/condiment(drop_location())
+ P.originalname = name
+ P.name = trim("[name] bottle")
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ return TRUE
+ if(item_type == "hypoVial")
+ var/obj/item/reagent_containers/glass/bottle/vial/small/P
+ for(var/i = 0; i < amount; i++)
+ P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
+ P.name = trim("[name] hypovial")
+ adjust_item_drop_location(P)
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ return TRUE
+ if(item_type == "smartDart")
+ var/obj/item/reagent_containers/syringe/dart/P
+ for(var/i = 0; i < amount; i++)
+ P = new /obj/item/reagent_containers/syringe/dart(drop_location())
+ P.name = trim("[name] SmartDart")
+ adjust_item_drop_location(P)
+ reagents.trans_to(P, vol_each)//, transfered_by = usr)
+ P.mode=!mode
+ P.update_icon()
+ return TRUE
+ return FALSE
+
+ if(action == "analyze")
+ // var/datum/reagent/R = GLOB.name2reagent[params["id"]]
+ var/reagent = GLOB.name2reagent[params["id"]]
+ var/datum/reagent/R = GLOB.chemical_reagents_list[reagent]
+ if(R)
+ var/state = "Unknown"
+ if(initial(R.reagent_state) == 1)
+ state = "Solid"
+ else if(initial(R.reagent_state) == 2)
+ state = "Liquid"
+ else if(initial(R.reagent_state) == 3)
+ state = "Gas"
+ var/const/P = 3 //The number of seconds between life ticks
+ var/T = initial(R.metabolization_rate) * (60 / P)
+ if(istype(R, /datum/reagent/fermi))
+ fermianalyze = TRUE
+ var/datum/chemical_reaction/Rcr = get_chemical_reaction(reagent)
+ var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
+ analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
+ else
+ fermianalyze = FALSE
+ analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
+ screen = "analyze"
return TRUE
- if("create")
- if(reagents.total_volume == 0)
- return FALSE
- var/item_type = params["type"]
- // Get amount of items
- var/amount = text2num(params["amount"])
- if(amount == null)
- amount = text2num(input(usr,
- "Max 20. Buffer content will be split evenly.",
- "How many to make?", 1))
- amount = clamp(round(amount), 0, 20)
- if (amount <= 0)
- return FALSE
- // Get units per item
- var/vol_each = text2num(params["volume"])
- var/vol_each_text = params["volume"]
- var/vol_each_max = reagents.total_volume / amount
- if (item_type == "pill")
- vol_each_max = min(50, vol_each_max)
- else if (item_type == "patch")
- vol_each_max = min(40, vol_each_max)
- else if (item_type == "bottle")
- vol_each_max = min(30, vol_each_max)
- else if (item_type == "condimentPack")
- vol_each_max = min(10, vol_each_max)
- else if (item_type == "condimentBottle")
- vol_each_max = min(50, vol_each_max)
- else if (item_type == "hypoVial")
- vol_each_max = min(60, vol_each_max)
- else if (item_type == "smartDart")
- vol_each_max = min(20, vol_each_max)
- else
- return FALSE
- if(vol_each_text == "auto")
- vol_each = vol_each_max
- if(vol_each == null)
- vol_each = text2num(input(usr,
- "Maximum [vol_each_max] units per item.",
- "How many units to fill?",
- vol_each_max))
- vol_each = clamp(vol_each, 0, vol_each_max)
- if(vol_each <= 0)
- return FALSE
- // Get item name
- var/name = params["name"]
- var/name_has_units = item_type == "pill" || item_type == "patch"
- if(!name)
- var/name_default = reagents.get_master_reagent_name()
- if (name_has_units)
- name_default += " ([vol_each]u)"
- name = stripped_input(usr,
- "Name:",
- "Give it a name!",
- name_default,
- MAX_NAME_LEN)
- if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
- return FALSE
- // Start filling
- if(item_type == "pill")
- var/obj/item/reagent_containers/pill/P
- var/target_loc = drop_location()
- var/drop_threshold = INFINITY
- if(bottle)
- var/datum/component/storage/STRB = bottle.GetComponent(
- /datum/component/storage)
- if(STRB)
- drop_threshold = STRB.max_items - bottle.contents.len
- for(var/i = 0; i < amount; i++)
- if(i < drop_threshold)
- P = new/obj/item/reagent_containers/pill(target_loc)
- else
- P = new/obj/item/reagent_containers/pill(drop_location())
- P.name = trim("[name] pill")
- if(chosenPillStyle == RANDOM_PILL_STYLE)
- P.icon_state ="pill[rand(1,21)]"
- else
- P.icon_state = "pill[chosenPillStyle]"
- if(P.icon_state == "pill4")
- P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
- adjust_item_drop_location(P)
- reagents.trans_to(P, vol_each)
- return TRUE
- if(item_type == "patch")
- var/obj/item/reagent_containers/pill/patch/P
- for(var/i = 0; i < amount; i++)
- P = new/obj/item/reagent_containers/pill/patch(drop_location())
- P.name = trim("[name] patch")
- adjust_item_drop_location(P)
- reagents.trans_to(P, vol_each)
- return TRUE
- if(item_type == "bottle")
- var/obj/item/reagent_containers/glass/bottle/P
- for(var/i = 0; i < amount; i++)
- P = new/obj/item/reagent_containers/glass/bottle(drop_location())
- P.name = trim("[name] bottle")
- adjust_item_drop_location(P)
- reagents.trans_to(P, vol_each)
- return TRUE
- if(item_type == "condimentPack")
- var/obj/item/reagent_containers/food/condiment/pack/P
- for(var/i = 0; i < amount; i++)
- P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
- P.originalname = name
- P.name = trim("[name] pack")
- P.desc = "A small condiment pack. The label says it contains [name]."
- reagents.trans_to(P, vol_each)
- return TRUE
- if(item_type == "condimentBottle")
- var/obj/item/reagent_containers/food/condiment/P
- for(var/i = 0; i < amount; i++)
- P = new/obj/item/reagent_containers/food/condiment(drop_location())
- P.originalname = name
- P.name = trim("[name] bottle")
- reagents.trans_to(P, vol_each)
- return TRUE
- if(item_type == "hypoVial")
- var/obj/item/reagent_containers/glass/bottle/vial/small/P
- for(var/i = 0; i < amount; i++)
- P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
- P.name = trim("[name] hypovial")
- adjust_item_drop_location(P)
- reagents.trans_to(P, vol_each)
- return TRUE
- if(item_type == "smartDart")
- var/obj/item/reagent_containers/syringe/dart/P
- for(var/i = 0; i < amount; i++)
- P = new /obj/item/reagent_containers/syringe/dart(drop_location())
- P.name = trim("[name] SmartDart")
- adjust_item_drop_location(P)
- reagents.trans_to(P, vol_each)
- P.mode=!mode
- P.update_icon()
- return TRUE
- return FALSE
+ if(action == "goScreen")
+ screen = params["screen"]
+ return TRUE
- if("analyze")
- var/reagent = GLOB.name2reagent[params["id"]]
- var/datum/reagent/R = GLOB.chemical_reagents_list[reagent]
- if(R)
- var/state = "Unknown"
- if(initial(R.reagent_state) == 1)
- state = "Solid"
- else if(initial(R.reagent_state) == 2)
- state = "Liquid"
- else if(initial(R.reagent_state) == 3)
- state = "Gas"
- var/const/P = 3 //The number of seconds between life ticks
- var/T = initial(R.metabolization_rate) * (60 / P)
- if(istype(R, /datum/reagent/fermi))
- fermianalyze = TRUE
- var/datum/chemical_reaction/Rcr = get_chemical_reaction(reagent)
- var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
- analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
- else
- fermianalyze = FALSE
- analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
- screen = "analyze"
- return TRUE
-
- if("goScreen")
- screen = params["screen"]
- . = TRUE
+ return FALSE
diff --git a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm
index 66c2616972..489f9dd179 100644
--- a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm
@@ -12,11 +12,10 @@
"tricord" = /datum/reagent/medicine/tricordrazine
)
-/obj/machinery/chem_dispenser/chem_synthesizer/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/chem_dispenser/chem_synthesizer/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "ChemDebugSynthesizer", name, 390, 330, master_ui, state)
+ ui = new(user, src, "ChemDebugSynthesizer", name)
ui.open()
/obj/machinery/chem_dispenser/chem_synthesizer/ui_act(action, params)
@@ -31,7 +30,11 @@
beaker = null
. = TRUE
if("input")
- var/input_reagent = replacetext(lowertext(input("Enter the name of any reagent", "Input") as text), " ", "") //95% of the time, the reagent types is a lowercase, no spaces / underscored version of the name
+ var/input_reagent = replacetext(lowertext(input("Enter the name of any reagent", "Input") as text|null), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name
+
+ if (isnull(input_reagent))
+ return
+
if(shortcuts[input_reagent])
input_reagent = shortcuts[input_reagent]
else
@@ -51,7 +54,7 @@
beaker = new /obj/item/reagent_containers/glass/beaker/bluespace(src)
visible_message("[src] dispenses a bluespace beaker.")
if("amount")
- var/input = input("Units to dispense", "Units") as num|null
+ var/input = text2num(params["amount"])
if(input)
amount = input
update_icon()
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index 4a4bbdb546..36e102be72 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -7,10 +7,11 @@
density = TRUE
icon = 'icons/obj/chemical.dmi'
icon_state = "mixer0"
- circuit = /obj/item/circuitboard/computer/pandemic
use_power = TRUE
idle_power_usage = 20
resistance_flags = ACID_PROOF
+ circuit = /obj/item/circuitboard/computer/pandemic
+
var/wait
var/datum/symptom/selected_symptom
var/obj/item/reagent_containers/beaker
@@ -23,11 +24,27 @@
QDEL_NULL(beaker)
return ..()
-/obj/machinery/computer/pandemic/handle_atom_del(atom/A)
+/obj/machinery/computer/pandemic/examine(mob/user)
. = ..()
+ if(beaker)
+ var/is_close
+ if(Adjacent(user)) //don't reveal exactly what's inside unless they're close enough to see the UI anyway.
+ . += "It contains \a [beaker]."
+ is_close = TRUE
+ else
+ . += "It has a beaker inside it."
+ . += "Alt-click to eject [is_close ? beaker : "the beaker"]."
+
+/obj/machinery/computer/pandemic/AltClick(mob/user)
+ . = ..()
+ if(user.canUseTopic(src, BE_CLOSE))
+ eject_beaker()
+
+/obj/machinery/computer/pandemic/handle_atom_del(atom/A)
if(A == beaker)
beaker = null
update_icon()
+ return ..()
/obj/machinery/computer/pandemic/proc/get_by_index(thing, index)
if(!beaker || !beaker.reagents)
@@ -107,7 +124,7 @@
/obj/machinery/computer/pandemic/proc/reset_replicator_cooldown()
wait = FALSE
update_icon()
- playsound(loc, 'sound/machines/ping.ogg', 30, 1)
+ playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
/obj/machinery/computer/pandemic/update_icon_state()
if(stat & BROKEN)
@@ -117,13 +134,19 @@
/obj/machinery/computer/pandemic/update_overlays()
. = ..()
- if(!(stat & BROKEN) && wait)
+ if(wait)
. += "waitlight"
-/obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/pandemic/proc/eject_beaker()
+ if(beaker)
+ beaker.forceMove(drop_location())
+ beaker = null
+ update_icon()
+
+/obj/machinery/computer/pandemic/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Pandemic", name, 520, 550, master_ui, state)
+ ui = new(user, src, "Pandemic", name)
ui.open()
/obj/machinery/computer/pandemic/ui_data(mob/user)
@@ -135,9 +158,9 @@
var/datum/reagent/blood/B = locate() in beaker.reagents.reagent_list
if(B)
data["has_blood"] = TRUE
- data[/datum/reagent/blood] = list()
- data[/datum/reagent/blood]["dna"] = B.data["blood_DNA"] || "none"
- data[/datum/reagent/blood]["type"] = B.data["blood_type"] || "none"
+ data["blood"] = list() //wha why the fuck are we sending pathtypes to tgui frontend?
+ data["blood"]["dna"] = B.data["blood_DNA"] || "none"
+ data["blood"]["type"] = B.data["blood_type"] || "none"
data["viruses"] = get_viruses_data(B)
data["resistances"] = get_resistance_data(B)
else
@@ -153,7 +176,7 @@
return
switch(action)
if("eject_beaker")
- replace_beaker(usr)
+ eject_beaker()
. = TRUE
if("empty_beaker")
if(beaker)
@@ -162,7 +185,7 @@
if("empty_eject_beaker")
if(beaker)
beaker.reagents.clear_reagents()
- replace_beaker(usr)
+ eject_beaker()
. = TRUE
if("rename_disease")
var/id = get_virus_id_by_index(text2num(params["index"]))
@@ -170,75 +193,62 @@
if(!A.mutable)
return
if(A)
- var/new_name = sanitize_name(html_encode(trim(params["name"], 50)))
+ var/new_name = sanitize_name(html_encode(trim(params["name"], 50)))//, allow_numbers = TRUE)
if(!new_name || ..())
return
A.AssignName(new_name)
. = TRUE
if("create_culture_bottle")
+ if (wait)
+ return
var/id = get_virus_id_by_index(text2num(params["index"]))
var/datum/disease/advance/A = SSdisease.archive_diseases[id]
if(!istype(A) || !A.mutable)
to_chat(usr, "ERROR: Cannot replicate virus strain.")
return
- wait = TRUE
- addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 50)
A = A.Copy()
- var/list/data = list("blood_DNA" = "UNKNOWN DNA", "blood_type" = "SY", "viruses" = list(A))
+ var/list/data = list("viruses" = list(A))
var/obj/item/reagent_containers/glass/bottle/B = new(drop_location())
B.name = "[A.name] culture bottle"
B.desc = "A small bottle. Contains [A.agent] culture in synthblood medium."
B.reagents.add_reagent(/datum/reagent/blood/synthetics, 10, data)
+ wait = TRUE
update_icon()
var/turf/source_turf = get_turf(src)
log_virus("A culture bottle was printed for the virus [A.admin_details()] at [loc_name(source_turf)] by [key_name(usr)]")
-
+ addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 50)
. = TRUE
if("create_vaccine_bottle")
- wait = TRUE
- addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 400)
+ if (wait)
+ return
var/id = params["index"]
var/datum/disease/D = SSdisease.archive_diseases[id]
var/obj/item/reagent_containers/glass/bottle/B = new(drop_location())
B.name = "[D.name] vaccine bottle"
B.reagents.add_reagent(/datum/reagent/vaccine, 15, list(id))
-
+ wait = TRUE
update_icon()
-
+ addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 200)
. = TRUE
+
/obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container())
. = TRUE //no afterattack
if(stat & (NOPOWER|BROKEN))
return
- var/obj/item/reagent_containers/B = I
- if(!user.transferItemToLoc(B, src))
+ if(beaker)
+ to_chat(user, "A container is already loaded into [src]!")
return
- replace_beaker(user, B)
+ if(!user.transferItemToLoc(I, src))
+ return
+
+ beaker = I
to_chat(user, "You insert [I] into [src].")
+ update_icon()
else
return ..()
-/obj/machinery/computer/pandemic/AltClick(mob/living/user)
- . = ..()
- if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
- return
- replace_beaker(user)
- return TRUE
-
-/obj/machinery/computer/pandemic/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
- if(beaker)
- if(user && Adjacent(user) && user.can_hold_items())
- if(!user.put_in_hands(beaker))
- beaker.forceMove(drop_location())
- if(new_beaker)
- beaker = new_beaker
- else
- beaker = null
- update_icon()
- return TRUE
-
/obj/machinery/computer/pandemic/on_deconstruction()
- replace_beaker(usr)
+ eject_beaker()
. = ..()
diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
index cac90d1c14..a539897c9d 100644
--- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm
+++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
@@ -7,6 +7,7 @@
icon_state = "smoke0"
density = TRUE
circuit = /obj/item/circuitboard/machine/smoke_machine
+
var/efficiency = 10
var/on = FALSE
var/cooldown = 0
@@ -31,6 +32,7 @@
/obj/machinery/smoke_machine/Initialize()
. = ..()
create_reagents(REAGENTS_BASE_VOLUME)
+ // AddComponent(/datum/component/plumbing/simple_demand)
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
reagents.maximum_volume += REAGENTS_BASE_VOLUME * B.rating
@@ -81,10 +83,9 @@
add_fingerprint(user)
if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
var/obj/item/reagent_containers/RC = I
- var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this)
+ var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this) //, transfered_by = user)
if(units)
to_chat(user, "You transfer [units] units of the solution to [src].")
- log_combat(usr, src, "has added [english_list(RC.reagents.reagent_list)] to [src]")
return
if(default_unfasten_wrench(user, I, 40))
on = FALSE
@@ -100,11 +101,10 @@
reagents.clear_reagents()
return ..()
-/obj/machinery/smoke_machine/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/smoke_machine/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "SmokeMachine", name, 350, 350, master_ui, state)
+ ui = new(user, src, "SmokeMachine", name)
ui.open()
/obj/machinery/smoke_machine/ui_data(mob/user)
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 385a82baa5..4034759c72 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -1962,12 +1962,12 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/bug_spray/on_mob_life(mob/living/carbon/M)
//Bugs should not drink Bug spray.
- if(ismoth(M) || isflyperson(M))
+ if(isinsect(M) || isflyperson(M))
M.adjustToxLoss(1,0)
return ..()
/datum/reagent/consumable/ethanol/bug_spray/on_mob_add(mob/living/carbon/M)
- if(ismoth(M) || isflyperson(M))
+ if(isinsect(M) || isflyperson(M))
M.emote("scream")
return ..()
@@ -2270,25 +2270,29 @@ All effects don't start immediately, but rather get worse over time; the rate is
////////////////////
//Race-Base-Drinks//
////////////////////
+/datum/reagent/consumable/ethanol/species_drink
+ var/species_required
+ var/disgust = 25
+ boozepwr = 50
-/datum/reagent/consumable/ethanol/coldscales
+/datum/reagent/consumable/ethanol/species_drink/on_mob_life(mob/living/carbon/C)
+ if(C.dna.species && C.dna.species.species_type == species_required) //species have a species_type variable that refers to one of the drinks
+ quality = RACE_DRINK
+ else
+ C.adjust_disgust(disgust)
+
+/datum/reagent/consumable/ethanol/species_drink/coldscales
name = "Coldscales"
color = "#5AEB52" //(90, 235, 82)
description = "A cold looking drink made for people with scales."
- boozepwr = 50 //strong!
taste_description = "dead flies"
glass_icon_state = "coldscales"
glass_name = "glass of Coldscales"
glass_desc = "A soft green drink that looks inviting!"
-/datum/reagent/consumable/ethanol/coldscales/on_mob_life(mob/living/carbon/M)
- if(islizard(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "lizard"
-/datum/reagent/consumable/ethanol/oil_drum
+/datum/reagent/consumable/ethanol/species_drink/oil_drum
name = "Oil Drum"
color = "#000000" //(0, 0, 0)
description = "Industrial grade oil mixed with some ethanol to make it a drink. Somehow not known to be toxic."
@@ -2298,31 +2302,20 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Drum of oil"
glass_desc = "A gray can of booze and oil..."
-/datum/reagent/consumable/ethanol/oil_drum/on_mob_life(mob/living/carbon/M)
- if(isipcperson(M) || issynthliz(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "robot"
-/datum/reagent/consumable/ethanol/nord_king
+/datum/reagent/consumable/ethanol/species_drink/nord_king
name = "Nord King"
color = "#EB1010" //(235, 16, 16)
description = "Strong mead mixed with more honey and ethanol. Beloved by its human patrons."
- boozepwr = 50 //strong!
taste_description = "honey and red wine"
glass_icon_state = "nord_king"
glass_name = "Keg of Nord King"
glass_desc = "A dripping keg of red mead."
-/datum/reagent/consumable/ethanol/nord_king/on_mob_life(mob/living/carbon/M)
- if(ishumanbasic(M) || isdwarf(M) || isangel(M)) //Humans and angel races are rare
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "basic"
-/datum/reagent/consumable/ethanol/velvet_kiss
+/datum/reagent/consumable/ethanol/species_drink/velvet_kiss
name = "Velvet Kiss"
color = "#EB1010" //(235, 16, 16)
description = "A bloody drink mixed with wine."
@@ -2332,14 +2325,9 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Velvet Kiss"
glass_desc = "Red and white drink for the upper classes or undead."
-/datum/reagent/consumable/ethanol/velvet_kiss/on_mob_life(mob/living/carbon/M)
- if(iszombie(M) || isvampire(M) || isdullahan(M)) //Rare races!
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "undead"
-/datum/reagent/consumable/ethanol/abduction_fruit
+/datum/reagent/consumable/ethanol/species_drink/abduction_fruit
name = "Abduction Fruit"
color = "#DEFACD" //(222, 250, 205)
description = "Mixing of juices to make an alien taste."
@@ -2349,14 +2337,9 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Abduction Fruit"
glass_desc = "Mixed fruits that were never meant to be mixed..."
-/datum/reagent/consumable/ethanol/abduction_fruit/on_mob_life(mob/living/carbon/M)
- if(isabductor(M) || isxenoperson(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "alien"
-/datum/reagent/consumable/ethanol/bug_zapper
+/datum/reagent/consumable/ethanol/species_drink/bug_zapper
name = "Bug Zapper"
color = "#F5882A" //(222, 250, 205)
description = "Copper and lemon juice. Hardly even a drink."
@@ -2366,14 +2349,9 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Bug Zapper"
glass_desc = "An odd mix of copper, lemon juice and power meant for non-human consumption."
-/datum/reagent/consumable/ethanol/bug_zapper/on_mob_life(mob/living/carbon/M)
- if(isinsect(M) || isflyperson(M) || ismoth(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "bug"
-/datum/reagent/consumable/ethanol/mush_crush
+/datum/reagent/consumable/ethanol/species_drink/mush_crush
name = "Mush Crush"
color = "#F5882A" //(222, 250, 205)
description = "Soil in a glass."
@@ -2383,14 +2361,9 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Mush Crush"
glass_desc = "Popular among people that want to grow their own food rather than drink the soil."
-/datum/reagent/consumable/ethanol/mush_crush/on_mob_life(mob/living/carbon/M)
- if(ispodperson(M) || ismush(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "plant"
-/datum/reagent/consumable/ethanol/darkbrew
+/datum/reagent/consumable/ethanol/species_drink/darkbrew
name = "Darkbrew"
color = "#000000" //(0, 0, 0)
description = "Contained dark matter mixed with coffee."
@@ -2400,31 +2373,21 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Darkbrew"
glass_desc = "A pitch black drink that's commonly confused with a type of coffee."
-/datum/reagent/consumable/ethanol/darkbrew/on_mob_life(mob/living/carbon/M)
- if(isshadow(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "shadow"
-/datum/reagent/consumable/ethanol/hollow_bone
+/datum/reagent/consumable/ethanol/species_drink/hollow_bone
name = "Hollow Bone"
color = "#FCF7D4" //(252, 247, 212)
- description = "Shockingly none-harmful mix of toxins and milk."
+ description = "Shockingly non-harmful mix of toxins and milk."
boozepwr = 15
taste_description = "Milk and salt"
glass_icon_state = "hollow_bone"
glass_name = "skull of Hollow Bone"
- glass_desc = "Mixing of milk and bone hurting juice for enjoyment for rather skinny people."
+ glass_desc = "Mixing of milk and bone hurting juice for the enjoyment of rather skinny people."
-/datum/reagent/consumable/ethanol/hollow_bone/on_mob_life(mob/living/carbon/M)
- if(isplasmaman(M) || isskeleton(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "skeleton"
-/datum/reagent/consumable/ethanol/frisky_kitty
+/datum/reagent/consumable/ethanol/species_drink/frisky_kitty
name = "Frisky Kitty"
color = "#FCF7D4" //(252, 247, 212)
description = "Warm milk mixed with a catnip."
@@ -2434,14 +2397,9 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "cup of Drisky Kitty"
glass_desc = "Warm milk and some catnip."
-/datum/reagent/consumable/ethanol/frisky_kitty/on_mob_life(mob/living/carbon/M)
- if(ismammal(M) || iscatperson(M)) //well its not to bad for mammals
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "furry"
-/datum/reagent/consumable/ethanol/jell_wyrm
+/datum/reagent/consumable/ethanol/species_drink/jell_wyrm
name = "Jell Wyrm"
color = "#FF6200" //(255, 98, 0)
description = "Horrible mix of Co2, toxins and heat. Meant for slime based life."
@@ -2451,15 +2409,9 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Jell Wyrm"
glass_desc = "A bubbly drink that is rather inviting to those that don't know who it's meant for."
-/datum/reagent/consumable/ethanol/jell_wyrm/on_mob_life(mob/living/carbon/M)
- if(isjellyperson(M) || isstartjelly(M) || isslimeperson(M) || isluminescent(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- M.adjustToxLoss(1, 0) //Low tox due to being carp + jell toxins.
- return ..()
+ species_required = "jelly"
-/datum/reagent/consumable/ethanol/laval_spit //Yes Laval
+/datum/reagent/consumable/ethanol/species_drink/laval_spit //Yes Laval
name = "Laval Spit"
color = "#DE3009" //(222, 48, 9)
description = "Heat minerals and some mauna loa. Meant for rock based life."
@@ -2469,15 +2421,10 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Laval Spit"
glass_desc = "Piping hot drink for those who can stomach the heat of lava."
-/datum/reagent/consumable/ethanol/laval_spit/on_mob_life(mob/living/carbon/M)
- if(isgolem(M))
- quality = RACE_DRINK
- else
- M.adjust_disgust(25)
- return ..()
+ species_required = "golem"
///////////////
-//Barrle Wine//
+//Barrel Wine//
///////////////
/datum/reagent/consumable/ethanol/fruit_wine
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 0c3de579b6..e1433eb64e 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -217,6 +217,9 @@
/datum/reagent/consumable/milk/on_mob_life(mob/living/carbon/M)
if(HAS_TRAIT(M, TRAIT_CALCIUM_HEALER))
M.heal_bodypart_damage(1.5,0, 0)
+ for(var/i in M.all_wounds)
+ var/datum/wound/iter_wound = i
+ iter_wound.on_xadone(2)
. = 1
else
if(M.getBruteLoss() && prob(20))
@@ -320,6 +323,83 @@
..()
. = 1
+/datum/reagent/consumable/tea/red
+ name = "Red Tea"
+ description = "Tasty red tea, helps the body digest food. Drink in moderation!"
+ color = "#101000" // rgb: 16, 16, 0
+ nutriment_factor = 0
+ taste_description = "sweet red tea"
+ glass_icon_state = "teaglass"
+ glass_name = "glass of red tea"
+ glass_desc = "A piping hot tea that helps with the digestion of food."
+
+/datum/reagent/consumable/tea/red/on_mob_life(mob/living/carbon/M)
+ if(M.nutrition > NUTRITION_LEVEL_HUNGRY)
+ M.adjust_nutrition(-3)
+ M.dizziness = max(0,M.dizziness-2)
+ M.drowsyness = max(0,M.drowsyness-1)
+ M.jitteriness = max(0,M.jitteriness-3)
+ M.adjust_bodytemperature(23 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
+ . = 1
+
+/datum/reagent/consumable/tea/green
+ name = "Green Tea"
+ description = "Tasty green tea, known to heal livers, it's good for you!"
+ color = "#101000" // rgb: 16, 16, 0
+ nutriment_factor = 0
+ taste_description = "tart green tea"
+ glass_icon_state = "teaglass"
+ glass_name = "glass of tea"
+ glass_desc = "A calming glass of green tea to help get you through the day."
+
+/datum/reagent/consumable/tea/green/on_mob_life(mob/living/carbon/M)
+ M.adjustOrganLoss(ORGAN_SLOT_LIVER, -0.5) //Detox!
+ M.dizziness = max(0,M.dizziness-2)
+ M.drowsyness = max(0,M.drowsyness-1)
+ M.jitteriness = max(0,M.jitteriness-3)
+ M.adjust_bodytemperature(15 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
+ . = 1
+
+/datum/reagent/consumable/tea/forest
+ name = "Forest Tea"
+ description = "Tea mixed with honey, has both antitoxins and sweetness in one!"
+ color = "#101000" // rgb: 16, 16, 0
+ nutriment_factor = 0
+ quality = DRINK_NICE
+ taste_description = "sweet tea"
+ glass_icon_state = "teaglass"
+ glass_name = "glass of forest tea"
+ glass_desc = "A lovely glass of tea and honey."
+
+/datum/reagent/consumable/tea/forest/on_mob_life(mob/living/carbon/M)
+ if(M.getToxLoss() && prob(40))//Two anti-toxins working here
+ M.adjustToxLoss(-1, 0, TRUE) //heals TOXINLOVERs
+ //Reminder that honey heals toxin lovers
+ M.dizziness = max(0,M.dizziness-2)
+ M.drowsyness = max(0,M.drowsyness-1)
+ M.jitteriness = max(0,M.jitteriness-3)
+ M.adjust_bodytemperature(15 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
+ . = 1
+
+/datum/reagent/consumable/tea/mush
+ name = "Mush Tea"
+ description = "Tea mixed with mushroom hallucinogen, used for fun rides or self reflection."
+ color = "#101000" // rgb: 16, 16, 0
+ nutriment_factor = 0
+ quality = DRINK_NICE
+ taste_description = "fungal infections"
+ glass_icon_state = "teaglass"
+ glass_name = "glass of mush tea"
+ glass_desc = "A cold merky brown tea."
+
+/datum/reagent/consumable/tea/mush/on_mob_life(mob/living/carbon/M)
+ M.set_drugginess(20) //Little better then space drugs
+ if(prob(20))
+ M.Dizzy(10)
+ if(prob(10))
+ M.disgust = 0
+ . = 1
+
/datum/reagent/consumable/lemonade
name = "Lemonade"
description = "Sweet, tangy lemonade. Good for the soul."
@@ -964,12 +1044,6 @@
M.emote("nya")
if(prob(20))
to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]")
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/list/adjusted = H.adjust_arousal(5,aphro = TRUE)
- for(var/g in adjusted)
- var/obj/item/organ/genital/G = g
- to_chat(M, "You feel like playing with your [G.name]!")
..()
/datum/reagent/consumable/monkey_energy
@@ -1013,4 +1087,23 @@
if(M.getToxLoss() && prob(30))
M.adjustToxLoss(-1, 0)
..()
- . = TRUE
\ No newline at end of file
+ . = TRUE
+
+// i googled "natural coagulant" and a couple of results came up for banana peels, so after precisely 30 more seconds of research, i now dub grinding banana peels good for your blood
+/datum/reagent/consumable/banana_peel
+ name = "Pulped Banana Peel"
+ description = "Okay, so you put a banana peel in a grinder... Why, exactly?"
+ color = "#863333" // rgb: 175, 175, 0
+ reagent_state = SOLID
+ taste_description = "stringy, bitter pulp"
+ glass_name = "glass of banana peel pulp"
+ glass_desc = "Okay, so you put a banana peel in a grinder... Why, exactly?"
+
+/datum/reagent/consumable/baked_banana_peel
+ name = "Baked Banana Peel Powder"
+ description = "You took a banana peel... pulped it... baked it... Where are you going with this?"
+ color = "#863333" // rgb: 175, 175, 0
+ reagent_state = SOLID
+ taste_description = "bitter powder"
+ glass_name = "glass of banana peel powder"
+ description = "You took a banana peel... pulped it... baked it... Where are you going with this?"
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index f1e45d0717..44b6e85f47 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -467,7 +467,7 @@
/datum/reagent/drug/skooma/on_mob_metabolize(mob/living/L)
. = ..()
L.add_movespeed_modifier(/datum/movespeed_modifier/reagent/skooma)
- L.next_move_modifier *= 2
+ L.action_cooldown_mod *= 2
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.physiology)
@@ -480,7 +480,7 @@
/datum/reagent/drug/skooma/on_mob_end_metabolize(mob/living/L)
. = ..()
L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/skooma)
- L.next_move_modifier *= 0.5
+ L.action_cooldown_mod *= 0.5
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.physiology)
@@ -542,13 +542,13 @@
/datum/reagent/syndicateadrenals/on_mob_metabolize(mob/living/M)
. = ..()
if(istype(M))
- M.next_move_modifier *= 0.5
+ M.action_cooldown_mod *= 0.5
to_chat(M, "You feel an intense surge of energy rushing through your veins.")
/datum/reagent/syndicateadrenals/on_mob_end_metabolize(mob/living/M)
. = ..()
if(istype(M))
- M.next_move_modifier *= 2
+ M.action_cooldown_mod *= 2
to_chat(M, "You feel as though the world around you is going faster.")
/datum/reagent/syndicateadrenals/overdose_start(mob/living/M)
@@ -559,128 +559,3 @@
var/mob/living/carbon/C = M
if(!C.undergoing_cardiac_arrest())
C.set_heartattack(TRUE)
-
-//aphrodisiac & anaphrodisiac
-
-/datum/reagent/drug/aphrodisiac
- name = "Crocin"
- description = "Naturally found in the crocus and gardenia flowers, this drug acts as a natural and safe aphrodisiac."
- taste_description = "strawberries"
- color = "#FFADFF"//PINK, rgb(255, 173, 255)
- can_synth = FALSE
-
-/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/M)
- if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO))
- if((prob(min(current_cycle/2,5))))
- M.emote(pick("moan","blush"))
- if(prob(min(current_cycle/4,10)))
- var/aroused_message = pick("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.")
- to_chat(M, "[aroused_message]")
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/list/genits = H.adjust_arousal(current_cycle, aphro = TRUE) // redundant but should still be here
- for(var/g in genits)
- var/obj/item/organ/genital/G = g
- to_chat(M, "[G.arousal_verb]!")
- ..()
-
-/datum/reagent/drug/aphrodisiacplus
- name = "Hexacrocin"
- description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive in most animals.\
- Addiction withdrawals can cause brain damage and shortness of breath. Overdosage can lead to brain damage and a \
- permanent increase in libido (commonly referred to as 'bimbofication')."
- taste_description = "liquid desire"
- color = "#FF2BFF"//dark pink
- addiction_threshold = 20
- overdose_threshold = 20
- can_synth = FALSE
-
-/datum/reagent/drug/aphrodisiacplus/on_mob_life(mob/living/M)
- if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO))
- if(prob(5))
- if(prob(current_cycle))
- M.say(pick("Hnnnnngghh...", "Ohh...", "Mmnnn..."))
- else
- M.emote(pick("moan","blush"))
- if(prob(5))
- var/aroused_message
- if(current_cycle>25)
- aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!")
- else
- aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
- to_chat(M, "[aroused_message]")
- REMOVE_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/list/genits = H.adjust_arousal(100, aphro = TRUE) // redundant but should still be here
- for(var/g in genits)
- var/obj/item/organ/genital/G = g
- to_chat(M, "[G.arousal_verb]!")
- ..()
-
-/datum/reagent/drug/aphrodisiacplus/addiction_act_stage2(mob/living/M)
- if(prob(30))
- M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2)
- ..()
-/datum/reagent/drug/aphrodisiacplus/addiction_act_stage3(mob/living/M)
- if(prob(30))
- M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3)
-
- ..()
-/datum/reagent/drug/aphrodisiacplus/addiction_act_stage4(mob/living/M)
- if(prob(30))
- M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 4)
- ..()
-
-/datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M)
- if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33))
- if(prob(5) && ishuman(M) && M.has_dna() && (M.client?.prefs.cit_toggles & BIMBOFICATION))
- if(!HAS_TRAIT(M,TRAIT_PERMABONER))
- to_chat(M, "Your libido is going haywire!")
- ADD_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT)
- ..()
-
-/datum/reagent/drug/anaphrodisiac
- name = "Camphor"
- description = "Naturally found in some species of evergreen trees, camphor is a waxy substance. When injested by most animals, it acts as an anaphrodisiac\
- , reducing libido and calming them. Non-habit forming and not addictive."
- taste_description = "dull bitterness"
- taste_mult = 2
- color = "#D9D9D9"//rgb(217, 217, 217)
- reagent_state = SOLID
- can_synth = FALSE
-
-/datum/reagent/drug/anaphrodisiac/on_mob_life(mob/living/M)
- if(M && M.client?.prefs.arousable && prob(16))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/list/genits = H.adjust_arousal(-100, aphro = TRUE)
- if(genits.len)
- to_chat(M, "You no longer feel aroused.")
- ..()
-
-/datum/reagent/drug/anaphrodisiacplus
- name = "Hexacamphor"
- description = "Chemically condensed camphor. Causes an extreme reduction in libido and a permanent one if overdosed. Non-addictive."
- taste_description = "tranquil celibacy"
- color = "#D9D9D9"//rgb(217, 217, 217)
- reagent_state = SOLID
- overdose_threshold = 20
- can_synth = FALSE
-
-/datum/reagent/drug/anaphrodisiacplus/on_mob_life(mob/living/M)
- if(M && M.client?.prefs.arousable)
- REMOVE_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/list/genits = H.adjust_arousal(-100, aphro = TRUE)
- if(genits.len)
- to_chat(M, "You no longer feel aroused.")
-
- ..()
-
-/datum/reagent/drug/anaphrodisiacplus/overdose_process(mob/living/M)
- if(M && M.client?.prefs.arousable && prob(5))
- to_chat(M, "You feel like you'll never feel aroused again...")
- ADD_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT)
- ..()
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index d449fa310c..a6e78ae98c 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -768,7 +768,6 @@
color = "#97ee63"
taste_description = "pure electricity"
-/* //We don't have ethereals here, so I'll just comment it out.
/datum/reagent/consumable/liquidelectricity/reaction_mob(mob/living/M, method=TOUCH, reac_volume) //can't be on life because of the way blood works.
if((method == INGEST || method == INJECT || method == PATCH) && iscarbon(M))
@@ -776,10 +775,9 @@
var/obj/item/organ/stomach/ethereal/stomach = C.getorganslot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
stomach.adjust_charge(reac_volume * REM)
-*/
/datum/reagent/consumable/liquidelectricity/on_mob_life(mob/living/carbon/M)
- if(prob(25)) // && !isethereal(M))
+ if(prob(25) && !isethereal(M))
M.electrocute_act(rand(10,15), "Liquid Electricity in their body", 1) //lmao at the newbs who eat energy bars
playsound(M, "sparks", 50, TRUE)
return ..()
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index b173df3282..37010cbbb5 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -144,6 +144,9 @@
M.adjustFireLoss(-power, 0)
M.adjustToxLoss(-power, 0, TRUE) //heals TOXINLOVERs
M.adjustCloneLoss(-power, 0)
+ for(var/i in M.all_wounds)
+ var/datum/wound/iter_wound = i
+ iter_wound.on_xadone(power)
REMOVE_TRAIT(M, TRAIT_DISFIGURED, TRAIT_GENERIC) //fixes common causes for disfiguration
. = 1
metabolization_rate = REAGENTS_METABOLISM * (0.00001 * (M.bodytemperature ** 2) + 0.5)
@@ -192,6 +195,9 @@
M.adjustFireLoss(-1.5 * power, 0)
M.adjustToxLoss(-power, 0, TRUE)
M.adjustCloneLoss(-power, 0)
+ for(var/i in M.all_wounds)
+ var/datum/wound/iter_wound = i
+ iter_wound.on_xadone(power)
REMOVE_TRAIT(M, TRAIT_DISFIGURED, TRAIT_GENERIC)
. = 1
..()
@@ -231,7 +237,7 @@
/datum/reagent/medicine/spaceacillin
name = "Spaceacillin"
- description = "Spaceacillin will prevent a patient from conventionally spreading any diseases they are currently infected with."
+ description = "Spaceacillin will prevent a patient from conventionally spreading any diseases they are currently infected with. Also reduces infection in serious burns."
color = "#f2f2f2"
metabolization_rate = 0.1 * REAGENTS_METABOLISM
pH = 8.1
@@ -359,7 +365,7 @@
/datum/reagent/medicine/salglu_solution
name = "Saline-Glucose Solution"
- description = "Has a 33% chance per metabolism cycle to heal brute and burn damage. Can be used as a temporary blood substitute."
+ description = "Has a 33% chance per metabolism cycle to heal brute and burn damage. Can be used as a temporary blood substitute, as well as slowly speeding blood regeneration."
reagent_state = LIQUID
color = "#DCDCDC"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
@@ -367,6 +373,7 @@
taste_description = "sweetness and salt"
var/last_added = 0
var/maximum_reachable = BLOOD_VOLUME_NORMAL - 10 //So that normal blood regeneration can continue with salglu active
+ var/extra_regen = 0.25 // in addition to acting as temporary blood, also add this much to their actual blood per tick
pH = 5.5
/datum/reagent/medicine/salglu_solution/on_mob_life(mob/living/carbon/M)
@@ -379,7 +386,7 @@
var/amount_to_add = min(M.blood_volume, volume*5)
var/new_blood_level = min(M.blood_volume + amount_to_add, maximum_reachable)
last_added = new_blood_level - M.blood_volume
- M.blood_volume = new_blood_level
+ M.blood_volume = new_blood_level + extra_regen
if(prob(33))
M.adjustBruteLoss(-0.5*REM, 0)
M.adjustFireLoss(-0.5*REM, 0)
@@ -403,7 +410,7 @@
/datum/reagent/medicine/mine_salve
name = "Miner's Salve"
- description = "A powerful painkiller. Restores bruising and burns in addition to making the patient believe they are fully healed."
+ description = "A powerful painkiller. Restores bruising and burns in addition to making the patient believe they are fully healed. Also great for treating severe burn wounds in a pinch."
reagent_state = LIQUID
color = "#6D6374"
metabolization_rate = 0.4 * REAGENTS_METABOLISM
@@ -432,7 +439,7 @@
// +10% success propability on each step, useful while operating in less-than-perfect conditions
if(show_message)
- to_chat(M, "You feel your wounds fade away to nothing!" )
+ to_chat(M, "You feel your injuries fade away to nothing!" )
..()
/datum/reagent/medicine/mine_salve/on_mob_end_metabolize(mob/living/M)
@@ -453,10 +460,10 @@
/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M))
- if (M.stat == DEAD)
+ var/mob/living/carbon/C = M
+ if(M.stat == DEAD)
show_message = 0
if(method in list(INGEST, VAPOR))
- var/mob/living/carbon/C = M
C.losebreath++
C.emote("cough")
to_chat(M, "You feel your throat closing up!")
@@ -465,6 +472,9 @@
else if(method in list(PATCH, TOUCH))
M.adjustBruteLoss(-1 * reac_volume)
M.adjustFireLoss(-1 * reac_volume)
+ for(var/i in C.all_wounds)
+ var/datum/wound/iter_wound = i
+ iter_wound.on_synthflesh(reac_volume)
if(show_message)
to_chat(M, "You feel your burns and bruises healing! It stings like hell!")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
@@ -1559,10 +1569,6 @@
/datum/reagent/medicine/polypyr/on_mob_life(mob/living/carbon/M) //I wanted a collection of small positive effects, this is as hard to obtain as coniine after all.
M.adjustOrganLoss(ORGAN_SLOT_LUNGS, -0.25)
M.adjustBruteLoss(-0.35, 0)
- if(prob(50))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.bleed_rate = max(H.bleed_rate - 1, 0)
..()
. = 1
@@ -1594,3 +1600,57 @@
if(prob(3))
to_chat(C, "[pick(GLOB.wisdoms)]") //give them a random wisdom
..()
+
+// helps bleeding wounds clot faster
+/datum/reagent/medicine/coagulant
+ name = "Sanguirite"
+ description = "A proprietary coagulant used to help bleeding wounds clot faster."
+ reagent_state = LIQUID
+ color = "#bb2424"
+ metabolization_rate = 0.25 * REAGENTS_METABOLISM
+ overdose_threshold = 20
+ /// How much base clotting we do per bleeding wound, multiplied by the below number for each bleeding wound
+ var/clot_rate = 0.25
+ /// If we have multiple bleeding wounds, we count the number of bleeding wounds, then multiply the clot rate by this^(n) before applying it to each cut, so more cuts = less clotting per cut (though still more total clotting)
+ var/clot_coeff_per_wound = 0.9
+
+/datum/reagent/medicine/coagulant/on_mob_life(mob/living/carbon/M)
+ . = ..()
+ if(!M.blood_volume || !M.all_wounds)
+ return
+
+ var/effective_clot_rate = clot_rate
+
+ for(var/i in M.all_wounds)
+ var/datum/wound/iter_wound = i
+ if(iter_wound.blood_flow)
+ effective_clot_rate *= clot_coeff_per_wound
+
+ for(var/i in M.all_wounds)
+ var/datum/wound/iter_wound = i
+ iter_wound.blood_flow = max(0, iter_wound.blood_flow - effective_clot_rate)
+
+/datum/reagent/medicine/coagulant/overdose_process(mob/living/M)
+ . = ..()
+ if(!M.blood_volume)
+ return
+
+ if(prob(15))
+ M.losebreath += rand(2,4)
+ M.adjustOxyLoss(rand(1,3))
+ if(prob(30))
+ to_chat(M, "You can feel your blood clotting up in your veins!")
+ else if(prob(10))
+ to_chat(M, "You feel like your blood has stopped moving!")
+ if(prob(50))
+ var/obj/item/organ/lungs/our_lungs = M.getorganslot(ORGAN_SLOT_LUNGS)
+ our_lungs.applyOrganDamage(1)
+ else
+ var/obj/item/organ/heart/our_heart = M.getorganslot(ORGAN_SLOT_HEART)
+ our_heart.applyOrganDamage(1)
+
+// can be synthesized on station rather than bought. made by grinding a banana peel, heating it up, then mixing the banana peel powder with salglu
+/datum/reagent/medicine/coagulant/weak
+ name = "Synthi-Sanguirite"
+ description = "A synthetic coagulant used to help bleeding wounds clot faster. Not quite as effective as name brand Sanguirite, especially on patients with lots of cuts."
+ clot_coeff_per_wound = 0.8
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index e0632a9199..ea9dbd5a9d 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -244,6 +244,11 @@
glass_desc = "The father of all refreshments."
shot_glass_icon_state = "shotglassclear"
+/datum/reagent/water/on_mob_life(mob/living/carbon/M)
+ . = ..()
+ if(M.blood_volume)
+ M.blood_volume += 0.1 // water is good for you!
+
/*
* Water reaction to turf
*/
@@ -341,6 +346,8 @@
return ..()
/datum/reagent/water/holywater/on_mob_life(mob/living/carbon/M)
+ if(M.blood_volume)
+ M.blood_volume += 0.1 // water is good for you!
if(!data)
data = list("misc" = 1)
data["misc"]++
@@ -2204,13 +2211,6 @@
M.emote("nya")
if(prob(20))
to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]")
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/list/adjusted = H.adjust_arousal(2,aphro = TRUE)
- for(var/g in adjusted)
- var/obj/item/organ/genital/G = g
- to_chat(M, "You feel like playing with your [G.name]!")
-
..()
/datum/reagent/preservahyde
@@ -2370,9 +2370,94 @@
if(data["blood_DNA"])
S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
+/datum/reagent/determination
+ name = "Determination"
+ description = "For when you need to push on a little more. Do NOT allow near plants."
+ reagent_state = LIQUID
+ color = "#D2FFFA"
+ metabolization_rate = 0.75 * REAGENTS_METABOLISM // 5u (WOUND_DETERMINATION_CRITICAL) will last for ~17 ticks
+ /// Whether we've had at least WOUND_DETERMINATION_SEVERE (2.5u) of determination at any given time. No damage slowdown immunity or indication we're having a second wind if it's just a single moderate wound
+ var/significant = FALSE
+ self_consuming = TRUE
+
+/datum/reagent/determination/on_mob_end_metabolize(mob/living/carbon/M)
+ if(significant)
+ var/stam_crash = 0
+ for(var/thing in M.all_wounds)
+ var/datum/wound/W = thing
+ stam_crash += (W.severity + 1) * 3 // spike of 3 stam damage per wound severity (moderate = 6, severe = 9, critical = 12) when the determination wears off if it was a combat rush
+ M.adjustStaminaLoss(stam_crash)
+ M.remove_status_effect(STATUS_EFFECT_DETERMINED)
+ ..()
+
+/datum/reagent/determination/on_mob_life(mob/living/carbon/M)
+ if(!significant && volume >= WOUND_DETERMINATION_SEVERE)
+ significant = TRUE
+ M.apply_status_effect(STATUS_EFFECT_DETERMINED) // in addition to the slight healing, limping cooldowns are divided by 4 during the combat high
+
+ volume = min(volume, WOUND_DETERMINATION_MAX)
+
+ for(var/thing in M.all_wounds)
+ var/datum/wound/W = thing
+ var/obj/item/bodypart/wounded_part = W.limb
+ if(wounded_part)
+ wounded_part.heal_damage(0.25, 0.25)
+ M.adjustStaminaLoss(-0.25*REM) // the more wounds, the more stamina regen
+ ..()
+
/datum/reagent/cellulose
name = "Cellulose Fibers"
description = "A crystaline polydextrose polymer, plants swear by this stuff."
reagent_state = SOLID
color = "#E6E6DA"
taste_mult = 0
+
+
+/datum/reagent/hairball
+ name = "Hairball"
+ description = "A bundle of keratinous bits and fibers, not easily digestible."
+ reagent_state = SOLID
+ can_synth = FALSE
+ metabolization_rate = 0.05 * REAGENTS_METABOLISM
+ taste_description = "wet hair"
+ var/amount = 0
+ var/knotted = FALSE
+
+/datum/reagent/hairball/on_mob_life(mob/living/carbon/M)
+ amount = M.reagents.get_reagent_amount(/datum/reagent/hairball)
+
+ if(amount < 10)
+ if(prob(10))
+ M.losebreath += 1
+ M.emote("cough")
+ to_chat(M, "You clear your throat.")
+ else
+ if(!knotted)
+ to_chat(M, "You feel a knot in your stomach.")
+ knotted = TRUE
+
+ if(prob(5 + amount * 0.5)) // don't want this to cause too much damage
+ M.losebreath += 2
+ to_chat(M, "You feel a knot in your throat.")
+ M.emote("cough")
+
+ else if(prob(amount - 4))
+ to_chat(M, "Your stomach feels awfully bloated.")
+ playsound(M,'sound/voice/catpeople/distressed.ogg', 50, FALSE)
+ M.visible_message("[M] seems distressed!.", ignored_mobs=M)
+
+ else if(prob(amount - 8))
+ knotted = FALSE
+ playsound(M,'sound/voice/catpeople/puking.ogg', 110, FALSE)
+ M.Immobilize(30)
+ sleep(30) //snowflake but it works, don't wanna proc this
+ if(QDELETED(M) || QDELETED(src)) //this handles race conditions about m or src not existing.
+ return
+ M.visible_message("[M] throws up a hairball! Disgusting!", ignored_mobs=M)
+ new /obj/item/toy/plush/hairball(get_turf(M))
+ to_chat(M, "Aaaah that's better!")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "cleared_stomach", /datum/mood_event/cleared_stomach, name)
+ M.reagents.del_reagent(/datum/reagent/hairball)
+ return
+ ..()
+
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 704895b8d4..07934d9880 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -155,6 +155,11 @@
pH = 12
value = REAGENT_VALUE_RARE
+/datum/reagent/toxin/carpotoxin/on_mob_life(mob/living/carbon/M)
+ . = ..()
+ for(var/i in M.all_scars)
+ qdel(i)
+
/datum/reagent/toxin/zombiepowder
name = "Zombie Powder"
description = "A strong neurotoxin that puts the subject into a death-like state."
@@ -369,6 +374,14 @@
pH = 4.9
value = REAGENT_VALUE_VERY_COMMON
+/datum/reagent/toxin/teapowder/red
+ name = "Ground Red Tea Leaves"
+ toxpwr = 0.4
+
+/datum/reagent/toxin/teapowder/green
+ name = "Ground Green Tea Leaves"
+ toxpwr = 0.6
+
/datum/reagent/toxin/mutetoxin //the new zombie powder.
name = "Mute Toxin"
description = "A nonlethal poison that inhibits speech in its victim."
@@ -718,22 +731,13 @@
/datum/reagent/toxin/heparin //Based on a real-life anticoagulant. I'm not a doctor, so this won't be realistic.
name = "Heparin"
- description = "A powerful anticoagulant. Victims will bleed uncontrollably and suffer scaling bruising."
+ description = "A powerful anticoagulant. All open cut wounds on the victim will open up and bleed much faster"
reagent_state = LIQUID
color = "#C8C8C8" //RGB: 200, 200, 200
metabolization_rate = 0.2 * REAGENTS_METABOLISM
toxpwr = 0
value = REAGENT_VALUE_VERY_RARE
-/datum/reagent/toxin/heparin/on_mob_life(mob/living/carbon/M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.bleed_rate = min(H.bleed_rate + 2, 8)
- H.adjustBruteLoss(1, 0) //Brute damage increases with the amount they're bleeding
- . = 1
- return ..() || .
-
-
/datum/reagent/toxin/rotatium //Rotatium. Fucks up your rotation and is hilarious
name = "Rotatium"
description = "A constantly swirling, oddly colourful fluid. Causes the consumer's sense of direction and hand-eye coordination to become wild."
diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm
index a2b8c27552..468d29c052 100644
--- a/code/modules/reagents/chemistry/recipes/drugs.dm
+++ b/code/modules/reagents/chemistry/recipes/drugs.dm
@@ -62,34 +62,3 @@
results = list(/datum/reagent/moonsugar = 1, /datum/reagent/medicine/morphine = 2.5)
required_temp = 315 //a little above normal body temperature
required_reagents = list(/datum/reagent/drug/skooma = 1)
-/datum/chemical_reaction/aphro
- name = "crocin"
- id = /datum/reagent/drug/aphrodisiac
- results = list(/datum/reagent/drug/aphrodisiac = 6)
- required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/water = 1)
- required_temp = 400
- mix_message = "The mixture boils off a pink vapor..."//The water boils off, leaving the crocin
-
-/datum/chemical_reaction/aphroplus
- name = "hexacrocin"
- id = /datum/reagent/drug/aphrodisiacplus
- results = list(/datum/reagent/drug/aphrodisiacplus = 1)
- required_reagents = list(/datum/reagent/drug/aphrodisiac = 6, /datum/reagent/phenol = 1)
- required_temp = 400
- mix_message = "The mixture rapidly condenses and darkens in color..."
-
-/datum/chemical_reaction/anaphro
- name = "camphor"
- id = /datum/reagent/drug/anaphrodisiac
- results = list(/datum/reagent/drug/anaphrodisiac = 6)
- required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/sulfur = 1)
- required_temp = 400
- mix_message = "The mixture boils off a yellow, smelly vapor..."//Sulfur burns off, leaving the camphor
-
-/datum/chemical_reaction/anaphroplus
- name = "pentacamphor"
- id = /datum/reagent/drug/anaphrodisiacplus
- results = list(/datum/reagent/drug/anaphrodisiacplus = 1)
- required_reagents = list(/datum/reagent/drug/aphrodisiac = 5, /datum/reagent/acetone = 1)
- required_temp = 300
- mix_message = "The mixture thickens and heats up slighty..."
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index 663d232bb8..9b303cd5c0 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -50,6 +50,18 @@
results = list(/datum/reagent/medicine/salglu_solution = 3)
required_reagents = list(/datum/reagent/consumable/sodiumchloride = 1, /datum/reagent/water = 1, /datum/reagent/consumable/sugar = 1)
+/datum/chemical_reaction/baked_banana_peel
+ results = list(/datum/reagent/consumable/baked_banana_peel = 1)
+ required_temp = 413.15 // if it's good enough for caramel it's good enough for this
+ required_reagents = list(/datum/reagent/consumable/banana_peel = 1)
+ mix_message = "The pulp dries up and takes on a powdery state!"
+ mob_react = FALSE
+
+/datum/chemical_reaction/coagulant_weak
+ results = list(/datum/reagent/medicine/coagulant/weak = 3)
+ required_reagents = list(/datum/reagent/medicine/salglu_solution = 2, /datum/reagent/consumable/baked_banana_peel = 1)
+ mob_react = FALSE
+
/datum/chemical_reaction/mine_salve
name = "Miner's Salve"
id = /datum/reagent/medicine/mine_salve
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index ddf38749c9..92861a94ed 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -715,10 +715,10 @@
required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/medicine/synaptizine = 1, /datum/reagent/water = 1)
/datum/chemical_reaction/cat
- name = "felined mutation toxic"
+ name = "felinid mutation toxic"
id = /datum/reagent/mutationtoxin/felinid
results = list(/datum/reagent/mutationtoxin/felinid = 1)
- required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/drug/aphrodisiac = 10, /datum/reagent/mutationtoxin = 1) // Maybe aphro+ if it becomes a shitty meme
+ required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/pax/catnip = 1, /datum/reagent/mutationtoxin = 1)
required_temp = 450
/datum/chemical_reaction/moff
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index fbdbb5f656..b71584982c 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -69,7 +69,8 @@
to_chat(user, "[src]'s transfer amount is now [amount_per_transfer_from_this] units.")
return
-/obj/item/reagent_containers/attack(mob/M, mob/user, def_zone)
+/obj/item/reagent_containers/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
+ . = ..()
if(user.a_intent == INTENT_HARM)
return ..()
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index ad8d722b61..20abcf847f 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -416,25 +416,3 @@
/obj/item/reagent_containers/glass/bottle/bromine
name = "bromine bottle"
list_reagents = list(/datum/reagent/bromine = 30)
-
-//Lewd Stuff
-
-/obj/item/reagent_containers/glass/bottle/crocin
- name = "Crocin bottle"
- desc = "A bottle of mild aphrodisiac. Increases libido."
- list_reagents = list(/datum/reagent/drug/aphrodisiac = 30)
-
-/obj/item/reagent_containers/glass/bottle/hexacrocin
- name = "Hexacrocin bottle"
- desc = "A bottle of strong aphrodisiac. Increases libido."
- list_reagents = list(/datum/reagent/drug/aphrodisiacplus = 30)
-
-/obj/item/reagent_containers/glass/bottle/camphor
- name = "Camphor bottle"
- desc = "A bottle of mild anaphrodisiac. Reduces libido."
- list_reagents = list(/datum/reagent/drug/anaphrodisiac = 30)
-
-/obj/item/reagent_containers/glass/bottle/hexacamphor
- name = "Hexacamphor bottle"
- desc = "A bottle of strong anaphrodisiac. Reduces libido."
- list_reagents = list(/datum/reagent/drug/anaphrodisiacplus = 30)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 37ea2ca70d..ec26182813 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -9,6 +9,11 @@
container_HP = 2
/obj/item/reagent_containers/glass/attack(mob/M, mob/user, obj/target)
+ // WARNING: This entire section is shitcode and prone to breaking at any time.
+ INVOKE_ASYNC(src, .proc/attempt_feed, M, user, target) // for example, the arguments in this proc are wrong
+ // but i don't have time to properly fix it right now.
+
+/obj/item/reagent_containers/glass/proc/attempt_feed(mob/M, mob/user, obj/target)
if(!canconsume(M, user))
return
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index efdd137ece..835ffe2d89 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -90,12 +90,12 @@
item_state = "medipen"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- amount_per_transfer_from_this = 13
- volume = 13
+ amount_per_transfer_from_this = 15
+ volume = 15
ignore_flags = 1 //so you can medipen through hardsuits
reagent_flags = DRAWABLE
flags_1 = null
- list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/preservahyde = 3)
+ list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/preservahyde = 3, /datum/reagent/medicine/coagulant = 2)
custom_premium_price = PRICE_ALMOST_EXPENSIVE
/obj/item/reagent_containers/hypospray/medipen/suicide_act(mob/living/carbon/user)
@@ -133,6 +133,20 @@
else
. += "It is spent."
+/obj/item/reagent_containers/hypospray/medipen/ekit
+ name = "emergency first-aid autoinjector"
+ desc = "An epinephrine medipen with extra coagulant and antibiotics to help stabilize bad cuts and burns."
+ volume = 15
+ amount_per_transfer_from_this = 15
+ list_reagents = list(/datum/reagent/medicine/epinephrine = 12, /datum/reagent/medicine/coagulant = 2.5, /datum/reagent/medicine/spaceacillin = 0.5)
+
+/obj/item/reagent_containers/hypospray/medipen/blood_loss
+ name = "hypovolemic-response autoinjector"
+ desc = "A medipen designed to stabilize and rapidly reverse severe bloodloss."
+ volume = 15
+ amount_per_transfer_from_this = 15
+ list_reagents = list(/datum/reagent/medicine/epinephrine = 5, /datum/reagent/medicine/coagulant = 2.5, /datum/reagent/iron = 3.5, /datum/reagent/medicine/salglu_solution = 4)
+
/obj/item/reagent_containers/hypospray/medipen/stimulants
name = "illegal stimpack medipen"
desc = "A highly illegal medipen due to its load and small injections, allow for five uses before being drained"
@@ -354,13 +368,17 @@
obj_flags |= EMAGGED
return TRUE
-/obj/item/hypospray/mkii/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/hypospray/mkii/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..() //Don't bother changing this or removing it from containers will break.
/obj/item/hypospray/mkii/attack(obj/item/I, mob/user, params)
return
/obj/item/hypospray/mkii/afterattack(atom/target, mob/user, proximity)
+ . = ..()
+ INVOKE_ASYNC(src, .proc/attempt_inject, target, user, proximity)
+
+/obj/item/hypospray/mkii/proc/attempt_inject(atom/target, mob/user, proximity)
if(!vial || !proximity || !isliving(target))
return
var/mob/living/L = target
diff --git a/code/modules/reagents/reagent_containers/maunamug.dm b/code/modules/reagents/reagent_containers/maunamug.dm
index 1600699226..3dfac8a631 100644
--- a/code/modules/reagents/reagent_containers/maunamug.dm
+++ b/code/modules/reagents/reagent_containers/maunamug.dm
@@ -88,7 +88,7 @@
user.visible_message("[user] inserts a power cell into [src].", "You insert the power cell into [src].")
update_icon()
-/obj/item/reagent_containers/glass/maunamug/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/reagent_containers/glass/maunamug/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(cell && open)
cell.update_icon()
user.put_in_hands(cell)
diff --git a/code/modules/reagents/reagent_containers/medspray.dm b/code/modules/reagents/reagent_containers/medspray.dm
index 02a3f987bc..40ad167531 100644
--- a/code/modules/reagents/reagent_containers/medspray.dm
+++ b/code/modules/reagents/reagent_containers/medspray.dm
@@ -32,6 +32,9 @@
to_chat(user, "You will now apply the medspray's contents in [squirt_mode ? "short bursts":"extended sprays"]. You'll now use [amount_per_transfer_from_this] units per use.")
/obj/item/reagent_containers/medspray/attack(mob/living/L, mob/user, def_zone)
+ INVOKE_ASYNC(src, .proc/attempt_spray, L, user, def_zone) // this is shitcode because the params for attack aren't even right but i'm not in the mood to refactor right now.
+
+/obj/item/reagent_containers/medspray/proc/attempt_spray(mob/living/L, mob/user, def_zone)
if(!reagents || !reagents.total_volume)
to_chat(user, "[src] is empty!")
return
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index ec1e7823ed..3c23794e5a 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -28,22 +28,24 @@
/obj/item/reagent_containers/pill/get_w_volume() // DEFAULT_VOLUME_TINY at 25u, DEFAULT_VOLUME_SMALL at 50u
return DEFAULT_VOLUME_TINY/2 + reagents.total_volume / reagents.maximum_volume * DEFAULT_VOLUME_TINY
-/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
+/obj/item/reagent_containers/pill/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
+ INVOKE_ASYNC(src, .proc/attempt_feed, M, user)
+
+/obj/item/reagent_containers/pill/proc/attempt_feed(mob/living/M, mob/living/user)
if(!canconsume(M, user))
- return 0
+ return FALSE
if(M == user)
M.visible_message("[user] attempts to [apply_method] [src].")
if(self_delay)
if(!do_mob(user, M, self_delay))
- return 0
+ return FALSE
to_chat(M, "You [apply_method] [src].")
-
else
M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \
"[user] attempts to force [M] to [apply_method] [src].")
if(!do_mob(user, M))
- return 0
+ return FALSE
M.visible_message("[user] forces [M] to [apply_method] [src].", \
"[user] forces [M] to [apply_method] [src].")
@@ -56,8 +58,7 @@
reagents.reaction(M, apply_type)
reagents.trans_to(M, reagents.total_volume)
qdel(src)
- return 1
-
+ return TRUE
/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
. = ..()
@@ -77,6 +78,7 @@
"You dissolve [src] in [target].", vision_distance = 2)
reagents.trans_to(target, reagents.total_volume)
qdel(src)
+ return STOP_ATTACK_PROC_CHAIN
/obj/item/reagent_containers/pill/tox
name = "toxins pill"
diff --git a/code/modules/reagents/reagent_containers/rags.dm b/code/modules/reagents/reagent_containers/rags.dm
index afa188e9f6..469a8ef907 100644
--- a/code/modules/reagents/reagent_containers/rags.dm
+++ b/code/modules/reagents/reagent_containers/rags.dm
@@ -55,11 +55,10 @@
if(do_after(user, action_speed, target = A))
user.visible_message("[user] finishes wiping off [A]!", "You finish wiping off [A].")
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
- return
/obj/item/reagent_containers/rag/alt_pre_attack(mob/living/M, mob/living/user, params)
if(istype(M) && user.a_intent == INTENT_HELP)
- user.changeNext_move(CLICK_CD_MELEE)
+ user.DelayNextAction(CLICK_CD_MELEE)
if(M.on_fire)
user.visible_message("\The [user] uses \the [src] to pat out [M == user ? "[user.p_their()]" : "\the [M]'s"] flames!")
if(hitsound)
@@ -193,4 +192,4 @@
extinguish_efficiency = 5
action_speed = 15
damp_threshold = 0.8
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 20, "bio" = 20, "rad" = 20, "fire" = 50, "acid" = 50) //items don't provide armor to wearers unlike clothing yet.
\ No newline at end of file
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 20, "bio" = 20, "rad" = 20, "fire" = 50, "acid" = 50) //items don't provide armor to wearers unlike clothing yet.
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 7fea8250d9..9b25a80680 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -27,6 +27,8 @@
/obj/item/reagent_containers/spray/afterattack(atom/A, mob/user)
. = ..()
+ if(!user.CheckActionCooldown(CLICK_CD_MELEE))
+ return
if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics))
return
@@ -50,7 +52,7 @@
spray(A)
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
- user.changeNext_move(CLICK_CD_RANGE*2)
+ user.last_action = world.time
user.newtonian_move(get_dir(A, user))
var/turf/T = get_turf(src)
if(reagents.has_reagent(/datum/reagent/toxin/acid))
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 4ab1470667..f42ae668c7 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -16,6 +16,7 @@
custom_materials = list(/datum/material/iron=10, /datum/material/glass=20)
reagent_flags = TRANSPARENT
custom_price = PRICE_CHEAP_AS_FREE
+ sharpness = SHARP_POINTY
/obj/item/reagent_containers/syringe/Initialize()
. = ..()
@@ -42,8 +43,7 @@
mode = !mode
update_icon()
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/reagent_containers/syringe/attack_hand()
+/obj/item/reagent_containers/syringe/on_attack_hand()
. = ..()
update_icon()
@@ -53,8 +53,14 @@
/obj/item/reagent_containers/syringe/attackby(obj/item/I, mob/user, params)
return
-/obj/item/reagent_containers/syringe/afterattack(atom/target, mob/user , proximity)
+/obj/item/reagent_containers/syringe/attack()
+ return // no bludgeoning.
+
+/obj/item/reagent_containers/syringe/afterattack(atom/target, mob/user, proximity)
. = ..()
+ INVOKE_ASYNC(src, .proc/attempt_inject, target, user, proximity)
+
+/obj/item/reagent_containers/syringe/proc/attempt_inject(atom/target, mob/user, proximity)
if(busy)
return
if(!proximity)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index 077c8331ae..6541deda1c 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -80,7 +80,7 @@
else
. += "There are no paper cups left."
-/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/reagent_dispensers/water_cooler/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
@@ -255,19 +255,6 @@
icon_state = "orangekeg"
reagent_id = /datum/reagent/consumable/ethanol/mead
-/obj/structure/reagent_dispensers/keg/aphro
- name = "keg of aphrodisiac"
- desc = "A keg of aphrodisiac."
- icon_state = "pinkkeg"
- reagent_id = /datum/reagent/drug/aphrodisiac
- tank_volume = 150
-
-/obj/structure/reagent_dispensers/keg/aphro/strong
- name = "keg of strong aphrodisiac"
- desc = "A keg of strong and addictive aphrodisiac."
- reagent_id = /datum/reagent/drug/aphrodisiacplus
- tank_volume = 120
-
/obj/structure/reagent_dispensers/keg/milk
name = "keg of milk"
desc = "A keg of pasteurised, homogenised, filtered and semi-skimmed space milk."
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index d8cb462c97..b81c3b88f8 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -174,10 +174,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
return ..()
// attack with hand, move pulled object onto conveyor
-/obj/machinery/conveyor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
+/obj/machinery/conveyor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
user.Move_Pulled(src)
// make the conveyor broken
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 64fe786219..c8da9ab5e3 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -299,13 +299,15 @@
// handle machine interaction
-/obj/machinery/disposal/bin/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
+/obj/machinery/disposal/bin/ui_state(mob/user)
+ return GLOB.notcontained_state
+
+/obj/machinery/disposal/bin/ui_interact(mob/user, datum/tgui/ui)
if(stat & BROKEN)
return
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "DisposalUnit", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "DisposalUnit", name)
ui.open()
/obj/machinery/disposal/bin/ui_data(mob/user)
@@ -375,7 +377,6 @@
log_combat(user, target, "shoved", "into [src] (disposal bin)")
return TRUE
-
/obj/machinery/disposal/bin/flush()
..()
full_pressure = FALSE
diff --git a/code/modules/research/anomaly/anomaly_core.dm b/code/modules/research/anomaly/anomaly_core.dm
new file mode 100644
index 0000000000..7aeb7b3a9b
--- /dev/null
+++ b/code/modules/research/anomaly/anomaly_core.dm
@@ -0,0 +1,63 @@
+// Embedded signaller used in anomalies.
+/obj/item/assembly/signaler/anomaly
+ name = "anomaly core"
+ desc = "The neutralized core of an anomaly. It'd probably be valuable for research."
+ icon_state = "anomaly_core"
+ //inhand_icon_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ resistance_flags = FIRE_PROOF
+ var/anomaly_type = /obj/effect/anomaly
+
+/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
+ if(!signal)
+ return FALSE
+ if(signal.data["code"] != code)
+ return FALSE
+ if(suicider)
+ manual_suicide(suicider)
+ for(var/obj/effect/anomaly/A in get_turf(src))
+ A.anomalyNeutralize()
+ return TRUE
+
+/obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user)
+ user.visible_message("[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!")
+ //user.set_suicide(TRUE)
+ user.suicide_log()
+ user.gib()
+
+/obj/item/assembly/signaler/anomaly/attackby(obj/item/I, mob/user, params)
+ if(I.tool_behaviour == TOOL_ANALYZER)
+ to_chat(user, "Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code].")
+ return ..()
+
+//Anomaly cores
+/obj/item/assembly/signaler/anomaly/pyro
+ name = "\improper pyroclastic anomaly core"
+ desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research."
+ icon_state = "pyro_core"
+ anomaly_type = /obj/effect/anomaly/pyro
+
+/obj/item/assembly/signaler/anomaly/grav
+ name = "\improper gravitational anomaly core"
+ desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research."
+ icon_state = "grav_core"
+ anomaly_type = /obj/effect/anomaly/grav
+
+/obj/item/assembly/signaler/anomaly/flux
+ name = "\improper flux anomaly core"
+ desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research."
+ icon_state = "flux_core"
+ anomaly_type = /obj/effect/anomaly/flux
+
+/obj/item/assembly/signaler/anomaly/bluespace
+ name = "\improper bluespace anomaly core"
+ desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research."
+ icon_state = "anomaly_core"
+ anomaly_type = /obj/effect/anomaly/bluespace
+
+/obj/item/assembly/signaler/anomaly/vortex
+ name = "\improper vortex anomaly core"
+ desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research."
+ icon_state = "vortex_core"
+ anomaly_type = /obj/effect/anomaly/bhole
diff --git a/code/modules/research/bepis.dm b/code/modules/research/bepis.dm
index 87aec72646..7b36a614a7 100644
--- a/code/modules/research/bepis.dm
+++ b/code/modules/research/bepis.dm
@@ -33,11 +33,13 @@
var/inaccuracy_percentage = 1.5
var/positive_cash_offset = 0
var/negative_cash_offset = 0
- var/minor_rewards = list(/obj/item/stack/circuit_stack/full, //To add a new minor reward, add it here.
- /obj/item/flashlight/flashdark,
- /obj/item/pen/survival,
- /obj/item/circuitboard/machine/sleeper/party,
- /obj/item/toy/sprayoncan)
+ var/list/minor_rewards = list(
+ //To add a new minor reward, add it here.
+ /obj/item/stack/circuit_stack/full,
+ /obj/item/pen/survival,
+ /obj/item/circuitboard/machine/sleeper/party,
+ /obj/item/toy/sprayoncan,
+ )
var/static/list/item_list = list()
/obj/machinery/rnd/bepis/attackby(obj/item/O, mob/user, params)
@@ -101,6 +103,7 @@
return
account.adjust_money(-deposit_value) //The money vanishes, not paid to any accounts.
SSblackbox.record_feedback("amount", "BEPIS_credits_spent", deposit_value)
+ //log_econ("[deposit_value] credits were inserted into [src] by [account.account_holder]")
banked_cash += deposit_value
use_power(1000 * power_saver)
say("Cash deposit successful. There is [banked_cash] in the chamber.")
@@ -179,10 +182,10 @@
icon_state = "chamber"
return
-/obj/machinery/rnd/bepis/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/rnd/bepis/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "Bepis", name, 500, 480, master_ui, state)
+ ui = new(user, src, "Bepis", name)
ui.open()
RefreshParts()
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
index 76ec6224b8..574c7c9282 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
@@ -119,6 +119,24 @@
category = list("initial", "Medical","Tool Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+/datum/design/bonesetter
+ name = "Bonesetter"
+ id = "bonesetter"
+ build_type = AUTOLATHE | PROTOLATHE
+ materials = list(/datum/material/iron = 1000)
+ build_path = /obj/item/bonesetter
+ category = list("initial", "Medical", "Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/sticky_tape/surgical
+ name = "Surgical Tape"
+ id = "surgical_tape"
+ build_type = PROTOLATHE
+ materials = list(/datum/material/plastic = 500)
+ build_path = /obj/item/stack/sticky_tape/surgical
+ category = list("initial", "Medical")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/datum/design/beaker
name = "Beaker"
id = "beaker"
diff --git a/code/modules/research/designs/tool_designs.dm b/code/modules/research/designs/tool_designs.dm
index 551d6fa0e3..4fe07cb02f 100644
--- a/code/modules/research/designs/tool_designs.dm
+++ b/code/modules/research/designs/tool_designs.dm
@@ -92,6 +92,16 @@
category = list("Tool Designs")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_CARGO
+/datum/design/ranged_analyzer
+ name = "Long-range Analyzer"
+ desc = "A new advanced atmospheric analyzer design, capable of performing scans at long range."
+ id = "ranged_analyzer"
+ build_type = PROTOLATHE
+ materials = list(/datum/material/iron = 400, /datum/material/glass = 1000, /datum/material/uranium = 800, /datum/material/gold = 200, /datum/material/plastic = 200)
+ build_path = /obj/item/analyzer/ranged
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+
/////////////////////////////////////////
//////////////Alien Tools////////////////
/////////////////////////////////////////
diff --git a/code/modules/research/nanites/nanite_chamber.dm b/code/modules/research/nanites/nanite_chamber.dm
index 4a980a0436..01513a0b41 100644
--- a/code/modules/research/nanites/nanite_chamber.dm
+++ b/code/modules/research/nanites/nanite_chamber.dm
@@ -150,8 +150,6 @@
return
if(busy)
return
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the door of [src]!", \
"You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
diff --git a/code/modules/research/nanites/nanite_chamber_computer.dm b/code/modules/research/nanites/nanite_chamber_computer.dm
index b9623b751d..70e4d05590 100644
--- a/code/modules/research/nanites/nanite_chamber_computer.dm
+++ b/code/modules/research/nanites/nanite_chamber_computer.dm
@@ -5,8 +5,6 @@
var/obj/item/disk/nanite_program/disk
icon_screen = "nanite_chamber_control"
circuit = /obj/item/circuitboard/computer/nanite_chamber_control
- ui_x = 380
- ui_y = 570
/obj/machinery/computer/nanite_chamber_control/Initialize()
. = ..()
@@ -25,10 +23,10 @@
find_chamber()
..()
-/obj/machinery/computer/nanite_chamber_control/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "NaniteChamberControl", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "NaniteChamberControl", name)
ui.open()
/obj/machinery/computer/nanite_chamber_control/ui_data()
diff --git a/code/modules/research/nanites/nanite_cloud_controller.dm b/code/modules/research/nanites/nanite_cloud_controller.dm
index ef0fc33bd7..1a0a5dbd4d 100644
--- a/code/modules/research/nanites/nanite_cloud_controller.dm
+++ b/code/modules/research/nanites/nanite_cloud_controller.dm
@@ -1,11 +1,9 @@
/obj/machinery/computer/nanite_cloud_controller
name = "nanite cloud controller"
desc = "Stores and controls nanite cloud backups."
- circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
icon = 'icons/obj/machines/research.dmi'
icon_state = "nanite_cloud_controller"
- ui_x = 375
- ui_y = 700
+ circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
var/obj/item/disk/nanite_program/disk
var/list/datum/nanite_cloud_backup/cloud_backups = list()
@@ -20,19 +18,25 @@
/obj/machinery/computer/nanite_cloud_controller/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/disk/nanite_program))
var/obj/item/disk/nanite_program/N = I
- if(disk)
- eject(user)
- if(user.transferItemToLoc(N, src))
+ if (user.transferItemToLoc(N, src))
to_chat(user, "You insert [N] into [src].")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
+ if(disk)
+ eject(user)
disk = N
else
..()
+/obj/machinery/computer/nanite_cloud_controller/AltClick(mob/user)
+ if(disk && user.canUseTopic(src, !issilicon(user)))
+ to_chat(user, "You take out [disk] from [src].")
+ eject(user)
+ return
+
/obj/machinery/computer/nanite_cloud_controller/proc/eject(mob/living/user)
if(!disk)
return
- if(!istype(user) || !Adjacent(user) ||!user.put_in_active_hand(disk))
+ if(!istype(user) || !Adjacent(user))// ||!user.put_in_active_hand(disk))
disk.forceMove(drop_location())
disk = null
@@ -53,10 +57,10 @@
backup.nanites = cloud_copy
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
-/obj/machinery/computer/nanite_cloud_controller/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "NaniteCloudControl", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "NaniteCloudControl", name)
ui.open()
/obj/machinery/computer/nanite_cloud_controller/ui_data()
diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm
index 3f62a11f89..5a330f7a4f 100644
--- a/code/modules/research/nanites/nanite_program_hub.dm
+++ b/code/modules/research/nanites/nanite_program_hub.dm
@@ -3,26 +3,24 @@
desc = "Compiles nanite programs from the techweb servers and downloads them into disks."
icon = 'icons/obj/machines/research.dmi'
icon_state = "nanite_program_hub"
- circuit = /obj/item/circuitboard/machine/nanite_program_hub
use_power = IDLE_POWER_USE
anchored = TRUE
density = TRUE
- ui_x = 500
- ui_y = 700
+ circuit = /obj/item/circuitboard/machine/nanite_program_hub
var/obj/item/disk/nanite_program/disk
var/datum/techweb/linked_techweb
var/current_category = "Main"
var/detail_view = TRUE
var/categories = list(
- list(name = "Utility Nanites"),
- list(name = "Medical Nanites"),
- list(name = "Sensor Nanites"),
- list(name = "Augmentation Nanites"),
- list(name = "Suppression Nanites"),
- list(name = "Weaponized Nanites"),
- list(name = "Protocols") //Moved to default techweb from B.E.P.I.S. research, for now
- )
+ list(name = "Utility Nanites"),
+ list(name = "Medical Nanites"),
+ list(name = "Sensor Nanites"),
+ list(name = "Augmentation Nanites"),
+ list(name = "Suppression Nanites"),
+ list(name = "Weaponized Nanites"),
+ list(name = "Protocols"),
+ )
/obj/machinery/nanite_program_hub/Initialize()
. = ..()
@@ -31,26 +29,44 @@
/obj/machinery/nanite_program_hub/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/disk/nanite_program))
var/obj/item/disk/nanite_program/N = I
- if(disk)
- eject(user)
if(user.transferItemToLoc(N, src))
to_chat(user, "You insert [N] into [src].")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
+ if(disk)
+ eject(user)
disk = N
else
..()
+/obj/machinery/nanite_program_hub/screwdriver_act(mob/living/user, obj/item/I) //remove when runtimed
+ if(..())
+ return TRUE
+
+ return default_deconstruction_screwdriver(user, "nanite_program_hub_t", "nanite_program_hub", I)
+
+/obj/machinery/nanite_program_hub/crowbar_act(mob/living/user, obj/item/I)
+ if(..())
+ return TRUE
+
+ return default_deconstruction_crowbar(I)
+
/obj/machinery/nanite_program_hub/proc/eject(mob/living/user)
if(!disk)
return
- if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
+ if(!istype(user) || !Adjacent(user))// || !user.put_in_active_hand(disk))
disk.forceMove(drop_location())
disk = null
-/obj/machinery/nanite_program_hub/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/nanite_program_hub/AltClick(mob/user)
+ if(disk && user.canUseTopic(src, !issilicon(user)))
+ to_chat(user, "You take out [disk] from [src].")
+ eject(user)
+ return
+
+/obj/machinery/nanite_program_hub/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "NaniteProgramHub", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "NaniteProgramHub", name)
ui.open()
/obj/machinery/nanite_program_hub/ui_data()
@@ -123,9 +139,3 @@
disk.program = null
disk.name = initial(disk.name)
. = TRUE
-
-
-/obj/machinery/nanite_program_hub/admin/Initialize()
- . = ..()
- linked_techweb = SSresearch.admin_tech
-
diff --git a/code/modules/research/nanites/nanite_programmer.dm b/code/modules/research/nanites/nanite_programmer.dm
index 3de2a974e2..804f256cf6 100644
--- a/code/modules/research/nanites/nanite_programmer.dm
+++ b/code/modules/research/nanites/nanite_programmer.dm
@@ -3,41 +3,57 @@
desc = "A device that can edit nanite program disks to adjust their functionality."
var/obj/item/disk/nanite_program/disk
var/datum/nanite_program/program
- circuit = /obj/item/circuitboard/machine/nanite_programmer
icon = 'icons/obj/machines/research.dmi'
icon_state = "nanite_programmer"
use_power = IDLE_POWER_USE
anchored = TRUE
density = TRUE
flags_1 = HEAR_1
- ui_x = 420
- ui_y = 550
+ circuit = /obj/item/circuitboard/machine/nanite_programmer
/obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/disk/nanite_program))
var/obj/item/disk/nanite_program/N = I
- if(disk)
- eject(user)
if(user.transferItemToLoc(N, src))
to_chat(user, "You insert [N] into [src]")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
+ if(disk)
+ eject(user)
disk = N
program = N.program
else
..()
+/obj/machinery/nanite_programmer/screwdriver_act(mob/living/user, obj/item/I)
+ if(..())
+ return TRUE
+
+ return default_deconstruction_screwdriver(user, "nanite_programmer_t", "nanite_programmer", I)
+
+/obj/machinery/nanite_programmer/crowbar_act(mob/living/user, obj/item/I)
+ if(..())
+ return TRUE
+
+ return default_deconstruction_crowbar(I)
+
/obj/machinery/nanite_programmer/proc/eject(mob/living/user)
if(!disk)
return
- if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
+ if(!istype(user) || !Adjacent(user))// || !user.put_in_active_hand(disk))
disk.forceMove(drop_location())
disk = null
program = null
-/obj/machinery/nanite_programmer/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/nanite_programmer/AltClick(mob/user)
+ if(disk && user.canUseTopic(src, !issilicon(user)))
+ to_chat(user, "You take out [disk] from [src].")
+ eject(user)
+ return
+
+/obj/machinery/nanite_programmer/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "NaniteProgrammer", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "NaniteProgrammer", name)
ui.open()
/obj/machinery/nanite_programmer/ui_data()
@@ -131,7 +147,7 @@
program.timer_trigger_delay = timer
. = TRUE
-/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
+/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
var/static/regex/when = regex("(?:^\\W*when|when\\W*$)", "i") //starts or ends with when
if(findtext(raw_message, when) && !istype(speaker, /obj/machinery/nanite_programmer))
diff --git a/code/modules/research/nanites/nanite_programs/utility.dm b/code/modules/research/nanites/nanite_programs/utility.dm
index ebe623d73d..f5372738db 100644
--- a/code/modules/research/nanites/nanite_programs/utility.dm
+++ b/code/modules/research/nanites/nanite_programs/utility.dm
@@ -51,7 +51,7 @@
rogue_types = list(/datum/nanite_program/toxic)
/datum/nanite_program/self_scan/register_extra_settings()
- extra_settings[NES_SCAN_TYPE] = new /datum/nanite_extra_setting/type("Medical", list("Medical", "Chemical", "Nanite"))
+ extra_settings[NES_SCAN_TYPE] = new /datum/nanite_extra_setting/type("Medical", list("Medical", "Chemical", "Wound", "Nanite"))
/datum/nanite_program/self_scan/on_trigger(comm_message)
if(host_mob.stat == DEAD)
@@ -62,6 +62,8 @@
healthscan(host_mob, host_mob)
if("Chemical")
chemscan(host_mob, host_mob)
+ if("Wound")
+ woundscan(host_mob, host_mob)
if("Nanite")
SEND_SIGNAL(host_mob, COMSIG_NANITE_SCAN, host_mob, TRUE)
diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm
index b222b2ad35..e3f5a0f286 100644
--- a/code/modules/research/nanites/nanite_remote.dm
+++ b/code/modules/research/nanites/nanite_remote.dm
@@ -80,10 +80,13 @@
var/datum/nanite_program/relay/N = X
N.relay_signal(code, relay_code, source)
-/obj/item/nanite_remote/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/item/nanite_remote/ui_state(mob/user)
+ return GLOB.hands_state
+
+/obj/item/nanite_remote/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "NaniteRemote", name, 420, 500, master_ui, state)
+ ui = new(user, src, "NaniteRemote", name)
ui.open()
/obj/item/nanite_remote/ui_data()
@@ -94,7 +97,6 @@
data["locked"] = locked
data["saved_settings"] = saved_settings
data["program_name"] = current_program_name
-
return data
/obj/item/nanite_remote/ui_act(action, params)
diff --git a/code/modules/research/nanites/public_chamber.dm b/code/modules/research/nanites/public_chamber.dm
index 76392c66e9..b7a8db4080 100644
--- a/code/modules/research/nanites/public_chamber.dm
+++ b/code/modules/research/nanites/public_chamber.dm
@@ -130,8 +130,6 @@
return
if(busy)
return
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the door of [src]!", \
"You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
diff --git a/code/modules/research/techweb/nodes/medical_nodes.dm b/code/modules/research/techweb/nodes/medical_nodes.dm
index a2fba1741a..02562f941e 100644
--- a/code/modules/research/techweb/nodes/medical_nodes.dm
+++ b/code/modules/research/techweb/nodes/medical_nodes.dm
@@ -121,7 +121,7 @@
display_name = "Advanced Surgery Tools"
description = "Refined and improved redesigns for the run-of-the-mill medical utensils."
prereq_ids = list("adv_biotech", "adv_surgery")
- design_ids = list("drapes", "retractor_adv", "surgicaldrill_adv", "scalpel_adv")
+ design_ids = list("drapes", "retractor_adv", "surgicaldrill_adv", "scalpel_adv", "bonesetter", "surgical_tape")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/adv_surgery
diff --git a/code/modules/research/techweb/nodes/tools_nodes.dm b/code/modules/research/techweb/nodes/tools_nodes.dm
index b084979116..180cdb5778 100644
--- a/code/modules/research/techweb/nodes/tools_nodes.dm
+++ b/code/modules/research/techweb/nodes/tools_nodes.dm
@@ -44,7 +44,7 @@
id = "exp_tools"
display_name = "Experimental Tools"
description = "Highly advanced construction tools."
- design_ids = list("exwelder", "jawsoflife", "handdrill", "holosigncombifan")
+ design_ids = list("exwelder", "jawsoflife", "handdrill", "holosigncombifan", "ranged_analyzer")
prereq_ids = list("adv_engi")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750)
diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
index 996b84131f..1ac09652b5 100644
--- a/code/modules/research/xenobiology/crossbreeding/_clothing.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
@@ -57,7 +57,7 @@ Slimecrossing Armor
light_color = newcolor
set_light(5)
-/obj/structure/light_prism/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/light_prism/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
to_chat(user, "You dispel [src]")
qdel(src)
@@ -118,7 +118,7 @@ Slimecrossing Armor
..()
REMOVE_TRAIT(user, TRAIT_PACIFISM, "peaceflower_[REF(src)]")
-/obj/item/clothing/head/peaceflower/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/clothing/head/peaceflower/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(iscarbon(user))
var/mob/living/carbon/C = user
if(src == C.head)
diff --git a/code/modules/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/ruins/lavalandruin_code/elephantgraveyard.dm
index 65530031c0..088683ccd2 100644
--- a/code/modules/ruins/lavalandruin_code/elephantgraveyard.dm
+++ b/code/modules/ruins/lavalandruin_code/elephantgraveyard.dm
@@ -73,7 +73,7 @@
create_reagents(20)
reagents.add_reagent(dispensedreagent, 20)
-/obj/structure/sink/oil_well/attack_hand(mob/M)
+/obj/structure/sink/oil_well/on_attack_hand(mob/M)
flick("puddle-oil-splash",src)
reagents.reaction(M, TOUCH, 20) //Covers target in 20u of oil.
to_chat(M, "You touch the pool of oil, only to get oil all over yourself. It would be wise to wash this off with water.")
diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm
index e6f87eea13..fd2f4377e7 100644
--- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm
+++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm
@@ -87,8 +87,7 @@
else
return QDEL_HINT_LETMELIVE
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/structure/necropolis_gate/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/necropolis_gate/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(locked || uses == 0)
to_chat(user, "It's [open ? "stuck open":"locked"].")
return
@@ -166,8 +165,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
else
return QDEL_HINT_LETMELIVE
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/necropolis_gate/legion_gate/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!open && !changing_openness)
var/safety = alert(user, "You think this might be a bad idea...", "Knock on the door?", "Proceed", "Abort")
if(safety == "Abort" || !in_range(src, user) || !src || open || changing_openness || user.incapacitated())
diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm
index 8a98a1939f..e87382cd6a 100644
--- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm
+++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm
@@ -57,7 +57,7 @@
canvas rotting away and contents vanishing.")
qdel(src)
-/obj/structure/cursed_money/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/structure/cursed_money/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
diff --git a/code/modules/ruins/spaceruin_code/TheDerelict.dm b/code/modules/ruins/spaceruin_code/TheDerelict.dm
index 513d16a0cb..d26e023df0 100644
--- a/code/modules/ruins/spaceruin_code/TheDerelict.dm
+++ b/code/modules/ruins/spaceruin_code/TheDerelict.dm
@@ -17,7 +17,6 @@
desc = "Looks like someone started shakily writing a will in space common, but were interrupted by something bloody..."
info = "__Objectives #1__: Find out what is hidden in Kosmicheskaya Stantsiya 13s Vault"
-
/// Vault controller for use on the derelict/KS13.
/obj/machinery/computer/vaultcontroller
name = "vault controller"
@@ -35,15 +34,10 @@
var/siphoned_power = 0
var/siphon_max = 1e7
- ui_x = 300
- ui_y = 120
-
-
/obj/machinery/computer/monitor/examine(mob/user)
. = ..()
. += "It appears to be powered via a cable connector."
-
//Checks for cable connection, charges if possible.
/obj/machinery/computer/vaultcontroller/process()
if(siphoned_power >= siphon_max)
@@ -52,13 +46,11 @@
if(attached_cable)
attempt_siphon()
-
///Looks for a cable connection beneath the machine.
/obj/machinery/computer/vaultcontroller/proc/update_cable()
var/turf/T = get_turf(src)
attached_cable = locate(/obj/structure/cable) in T
-
///Initializes airlock links.
/obj/machinery/computer/vaultcontroller/proc/find_airlocks()
for(var/obj/machinery/door/airlock/A in GLOB.airlocks)
@@ -70,7 +62,6 @@
door2 = A
break
-
///Tries to charge from powernet excess, no upper limit except max charge.
/obj/machinery/computer/vaultcontroller/proc/attempt_siphon()
var/surpluspower = clamp(attached_cable.surplus(), 0, (siphon_max - siphoned_power))
@@ -78,7 +69,6 @@
attached_cable.add_load(surpluspower)
siphoned_power += surpluspower
-
///Handles the doors closing
/obj/machinery/computer/vaultcontroller/proc/cycle_close(obj/machinery/door/airlock/A)
A.safe = FALSE //Make sure its forced closed, always
@@ -86,14 +76,12 @@
A.close()
A.bolt()
-
///Handles the doors opening
/obj/machinery/computer/vaultcontroller/proc/cycle_open(obj/machinery/door/airlock/A)
A.unbolt()
A.open()
A.bolt()
-
///Attempts to lock the vault doors
/obj/machinery/computer/vaultcontroller/proc/lock_vault()
if(door1 && !door1.density)
@@ -103,7 +91,6 @@
if(door1.density && door1.locked && door2.density && door2.locked)
locked = TRUE
-
///Attempts to unlock the vault doors
/obj/machinery/computer/vaultcontroller/proc/unlock_vault()
if(door1 && door1.density)
@@ -113,7 +100,6 @@
if(!door1.density && door1.locked && !door2.density && door2.locked)
locked = FALSE
-
///Attempts to lock/unlock vault doors, if machine is charged.
/obj/machinery/computer/vaultcontroller/proc/activate_lock()
if(siphoned_power < siphon_max)
@@ -125,15 +111,12 @@
else
lock_vault()
-
-/obj/machinery/computer/vaultcontroller/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/vaultcontroller/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "VaultController", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "VaultController", name)
ui.open()
-
/obj/machinery/computer/vaultcontroller/ui_act(action, params)
if(..())
return
@@ -141,7 +124,6 @@
if("togglelock")
activate_lock()
-
/obj/machinery/computer/vaultcontroller/ui_data()
var/list/data = list()
data["stored"] = siphoned_power
@@ -149,7 +131,6 @@
data["doorstatus"] = locked
return data
-
///Airlock that can't be deconstructed, broken or hacked.
/obj/machinery/door/airlock/vault/derelict
locked = TRUE
@@ -158,16 +139,13 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
id_tag = "derelictvault"
-
///Overrides screwdriver attack to prevent all deconstruction and hacking.
/obj/machinery/door/airlock/vault/derelict/attackby(obj/item/C, mob/user, params)
if(C.tool_behaviour == TOOL_SCREWDRIVER)
return
..()
-
// So drones can teach borgs and AI dronespeak. For best effect, combine with mother drone lawset.
-
/obj/item/dronespeak_manual
name = "dronespeak manual"
desc = "The book's cover reads: \"Understanding Dronespeak - An exercise in futility.\""
@@ -181,7 +159,7 @@
to_chat(user, "You start skimming through [src], but you already know dronespeak.")
else
to_chat(user, "You start skimming through [src], and suddenly the drone chittering makes sense.")
- user.grant_language(/datum/language/drone, TRUE, TRUE)
+ user.grant_language(/datum/language/drone, TRUE, TRUE)//, LANGUAGE_MIND)
return
if(user.has_language(/datum/language/drone))
@@ -202,7 +180,7 @@
M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.")
else
M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], chitters resonate in your mind.", "You hear smacking.")
- M.grant_language(/datum/language/drone, TRUE, TRUE)
+ M.grant_language(/datum/language/drone, TRUE, TRUE) //, LANGUAGE_MIND)
return
/obj/structure/fluff/oldturret
diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
index b74b32009f..d97eae5766 100644
--- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
@@ -263,7 +263,7 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337)
/turf/closed/indestructible/hoteldoor/attack_tk(mob/user)
return //need to be close.
-/turf/closed/indestructible/hoteldoor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/turf/closed/indestructible/hoteldoor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
promptExit(user)
/turf/closed/indestructible/hoteldoor/attack_animal(mob/user)
diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm
index f6418b9236..7326cad816 100644
--- a/code/modules/security_levels/keycard_authentication.dm
+++ b/code/modules/security_levels/keycard_authentication.dm
@@ -35,11 +35,13 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
QDEL_NULL(ev)
return ..()
-/obj/machinery/keycard_auth/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)
+/obj/machinery/keycard_auth/ui_state(mob/user)
+ return GLOB.physical_state
+
+/obj/machinery/keycard_auth/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "KeycardAuth", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "KeycardAuth", name)
ui.open()
/obj/machinery/keycard_auth/ui_data()
diff --git a/code/modules/shuttle/custom_shuttle.dm b/code/modules/shuttle/custom_shuttle.dm
index 6ff15c628e..c71b6ba9a8 100644
--- a/code/modules/shuttle/custom_shuttle.dm
+++ b/code/modules/shuttle/custom_shuttle.dm
@@ -257,7 +257,7 @@
return
..()
-/obj/machinery/computer/camera_advanced/shuttle_docker/custom/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/computer/camera_advanced/shuttle_docker/custom/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!shuttleId)
to_chat(user, "You must link the console to a shuttle first.")
return
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 637d9ae334..810cadcd2c 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -45,11 +45,14 @@
say("Please equip your ID card into your ID slot to authenticate.")
. = ..()
-/obj/machinery/computer/emergency_shuttle/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.human_adjacent_state)
+/obj/machinery/computer/emergency_shuttle/ui_state(mob/user)
+ return GLOB.human_adjacent_state
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/emergency_shuttle/ui_interact(mob/user, datum/tgui/ui)
+
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "EmergencyShuttleConsole", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "EmergencyShuttleConsole", name)
ui.open()
/obj/machinery/computer/emergency_shuttle/ui_data()
@@ -65,8 +68,8 @@
var/job = ID.assignment
if(obj_flags & EMAGGED)
- name = Gibberish(name, 0)
- job = Gibberish(job, 0)
+ name = Gibberish(name)
+ job = Gibberish(job)
A += list(list("name" = name, "job" = job))
data["authorizations"] = A
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 0cf348a95b..195e87720c 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -29,7 +29,7 @@
. = ..()
GLOB.navigation_computers -= src
-/obj/machinery/computer/camera_advanced/shuttle_docker/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/computer/camera_advanced/shuttle_docker/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(jammed)
to_chat(user, "The Syndicate is jamming the console!")
return
diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm
index 9af6d7fe9f..314d5e8b80 100644
--- a/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm
+++ b/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm
@@ -61,7 +61,7 @@
if(user?.client)
user.client.images -= eyeobj.user_image
-/obj/machinery/computer/camera_advanced/shuttle_creator/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/computer/camera_advanced/shuttle_creator/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!is_operational()) //you cant use broken machine you chumbis
return
if(current_user)
diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm
index 440e6cb03b..0076f584e9 100644
--- a/code/modules/shuttle/syndicate.dm
+++ b/code/modules/shuttle/syndicate.dm
@@ -1,4 +1,4 @@
-#define SYNDICATE_CHALLENGE_TIMER 12000 //20 minutes
+#define SYNDICATE_CHALLENGE_TIMER 9000 // 15 minutes
/obj/machinery/computer/shuttle/syndicate
name = "syndicate shuttle terminal"
@@ -21,8 +21,8 @@
/obj/machinery/computer/shuttle/syndicate/Topic(href, href_list)
if(href_list["move"])
var/obj/item/circuitboard/computer/syndicate_shuttle/board = circuit
- if(board.challenge && world.time < SYNDICATE_CHALLENGE_TIMER)
- to_chat(usr, "You've issued a combat challenge to the station! You've got to give them at least [DisplayTimeText(SYNDICATE_CHALLENGE_TIMER - world.time)] more to allow them to prepare.")
+ if(board.challenge && ((world.time - SSticker.round_start_time) < SYNDICATE_CHALLENGE_TIMER))
+ to_chat(usr, "You've issued a combat challenge to the station! You've got to give them at least [DisplayTimeText(SYNDICATE_CHALLENGE_TIMER - (world.time - SSticker.round_start_time))] more to allow them to prepare.")
return 0
board.moved = TRUE
..()
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 21552f7e87..57502e2cd5 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -56,11 +56,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
to_chat(caller, "[caller.ranged_ability.name] has been disabled.")
caller.ranged_ability.remove_ranged_ability()
return TRUE //TRUE for failed, FALSE for passed.
- if(ranged_clickcd_override >= 0)
- ranged_ability_user.next_click = world.time + ranged_clickcd_override
- else
- ranged_ability_user.next_click = world.time + CLICK_CD_CLICK_ABILITY
- ranged_ability_user.face_atom(A)
return FALSE
/obj/effect/proc_holder/proc/add_ranged_ability(mob/living/user, msg, forced)
diff --git a/code/modules/spells/spell_types/bloodcrawl.dm b/code/modules/spells/spell_types/bloodcrawl.dm
index e59fc2049d..39b0f1709e 100644
--- a/code/modules/spells/spell_types/bloodcrawl.dm
+++ b/code/modules/spells/spell_types/bloodcrawl.dm
@@ -25,6 +25,11 @@
/obj/effect/proc_holder/spell/bloodcrawl/perform(obj/effect/decal/cleanable/target, recharge = 1, mob/living/user = usr)
if(istype(user))
+ if(istype(user, /mob/living/simple_animal/slaughter))
+ var/mob/living/simple_animal/slaughter/slaught = user
+ slaught.current_hitstreak = 0
+ slaught.wound_bonus = initial(slaught.wound_bonus)
+ slaught.bare_wound_bonus = initial(slaught.bare_wound_bonus)
if(phased)
if(user.phasein(target))
phased = 0
diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm
index a8f9c8bce5..e513865246 100644
--- a/code/modules/spells/spell_types/shapeshift.dm
+++ b/code/modules/spells/spell_types/shapeshift.dm
@@ -105,7 +105,7 @@
var/damage_percent = (stored.maxHealth - stored.health)/stored.maxHealth;
var/damapply = damage_percent * shape.maxHealth;
- shape.apply_damage(damapply, source.convert_damage_type, forced = TRUE);
+ shape.apply_damage(damapply, source.convert_damage_type, forced = TRUE, wound_bonus=CANT_WOUND);
slink = soullink(/datum/soullink/shapeshift, stored , shape)
slink.source = src
@@ -158,7 +158,7 @@
var/damage_percent = (shape.maxHealth - shape.health)/shape.maxHealth;
var/damapply = stored.maxHealth * damage_percent
- stored.apply_damage(damapply, source.convert_damage_type, forced = TRUE)
+ stored.apply_damage(damapply, source.convert_damage_type, forced = TRUE, wound_bonus=CANT_WOUND)
qdel(shape)
qdel(src)
diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm
index bec0f7871a..5797cbf8b7 100644
--- a/code/modules/spells/spell_types/spacetime_distortion.dm
+++ b/code/modules/spells/spell_types/spacetime_distortion.dm
@@ -110,8 +110,7 @@
else
walk_link(user)
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/effect/cross_action/spacetime_dist/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
walk_link(user)
/obj/effect/cross_action/spacetime_dist/attack_paw(mob/user)
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index 2ca0e65477..4c3f30a786 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -210,20 +210,23 @@
/obj/machinery/computer/bsa_control
name = "bluespace artillery control"
- var/obj/machinery/bsa/full/cannon
- var/notice
- var/target
use_power = NO_POWER_USE
circuit = /obj/item/circuitboard/computer/bsa_control
icon = 'icons/obj/machines/particle_accelerator.dmi'
icon_state = "control_boxp"
+
+ var/obj/machinery/bsa/full/cannon
+ var/notice
+ var/target
var/area_aim = FALSE //should also show areas for targeting
-/obj/machinery/computer/bsa_control/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)
+/obj/machinery/computer/bsa_control/ui_state(mob/user)
+ return GLOB.physical_state
+
+/obj/machinery/computer/bsa_control/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "BluespaceArtillery", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "BluespaceArtillery", name)
ui.open()
/obj/machinery/computer/bsa_control/ui_data()
@@ -255,7 +258,7 @@
if(!GLOB.bsa_unlock)
return
var/list/gps_locators = list()
- for(var/obj/item/gps/G in GLOB.GPS_list) //nulls on the list somehow
+ for(var/datum/component/gps/G in GLOB.GPS_list) //nulls on the list somehow
if(G.tracking)
gps_locators[G.gpstag] = G
diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm
index 40fb066fe1..4ac3777a41 100644
--- a/code/modules/station_goals/dna_vault.dm
+++ b/code/modules/station_goals/dna_vault.dm
@@ -174,14 +174,13 @@
. = ..()
-/obj/machinery/dna_vault/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)
+/obj/machinery/dna_vault/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
roll_powers(user)
- ui = new(user, src, ui_key, "DnaVault", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "DnaVault", name)
ui.open()
-
/obj/machinery/dna_vault/proc/roll_powers(mob/user)
if(user in power_lottery)
return
@@ -279,5 +278,5 @@
H.add_movespeed_modifier(/datum/movespeed_modifier/dna_vault_speedup)
if(VAULT_QUICK)
to_chat(H, "Your arms move as fast as lightning.")
- H.next_move_modifier = 0.5
+ H.action_cooldown_mod = 0.5
power_lottery[H] = list()
diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm
index 299fda4a26..c8fbda8988 100644
--- a/code/modules/station_goals/shield.dm
+++ b/code/modules/station_goals/shield.dm
@@ -42,10 +42,10 @@
circuit = /obj/item/circuitboard/computer/sat_control
var/notice
-/obj/machinery/computer/sat_control/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)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/sat_control/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "SatelliteControl", name, ui_x, ui_y, master_ui, state)
+ ui = new(user, src, "SatelliteControl", name)
ui.open()
/obj/machinery/computer/sat_control/ui_act(action, params)
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
similarity index 53%
rename from code/modules/surgery/bodyparts/bodyparts.dm
rename to code/modules/surgery/bodyparts/_bodyparts.dm
index fcdb07ca17..3d88282937 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -71,6 +71,28 @@
var/medium_burn_msg = "blistered"
var/heavy_burn_msg = "peeling away"
+ /// The wounds currently afflicting this body part
+ var/list/wounds
+
+ /// The scars currently afflicting this body part
+ var/list/scars
+ /// Our current stored wound damage multiplier
+ var/wound_damage_multiplier = 1
+
+ /// This number is subtracted from all wound rolls on this bodypart, higher numbers mean more defense, negative means easier to wound
+ var/wound_resistance = 0
+ /// When this bodypart hits max damage, this number is added to all wound rolls. Obviously only relevant for bodyparts that have damage caps.
+ var/disabled_wound_penalty = 15
+
+ /// A hat won't cover your face, but a shirt covering your chest will cover your... you know, chest
+ var/scars_covered_by_clothes = TRUE
+ /// So we know if we need to scream if this limb hits max damage
+ var/last_maxed
+ /// How much generic bleedstacks we have on this bodypart
+ var/generic_bleedstacks
+ /// If we have a gauze wrapping currently applied (not including splints)
+ var/obj/item/stack/current_gauze
+
/obj/item/bodypart/examine(mob/user)
. = ..()
if(brute_dam > DAMAGE_PRECISION)
@@ -129,8 +151,20 @@
var/turf/T = get_turf(src)
if(status != BODYPART_ROBOTIC)
playsound(T, 'sound/misc/splort.ogg', 50, 1, -1)
- for(var/obj/item/I in src)
- I.forceMove(T)
+ if(current_gauze)
+ QDEL_NULL(current_gauze)
+ for(var/obj/item/organ/drop_organ in get_organs())
+ drop_organ.transfer_to_limb(src, owner)
+
+///since organs aren't actually stored in the bodypart themselves while attached to a person, we have to query the owner for what we should have
+/obj/item/bodypart/proc/get_organs()
+ if(!owner)
+ return
+ . = list()
+ for(var/i in owner.internal_organs) //internal organs inside the dismembered limb are dropped.
+ var/obj/item/organ/organ_check = i
+ if(check_zone(organ_check.zone) == body_zone)
+ . += organ_check
/obj/item/bodypart/proc/consider_processing()
if(stamina_dam > DAMAGE_PRECISION)
@@ -149,7 +183,7 @@
//Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all.
//Damage will not exceed max_damage using this proc
//Cannot apply negative damage
-/obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
+/obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, blocked = 0, updating_health = TRUE, required_status = null, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE) // maybe separate BRUTE_SHARP and BRUTE_OTHER eventually somehow hmm
if(owner && (owner.status_flags & GODMODE))
return FALSE //godmode
var/dmg_mlt = CONFIG_GET(number/damage_multiplier)
@@ -163,20 +197,82 @@
if(!brute && !burn && !stamina)
return FALSE
+ brute *= wound_damage_multiplier
+ burn *= wound_damage_multiplier
+
switch(animal_origin)
if(ALIEN_BODYPART,LARVA_BODYPART) //aliens take some additional burn //nothing can burn with so much snowflake code around
burn *= 1.2
+ /*
+ // START WOUND HANDLING
+ */
+
+ // what kind of wounds we're gonna roll for, take the greater between brute and burn, then if it's brute, we subdivide based on sharpness
+ var/wounding_type = (brute > burn ? WOUND_BLUNT : WOUND_BURN)
+ var/wounding_dmg = max(brute, burn)
+ var/mangled_state = get_mangled_state()
+ var/bio_state = owner.get_biological_state()
+ var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%)
+
+ if(wounding_type == WOUND_BLUNT)
+ if(sharpness == SHARP_EDGED)
+ wounding_type = WOUND_SLASH
+ else if(sharpness == SHARP_POINTY)
+ wounding_type = WOUND_PIERCE
+
+ //Handling for bone only/flesh only(none right now)/flesh and bone targets
+ switch(bio_state)
+ // if we're bone only, all cutting attacks go straight to the bone
+ if(BIO_JUST_BONE)
+ if(wounding_type == WOUND_SLASH)
+ wounding_type = WOUND_BLUNT
+ wounding_dmg *= (easy_dismember ? 1 : 0.5)
+ else if(wounding_type == WOUND_PIERCE)
+ wounding_type = WOUND_BLUNT
+ wounding_dmg *= (easy_dismember ? 1 : 0.75)
+ if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+ // note that there's no handling for BIO_JUST_FLESH since we don't have any that are that right now (slimepeople maybe someday)
+ // standard humanoids
+ if(BIO_FLESH_BONE)
+ // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
+ // So a big sharp weapon is still all you need to destroy a limb
+ if(mangled_state == BODYPART_MANGLED_FLESH && sharpness)
+ playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
+ if(wounding_type == WOUND_SLASH && !easy_dismember)
+ wounding_dmg *= 0.5 // edged weapons pass along 50% of their wounding damage to the bone since the power is spread out over a larger area
+ if(wounding_type == WOUND_PIERCE && !easy_dismember)
+ wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
+ wounding_type = WOUND_BLUNT
+ else if(mangled_state == BODYPART_MANGLED_BOTH && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+
+ // now we have our wounding_type and are ready to carry on with wounds and dealing the actual damage
+ if(owner && wounding_dmg >= WOUND_MINIMUM_DAMAGE && wound_bonus != CANT_WOUND)
+ check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
+
+ for(var/i in wounds)
+ var/datum/wound/iter_wound = i
+ iter_wound.receive_damage(wounding_type, wounding_dmg, wound_bonus)
+
+ /*
+ // END WOUND HANDLING
+ */
+
+ //back to our regularly scheduled program, we now actually apply damage if there's room below limb damage cap
+
var/can_inflict = max_damage - get_damage()
- if(can_inflict <= 0)
- return FALSE
var/total_damage = brute + burn
- if(total_damage > can_inflict)
+ if(total_damage > can_inflict && total_damage > 0) // TODO: the second part of this check should be removed once disabling is all done
brute = round(brute * (max_damage / total_damage),DAMAGE_PRECISION)
burn = round(burn * (max_damage / total_damage),DAMAGE_PRECISION)
+ if(can_inflict <= 0)
+ return FALSE
+
brute_dam += brute
burn_dam += burn
@@ -196,6 +292,165 @@
update_disabled()
return update_bodypart_damage_state()
+/// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds
+/obj/item/bodypart/proc/painless_wound_roll(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=SHARP_NONE)
+ if(!owner || phantom_wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND)
+ return
+
+ var/mangled_state = get_mangled_state()
+ var/bio_state = owner.get_biological_state()
+ var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%)
+
+ if(wounding_type == WOUND_BLUNT)
+ if(sharpness == SHARP_EDGED)
+ wounding_type = WOUND_SLASH
+ else if(sharpness == SHARP_POINTY)
+ wounding_type = WOUND_PIERCE
+
+ //Handling for bone only/flesh only(none right now)/flesh and bone targets
+ switch(bio_state)
+ // if we're bone only, all cutting attacks go straight to the bone
+ if(BIO_JUST_BONE)
+ if(wounding_type == WOUND_SLASH)
+ wounding_type = WOUND_BLUNT
+ phantom_wounding_dmg *= (easy_dismember ? 1 : 0.5)
+ else if(wounding_type == WOUND_PIERCE)
+ wounding_type = WOUND_BLUNT
+ phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75)
+ if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+ // note that there's no handling for BIO_JUST_FLESH since we don't have any that are that right now (slimepeople maybe someday)
+ // standard humanoids
+ if(BIO_FLESH_BONE)
+ // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
+ // So a big sharp weapon is still all you need to destroy a limb
+ if(mangled_state == BODYPART_MANGLED_FLESH && sharpness)
+ playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
+ if(wounding_type == WOUND_SLASH && !easy_dismember)
+ phantom_wounding_dmg *= 0.5 // edged weapons pass along 50% of their wounding damage to the bone since the power is spread out over a larger area
+ if(wounding_type == WOUND_PIERCE && !easy_dismember)
+ phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
+ wounding_type = WOUND_BLUNT
+ else if(mangled_state == BODYPART_MANGLED_BOTH && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+
+ check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)
+
+/**
+ * check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria
+ *
+ * We generate a "score" for how woundable the attack was based on the damage and other factors discussed in [/obj/item/bodypart/proc/check_wounding_mods], then go down the list from most severe to least severe wounds in that category.
+ * We can promote a wound from a lesser to a higher severity this way, but we give up if we have a wound of the given type and fail to roll a higher severity, so no sidegrades/downgrades
+ *
+ * Arguments:
+ * * woundtype- Either WOUND_BLUNT, WOUND_SLASH, WOUND_PIERCE, or WOUND_BURN based on the attack type.
+ * * damage- How much damage is tied to this attack, since wounding potential scales with damage in an attack (see: WOUND_DAMAGE_EXPONENT)
+ * * wound_bonus- The wound_bonus of an attack
+ * * bare_wound_bonus- The bare_wound_bonus of an attack
+ */
+/obj/item/bodypart/proc/check_wounding(woundtype, damage, wound_bonus, bare_wound_bonus)
+ // actually roll wounds if applicable
+ if(HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE))
+ damage *= 1.5
+ else
+ damage = min(damage, WOUND_MAX_CONSIDERED_DAMAGE)
+
+ var/base_roll = rand(max(damage/1.5,25), round(damage ** WOUND_DAMAGE_EXPONENT))
+ var/injury_roll = base_roll
+ injury_roll += check_woundings_mods(woundtype, damage, wound_bonus, bare_wound_bonus)
+ var/list/wounds_checking = GLOB.global_wound_types[woundtype]
+
+ // quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow
+ if(ishuman(owner))
+ var/mob/living/carbon/human/human_wearer = owner
+ var/list/clothing = human_wearer.clothingonpart(src)
+ for(var/i in clothing)
+ var/obj/item/clothing/clothes_check = i
+ // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary
+ if(clothes_check.armor.getRating("wound"))
+ bare_wound_bonus = 0
+ break
+
+ //cycle through the wounds of the relevant category from the most severe down
+ for(var/PW in wounds_checking)
+ var/datum/wound/possible_wound = PW
+ var/datum/wound/replaced_wound
+ for(var/i in wounds)
+ var/datum/wound/existing_wound = i
+ if(existing_wound.type in wounds_checking)
+ if(existing_wound.severity >= initial(possible_wound.severity))
+ return
+ else
+ replaced_wound = existing_wound
+
+ if(initial(possible_wound.threshold_minimum) < injury_roll)
+ var/datum/wound/new_wound
+ if(replaced_wound)
+ new_wound = replaced_wound.replace_wound(possible_wound)
+ log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned
+ else
+ new_wound = new possible_wound
+ new_wound.apply_wound(src)
+ log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll)
+ return new_wound
+
+// try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart
+/obj/item/bodypart/proc/force_wound_upwards(specific_woundtype, smited = FALSE)
+ var/datum/wound/potential_wound = specific_woundtype
+ for(var/i in wounds)
+ var/datum/wound/existing_wound = i
+ if(existing_wound.wound_type == initial(potential_wound.wound_type))
+ if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force
+ existing_wound.replace_wound(potential_wound, smited)
+ return
+
+ var/datum/wound/new_wound = new potential_wound
+ new_wound.apply_wound(src, smited = smited)
+
+/**
+ * check_wounding_mods() is where we handle the various modifiers of a wound roll
+ *
+ * A short list of things we consider: any armor a human target may be wearing, and if they have no wound armor on the limb, if we have a bare_wound_bonus to apply, plus the plain wound_bonus
+ * We also flick through all of the wounds we currently have on this limb and add their threshold penalties, so that having lots of bad wounds makes you more liable to get hurt worse
+ * Lastly, we add the inherent wound_resistance variable the bodypart has (heads and chests are slightly harder to wound), and a small bonus if the limb is already disabled
+ *
+ * Arguments:
+ * * It's the same ones on [receive_damage]
+ */
+/obj/item/bodypart/proc/check_woundings_mods(wounding_type, damage, wound_bonus, bare_wound_bonus)
+ var/armor_ablation = 0
+ var/injury_mod = 0
+
+ if(owner && ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ var/list/clothing = H.clothingonpart(src)
+ for(var/c in clothing)
+ var/obj/item/clothing/C = c
+ // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary
+ armor_ablation += C.armor.getRating("wound")
+ if(wounding_type == WOUND_SLASH)
+ C.take_damage_zone(body_zone, damage, BRUTE, armour_penetration)
+ else if(wounding_type == WOUND_BURN && damage >= 10) // lazy way to block freezing from shredding clothes without adding another var onto apply_damage()
+ C.take_damage_zone(body_zone, damage, BURN, armour_penetration)
+
+ if(!armor_ablation)
+ injury_mod += bare_wound_bonus
+
+ injury_mod -= armor_ablation
+ injury_mod += wound_bonus
+
+ for(var/thing in wounds)
+ var/datum/wound/W = thing
+ injury_mod += W.threshold_penalty
+
+ var/part_mod = -wound_resistance
+ if(get_damage(TRUE) >= max_damage)
+ part_mod += disabled_wound_penalty
+
+ injury_mod += part_mod
+
+ return injury_mod
+
//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
//Damage cannot go below zero.
//Cannot remove negative damage (i.e. apply damage)
@@ -227,16 +482,29 @@
//Checks disabled status thresholds
/obj/item/bodypart/proc/update_disabled()
+ if(!owner)
+ return
set_disabled(is_disabled())
/obj/item/bodypart/proc/is_disabled()
+ if(!owner)
+ return
if(HAS_TRAIT(owner, TRAIT_PARALYSIS))
return BODYPART_DISABLED_PARALYSIS
+ for(var/i in wounds)
+ var/datum/wound/W = i
+ if(W.disabling)
+ return BODYPART_DISABLED_WOUND
if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NODISMEMBER))
. = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled
- if((get_damage(TRUE) >= max_damage) || (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) && (get_damage(TRUE) >= (max_damage * 0.6)))) //Easy limb disable disables the limb at 40% health instead of 0%
- return BODYPART_DISABLED_DAMAGE
- if(disabled && (get_damage(TRUE) <= (max_damage * 0.5)))
+ if(get_damage(TRUE) >= max_damage * (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) ? 0.6 : 1)) //Easy limb disable disables the limb at 40% health instead of 0%
+ if(!last_maxed)
+ owner.emote("scream")
+ last_maxed = TRUE
+ if(!is_organic_limb() || stamina_dam >= max_damage)
+ return BODYPART_DISABLED_DAMAGE
+ else if(disabled && (get_damage(TRUE) <= (max_damage * 0.8))) // reenabled at 80% now instead of 50% as of wounds update
+ last_maxed = FALSE
return BODYPART_NOT_DISABLED
else
return BODYPART_NOT_DISABLED
@@ -251,9 +519,11 @@
/obj/item/bodypart/proc/set_disabled(new_disabled)
- if(disabled == new_disabled)
+ if(disabled == new_disabled || !owner)
return FALSE
disabled = new_disabled
+ if(disabled && owner.get_item_for_held_index(held_index))
+ owner.dropItemToGround(owner.get_item_for_held_index(held_index))
owner.update_health_hud() //update the healthdoll
owner.update_body()
owner.update_mobility()
@@ -334,9 +604,9 @@
//body marking memes
var/list/colorlist = list()
colorlist.Cut()
- colorlist += ReadRGB("[H.dna.features["mcolor"]]0")
- colorlist += ReadRGB("[H.dna.features["mcolor2"]]0")
- colorlist += ReadRGB("[H.dna.features["mcolor3"]]0")
+ colorlist += ReadRGB("[H.dna.features["mcolor"]]00")
+ colorlist += ReadRGB("[H.dna.features["mcolor2"]]00")
+ colorlist += ReadRGB("[H.dna.features["mcolor3"]]00")
colorlist += list(0,0,0, S.hair_alpha)
for(var/index=1, index<=colorlist.len, index++)
colorlist[index] = colorlist[index]/255
@@ -581,293 +851,86 @@
drop_organs()
qdel(src)
-/obj/item/bodypart/chest
- name = BODY_ZONE_CHEST
- desc = "It's impolite to stare at a person's chest."
- icon_state = "default_human_chest"
- max_damage = 200
- body_zone = BODY_ZONE_CHEST
- body_part = CHEST
- px_x = 0
- px_y = 0
- stam_damage_coeff = 1
- max_stamina_damage = 200
- var/obj/item/cavity_item
-
-/obj/item/bodypart/chest/can_dismember(obj/item/I)
- if(!((owner.stat == DEAD) || owner.InFullCritical()))
- return FALSE
- return ..()
-
-/obj/item/bodypart/chest/Destroy()
- if(cavity_item)
- qdel(cavity_item)
- return ..()
-
-/obj/item/bodypart/chest/drop_organs(mob/user)
- if(cavity_item)
- cavity_item.forceMove(user.loc)
- cavity_item = null
- ..()
-
-/obj/item/bodypart/chest/monkey
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "default_monkey_chest"
- animal_origin = MONKEY_BODYPART
-
-/obj/item/bodypart/chest/alien
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "alien_chest"
- dismemberable = 0
- max_damage = 500
- animal_origin = ALIEN_BODYPART
-
-/obj/item/bodypart/chest/devil
- dismemberable = 0
- max_damage = 5000
- animal_origin = DEVIL_BODYPART
-
-/obj/item/bodypart/chest/larva
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "larva_chest"
- dismemberable = 0
- max_damage = 50
- animal_origin = LARVA_BODYPART
-
-/obj/item/bodypart/l_arm
- name = "left arm"
- desc = "Did you know that the word 'sinister' stems originally from the \
- Latin 'sinestra' (left hand), because the left hand was supposed to \
- be possessed by the devil? This arm appears to be possessed by no \
- one though."
- icon_state = "default_human_l_arm"
- attack_verb = list("slapped", "punched")
- max_damage = 50
- max_stamina_damage = 50
- body_zone = BODY_ZONE_L_ARM
- body_part = ARM_LEFT
- aux_icons = list(BODY_ZONE_PRECISE_L_HAND = HANDS_PART_LAYER, "l_hand_behind" = BODY_BEHIND_LAYER)
- body_damage_coeff = 0.75
- held_index = 1
- px_x = -6
- px_y = 0
- stam_heal_tick = STAM_RECOVERY_LIMB
-
-/obj/item/bodypart/l_arm/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
-
-/obj/item/bodypart/l_arm/set_disabled(new_disabled)
- . = ..()
- if(!.)
+/// Get whatever wound of the given type is currently attached to this limb, if any
+/obj/item/bodypart/proc/get_wound_type(checking_type)
+ if(isnull(wounds))
return
- if(owner.stat < UNCONSCIOUS)
- switch(disabled)
- if(BODYPART_DISABLED_DAMAGE)
- owner.emote("scream")
- to_chat(owner, "Your [name] is too damaged to function!")
- if(BODYPART_DISABLED_PARALYSIS)
- to_chat(owner, "You can't feel your [name]!")
- if(held_index)
- owner.dropItemToGround(owner.get_item_for_held_index(held_index))
- if(owner.hud_used)
- var/obj/screen/inventory/hand/L = owner.hud_used.hand_slots["[held_index]"]
- if(L)
- L.update_icon()
+ for(var/i in wounds)
+ if(istype(i, checking_type))
+ return i
-/obj/item/bodypart/l_arm/monkey
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "default_monkey_l_arm"
- animal_origin = MONKEY_BODYPART
- px_x = -5
- px_y = -3
+/**
+ * update_wounds() is called whenever a wound is gained or lost on this bodypart, as well as if there's a change of some kind on a bone wound possibly changing disabled status
+ *
+ * Covers tabulating the damage multipliers we have from wounds (burn specifically), as well as deleting our gauze wrapping if we don't have any wounds that can use bandaging
+ *
+ * Arguments:
+ * * replaced- If true, this is being called from the remove_wound() of a wound that's being replaced, so the bandage that already existed is still relevant, but the new wound hasn't been added yet
+ */
+/obj/item/bodypart/proc/update_wounds(replaced = FALSE)
+ var/dam_mul = 1 //initial(wound_damage_multiplier)
+ // we can only have one wound per type, but remember there's multiple types
+ // we can (normally) only have one wound per type, but remember there's multiple types (smites like :B:loodless can generate multiple cuts on a limb)
+ for(var/i in wounds)
+ var/datum/wound/iter_wound = i
+ dam_mul *= iter_wound.damage_mulitplier_penalty
-/obj/item/bodypart/l_arm/alien
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "alien_l_arm"
- px_x = 0
- px_y = 0
- dismemberable = 0
- max_damage = 100
- animal_origin = ALIEN_BODYPART
+ if(!LAZYLEN(wounds) && current_gauze && !replaced)
+ owner.visible_message("\The [current_gauze] on [owner]'s [name] fall away.", "The [current_gauze] on your [name] fall away.")
+ QDEL_NULL(current_gauze)
+ wound_damage_multiplier = dam_mul
+ update_disabled()
-/obj/item/bodypart/l_arm/devil
- dismemberable = 0
- max_damage = 5000
- animal_origin = DEVIL_BODYPART
-
-/obj/item/bodypart/r_arm
- name = "right arm"
- desc = "Over 87% of humans are right handed. That figure is much lower \
- among humans missing their right arm."
- icon_state = "default_human_r_arm"
- attack_verb = list("slapped", "punched")
- max_damage = 50
- body_zone = BODY_ZONE_R_ARM
- body_part = ARM_RIGHT
- aux_icons = list(BODY_ZONE_PRECISE_R_HAND = HANDS_PART_LAYER, "r_hand_behind" = BODY_BEHIND_LAYER)
- body_damage_coeff = 0.75
- held_index = 2
- px_x = 6
- px_y = 0
- stam_heal_tick = STAM_RECOVERY_LIMB
- max_stamina_damage = 50
-
-/obj/item/bodypart/r_arm/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
-
-/obj/item/bodypart/r_arm/set_disabled(new_disabled)
- . = ..()
- if(!.)
+/obj/item/bodypart/proc/get_bleed_rate()
+ if(status != BODYPART_ORGANIC) // maybe in the future we can bleed oil from aug parts, but not now
return
- if(owner.stat < UNCONSCIOUS)
- switch(disabled)
- if(BODYPART_DISABLED_DAMAGE)
- owner.emote("scream")
- to_chat(owner, "Your [name] is too damaged to function!")
- if(BODYPART_DISABLED_PARALYSIS)
- to_chat(owner, "You can't feel your [name]!")
- if(held_index)
- owner.dropItemToGround(owner.get_item_for_held_index(held_index))
- if(owner.hud_used)
- var/obj/screen/inventory/hand/R = owner.hud_used.hand_slots["[held_index]"]
- if(R)
- R.update_icon()
+ var/bleed_rate = 0
+ if(generic_bleedstacks > 0)
+ bleed_rate++
+ //We want an accurate reading of .len
+ listclearnulls(embedded_objects)
+ for(var/obj/item/embeddies in embedded_objects)
+ if(!embeddies.isEmbedHarmless())
+ bleed_rate += 0.5
-/obj/item/bodypart/r_arm/monkey
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "default_monkey_r_arm"
- animal_origin = MONKEY_BODYPART
- px_x = 5
- px_y = -3
+ for(var/thing in wounds)
+ var/datum/wound/W = thing
+ bleed_rate += W.blood_flow
+ if(owner.mobility_flags & ~MOBILITY_STAND)
+ bleed_rate *= 0.75
+ return bleed_rate
-/obj/item/bodypart/r_arm/alien
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "alien_r_arm"
- px_x = 0
- px_y = 0
- dismemberable = 0
- max_damage = 100
- animal_origin = ALIEN_BODYPART
-
-/obj/item/bodypart/r_arm/devil
- dismemberable = 0
- max_damage = 5000
- animal_origin = DEVIL_BODYPART
-
-/obj/item/bodypart/l_leg
- name = "left leg"
- desc = "Some athletes prefer to tie their left shoelaces first for good \
- luck. In this instance, it probably would not have helped."
- icon_state = "default_human_l_leg"
- attack_verb = list("kicked", "stomped")
- max_damage = 50
- body_zone = BODY_ZONE_L_LEG
- body_part = LEG_LEFT
- body_damage_coeff = 0.75
- px_x = -2
- px_y = 12
- stam_heal_tick = STAM_RECOVERY_LIMB
- max_stamina_damage = 50
-
-/obj/item/bodypart/l_leg/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
-
-/obj/item/bodypart/l_leg/set_disabled(new_disabled)
- . = ..()
- if(!. || owner.stat >= UNCONSCIOUS)
+/**
+ * apply_gauze() is used to- well, apply gauze to a bodypart
+ *
+ * As of the Wounds 2 PR, all bleeding is now bodypart based rather than the old bleedstacks system, and 90% of standard bleeding comes from flesh wounds (the exception is embedded weapons).
+ * The same way bleeding is totaled up by bodyparts, gauze now applies to all wounds on the same part. Thus, having a slash wound, a pierce wound, and a broken bone wound would have the gauze
+ * applying blood staunching to the first two wounds, while also acting as a sling for the third one. Once enough blood has been absorbed or all wounds with the ACCEPTS_GAUZE flag have been cleared,
+ * the gauze falls off.
+ *
+ * Arguments:
+ * * gauze- Just the gauze stack we're taking a sheet from to apply here
+ */
+/obj/item/bodypart/proc/apply_gauze(obj/item/stack/gauze)
+ if(!istype(gauze) || !gauze.absorption_capacity)
return
- switch(disabled)
- if(BODYPART_DISABLED_DAMAGE)
- owner.emote("scream")
- to_chat(owner, "Your [name] is too damaged to function!")
- if(BODYPART_DISABLED_PARALYSIS)
- to_chat(owner, "You can't feel your [name]!")
+ QDEL_NULL(current_gauze)
+ current_gauze = new gauze.type(src, 1)
+ gauze.use(1)
-
-/obj/item/bodypart/l_leg/digitigrade
- name = "left digitigrade leg"
- use_digitigrade = FULL_DIGITIGRADE
-
-/obj/item/bodypart/l_leg/monkey
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "default_monkey_l_leg"
- animal_origin = MONKEY_BODYPART
- px_y = 4
-
-/obj/item/bodypart/l_leg/alien
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "alien_l_leg"
- px_x = 0
- px_y = 0
- dismemberable = 0
- max_damage = 100
- animal_origin = ALIEN_BODYPART
-
-/obj/item/bodypart/l_leg/devil
- dismemberable = 0
- max_damage = 5000
- animal_origin = DEVIL_BODYPART
-
-/obj/item/bodypart/r_leg
- name = "right leg"
- desc = "You put your right leg in, your right leg out. In, out, in, out, \
- shake it all about. And apparently then it detaches.\n\
- The hokey pokey has certainly changed a lot since space colonisation."
- // alternative spellings of 'pokey' are availible
- icon_state = "default_human_r_leg"
- attack_verb = list("kicked", "stomped")
- max_damage = 50
- body_zone = BODY_ZONE_R_LEG
- body_part = LEG_RIGHT
- body_damage_coeff = 0.75
- px_x = 2
- px_y = 12
- max_stamina_damage = 50
- stam_heal_tick = STAM_RECOVERY_LIMB
-
-/obj/item/bodypart/r_leg/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
-
-/obj/item/bodypart/r_leg/set_disabled(new_disabled)
- . = ..()
- if(!. || owner.stat >= UNCONSCIOUS)
+/**
+ * seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity.
+ *
+ * The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandages fall off and we're left with nothing.
+ *
+ * Arguments:
+ * * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?)
+ */
+/obj/item/bodypart/proc/seep_gauze(seep_amt = 0)
+ if(!current_gauze)
return
- switch(disabled)
- if(BODYPART_DISABLED_DAMAGE)
- owner.emote("scream")
- to_chat(owner, "Your [name] is too damaged to function!")
- if(BODYPART_DISABLED_PARALYSIS)
- to_chat(owner, "You can't feel your [name]!")
-
-/obj/item/bodypart/r_leg/digitigrade
- name = "right digitigrade leg"
- use_digitigrade = FULL_DIGITIGRADE
-
-/obj/item/bodypart/r_leg/monkey
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "default_monkey_r_leg"
- animal_origin = MONKEY_BODYPART
- px_y = 4
-
-/obj/item/bodypart/r_leg/alien
- icon = 'icons/mob/animal_parts.dmi'
- icon_state = "alien_r_leg"
- px_x = 0
- px_y = 0
- dismemberable = 0
- max_damage = 100
- animal_origin = ALIEN_BODYPART
-
-/obj/item/bodypart/r_leg/devil
- dismemberable = 0
- max_damage = 5000
- animal_origin = DEVIL_BODYPART
+ current_gauze.absorption_capacity -= seep_amt
+ if(current_gauze.absorption_capacity < 0)
+ owner.visible_message("\The [current_gauze] on [owner]'s [name] fall away in rags.", "\The [current_gauze] on your [name] fall away in rags.", vision_distance=COMBAT_MESSAGE_RANGE)
+ QDEL_NULL(current_gauze)
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index f654270df7..fa003e3f3c 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -4,7 +4,7 @@
return TRUE
//Dismember a limb
-/obj/item/bodypart/proc/dismember(dam_type = BRUTE)
+/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE)
if(!owner)
return FALSE
var/mob/living/carbon/C = owner
@@ -15,8 +15,9 @@
if(HAS_TRAIT(C, TRAIT_NODISMEMBER))
return FALSE
var/obj/item/bodypart/affecting = C.get_bodypart(BODY_ZONE_CHEST)
- affecting.receive_damage(clamp(brute_dam/2 * affecting.body_damage_coeff, 15, 50), clamp(burn_dam/2 * affecting.body_damage_coeff, 0, 50)) //Damage the chest based on limb's existing damage
- C.visible_message("[C]'s [src.name] has been violently dismembered!")
+ affecting.receive_damage(clamp(brute_dam/2 * affecting.body_damage_coeff, 15, 50), clamp(burn_dam/2 * affecting.body_damage_coeff, 0, 50), wound_bonus=CANT_WOUND) //Damage the chest based on limb's existing damage
+ if(!silent)
+ C.visible_message("[C]'s [name] is violently dismembered!")
C.emote("scream")
SEND_SIGNAL(C, COMSIG_ADD_MOOD_EVENT, "dismembered", /datum/mood_event/dismembered)
drop_limb()
@@ -30,6 +31,7 @@
burn()
return TRUE
add_mob_blood(C)
+ C.bleed(rand(20, 40))
var/direction = pick(GLOB.cardinals)
var/t_range = rand(2,max(throw_range/2, 2))
var/turf/target_turf = get_turf(src)
@@ -80,14 +82,13 @@
if(organ_spilled)
C.visible_message("[C]'s internal organs spill out onto the floor!")
-
-
//limb removal. The "special" argument is used for swapping a limb with a new one without the effects of losing a limb kicking in.
-/obj/item/bodypart/proc/drop_limb(special)
+/obj/item/bodypart/proc/drop_limb(special, dismembered)
if(!owner)
return
var/atom/Tsec = owner.drop_location()
var/mob/living/carbon/C = owner
+ SEND_SIGNAL(C, COMSIG_CARBON_REMOVE_LIMB, src, dismembered)
update_limb(1)
C.bodyparts -= src
@@ -95,6 +96,15 @@
C.dropItemToGround(owner.get_item_for_held_index(held_index), 1)
C.hand_bodyparts[held_index] = null
+ for(var/thing in scars)
+ var/datum/scar/S = thing
+ S.victim = null
+ LAZYREMOVE(owner.all_scars, S)
+
+ for(var/thing in wounds)
+ var/datum/wound/W = thing
+ W.remove_wound(TRUE)
+
owner = null
for(var/X in C.surgeries) //if we had an ongoing surgery on that limb, we stop it.
@@ -143,7 +153,52 @@
forceMove(Tsec)
+/**
+ * get_mangled_state() is relevant for flesh and bone bodyparts, and returns whether this bodypart has mangled skin, mangled bone, or both (or neither i guess)
+ *
+ * Dismemberment for flesh and bone requires the victim to have the skin on their bodypart destroyed (either a critical cut or piercing wound), and at least a hairline fracture
+ * (severe bone), at which point we can start rolling for dismembering. The attack must also deal at least 10 damage, and must be a brute attack of some kind (sorry for now, cakehat, maybe later)
+ *
+ * Returns: BODYPART_MANGLED_NONE if we're fine, BODYPART_MANGLED_FLESH if our skin is broken, BODYPART_MANGLED_BONE if our bone is broken, or BODYPART_MANGLED_BOTH if both are broken and we're up for dismembering
+ */
+/obj/item/bodypart/proc/get_mangled_state()
+ . = BODYPART_MANGLED_NONE
+ for(var/i in wounds)
+ var/datum/wound/iter_wound = i
+ if((iter_wound.wound_flags & MANGLES_BONE))
+ . |= BODYPART_MANGLED_BONE
+ if((iter_wound.wound_flags & MANGLES_FLESH))
+ . |= BODYPART_MANGLED_FLESH
+
+/**
+ * try_dismember() is used, once we've confirmed that a flesh and bone bodypart has both the skin and bone mangled, to actually roll for it
+ *
+ * Mangling is described in the above proc, [/obj/item/bodypart/proc/get_mangled_state()]. This simply makes the roll for whether we actually dismember or not
+ * using how damaged the limb already is, and how much damage this blow was for. If we have a critical bone wound instead of just a severe, we add +10% to the roll.
+ * Lastly, we choose which kind of dismember we want based on the wounding type we hit with. Note we don't care about all the normal mods or armor for this
+ *
+ * Arguments:
+ * * wounding_type: Either WOUND_BLUNT, WOUND_SLASH, or WOUND_PIERCE, basically only matters for the dismember message
+ * * wounding_dmg: The damage of the strike that prompted this roll, higher damage = higher chance
+ * * wound_bonus: Not actually used right now, but maybe someday
+ * * bare_wound_bonus: ditto above
+ */
+/obj/item/bodypart/proc/try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
+ if(wounding_dmg < DISMEMBER_MINIMUM_DAMAGE)
+ return
+
+ var/base_chance = wounding_dmg + (get_damage() / max_damage * 50) // how much damage we dealt with this blow, + 50% of the damage percentage we already had on this bodypart
+ if(locate(/datum/wound/blunt/critical) in wounds) // we only require a severe bone break, but if there's a critical bone break, we'll add 10% more
+ base_chance += 10
+
+ if(!prob(base_chance))
+ return
+
+ var/datum/wound/loss/dismembering = new
+ dismembering.apply_dismember(src, wounding_type)
+
+ return TRUE
//when a limb is dropped, the internal organs are removed from the mob and put into the limb
/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/LB, mob/living/carbon/C)
@@ -298,6 +353,15 @@
for(var/obj/item/organ/O in contents)
O.Insert(C)
+ for(var/thing in scars)
+ var/datum/scar/S = thing
+ S.victim = C
+ LAZYADD(C.all_scars, thing)
+
+ for(var/i in wounds)
+ var/datum/wound/W = i
+ W.apply_wound(src, TRUE)
+
update_bodypart_damage_state()
update_disabled()
@@ -359,7 +423,7 @@
/mob/living/carbon/regenerate_limb(limb_zone, noheal)
var/obj/item/bodypart/L
if(get_bodypart(limb_zone))
- return 0
+ return FALSE
L = newBodyPart(limb_zone, 0, 0)
if(L)
if(!noheal)
@@ -367,6 +431,8 @@
L.burn_dam = 0
L.brutestate = 0
L.burnstate = 0
-
+ var/datum/scar/scaries = new
+ var/datum/wound/loss/phantom_loss = new // stolen valor, really
+ scaries.generate(L, phantom_loss)
L.attach_limb(src, 1)
- return 1
+ return TRUE
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index a74b1dad28..13b1140527 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -35,8 +35,11 @@
//If the head is a special sprite
var/custom_head
+ wound_resistance = 10
+ scars_covered_by_clothes = FALSE
+
/obj/item/bodypart/head/can_dismember(obj/item/I)
- if(!((owner.stat == DEAD) || owner.InFullCritical()))
+ if(owner && !((owner.stat == DEAD) || owner.InFullCritical()))
return FALSE
return ..()
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index 29aca7166f..3161419449 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -10,6 +10,16 @@
if(L.body_zone == zone)
return L
+///Get the bodypart for whatever hand we have active, Only relevant for carbons
+/mob/proc/get_active_hand()
+ return FALSE
+
+/mob/living/carbon/get_active_hand()
+ var/which_hand = BODY_ZONE_PRECISE_L_HAND
+ if(!(active_hand_index % 2))
+ which_hand = BODY_ZONE_PRECISE_R_HAND
+ return get_bodypart(check_zone(which_hand))
+
/mob/living/carbon/has_hand_for_held_index(i)
if(i)
var/obj/item/bodypart/L = hand_bodyparts[i]
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
new file mode 100644
index 0000000000..5a887ee6b7
--- /dev/null
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -0,0 +1,289 @@
+/obj/item/bodypart/chest
+ name = BODY_ZONE_CHEST
+ desc = "It's impolite to stare at a person's chest."
+ icon_state = "default_human_chest"
+ max_damage = 200
+ body_zone = BODY_ZONE_CHEST
+ body_part = CHEST
+ px_x = 0
+ px_y = 0
+ stam_damage_coeff = 1
+ max_stamina_damage = 200
+ var/obj/item/cavity_item
+
+/obj/item/bodypart/chest/can_dismember(obj/item/I)
+ if(!((owner.stat == DEAD) || owner.InFullCritical()) || !get_organs())
+ return FALSE
+ return ..()
+
+/obj/item/bodypart/chest/Destroy()
+ if(cavity_item)
+ qdel(cavity_item)
+ return ..()
+
+/obj/item/bodypart/chest/drop_organs(mob/user)
+ if(cavity_item)
+ cavity_item.forceMove(user.loc)
+ cavity_item = null
+ ..()
+
+/obj/item/bodypart/chest/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_chest"
+ animal_origin = MONKEY_BODYPART
+
+/obj/item/bodypart/chest/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_chest"
+ dismemberable = 0
+ max_damage = 500
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/chest/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
+/obj/item/bodypart/chest/larva
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "larva_chest"
+ dismemberable = 0
+ max_damage = 50
+ animal_origin = LARVA_BODYPART
+
+/obj/item/bodypart/l_arm
+ name = "left arm"
+ desc = "Did you know that the word 'sinister' stems originally from the \
+ Latin 'sinestra' (left hand), because the left hand was supposed to \
+ be possessed by the devil? This arm appears to be possessed by no \
+ one though."
+ icon_state = "default_human_l_arm"
+ attack_verb = list("slapped", "punched")
+ max_damage = 50
+ max_stamina_damage = 50
+ body_zone = BODY_ZONE_L_ARM
+ body_part = ARM_LEFT
+ aux_icons = list(BODY_ZONE_PRECISE_L_HAND = HANDS_PART_LAYER, "l_hand_behind" = BODY_BEHIND_LAYER)
+ body_damage_coeff = 0.75
+ held_index = 1
+ px_x = -6
+ px_y = 0
+ stam_heal_tick = STAM_RECOVERY_LIMB
+
+/obj/item/bodypart/l_arm/is_disabled()
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/l_arm/set_disabled(new_disabled)
+ . = ..()
+ if(!.)
+ return
+ if(owner.stat < UNCONSCIOUS)
+ switch(disabled)
+ if(BODYPART_DISABLED_DAMAGE)
+ owner.emote("scream")
+ to_chat(owner, "Your [name] is too damaged to function!")
+ if(BODYPART_DISABLED_PARALYSIS)
+ to_chat(owner, "You can't feel your [name]!")
+ if(held_index)
+ owner.dropItemToGround(owner.get_item_for_held_index(held_index))
+ if(owner.hud_used)
+ var/obj/screen/inventory/hand/L = owner.hud_used.hand_slots["[held_index]"]
+ if(L)
+ L.update_icon()
+
+/obj/item/bodypart/l_arm/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_l_arm"
+ animal_origin = MONKEY_BODYPART
+ px_x = -5
+ px_y = -3
+
+/obj/item/bodypart/l_arm/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_l_arm"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/l_arm/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
+/obj/item/bodypart/r_arm
+ name = "right arm"
+ desc = "Over 87% of humans are right handed. That figure is much lower \
+ among humans missing their right arm."
+ icon_state = "default_human_r_arm"
+ attack_verb = list("slapped", "punched")
+ max_damage = 50
+ body_zone = BODY_ZONE_R_ARM
+ body_part = ARM_RIGHT
+ aux_icons = list(BODY_ZONE_PRECISE_R_HAND = HANDS_PART_LAYER, "r_hand_behind" = BODY_BEHIND_LAYER)
+ body_damage_coeff = 0.75
+ held_index = 2
+ px_x = 6
+ px_y = 0
+ stam_heal_tick = STAM_RECOVERY_LIMB
+ max_stamina_damage = 50
+
+/obj/item/bodypart/r_arm/is_disabled()
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/r_arm/set_disabled(new_disabled)
+ . = ..()
+ if(!.)
+ return
+ if(owner.stat < UNCONSCIOUS)
+ switch(disabled)
+ if(BODYPART_DISABLED_DAMAGE)
+ owner.emote("scream")
+ to_chat(owner, "Your [name] is too damaged to function!")
+ if(BODYPART_DISABLED_PARALYSIS)
+ to_chat(owner, "You can't feel your [name]!")
+ if(held_index)
+ owner.dropItemToGround(owner.get_item_for_held_index(held_index))
+ if(owner.hud_used)
+ var/obj/screen/inventory/hand/R = owner.hud_used.hand_slots["[held_index]"]
+ if(R)
+ R.update_icon()
+
+
+/obj/item/bodypart/r_arm/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_r_arm"
+ animal_origin = MONKEY_BODYPART
+ px_x = 5
+ px_y = -3
+
+/obj/item/bodypart/r_arm/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_r_arm"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/r_arm/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
+/obj/item/bodypart/l_leg
+ name = "left leg"
+ desc = "Some athletes prefer to tie their left shoelaces first for good \
+ luck. In this instance, it probably would not have helped."
+ icon_state = "default_human_l_leg"
+ attack_verb = list("kicked", "stomped")
+ max_damage = 50
+ body_zone = BODY_ZONE_L_LEG
+ body_part = LEG_LEFT
+ body_damage_coeff = 0.75
+ px_x = -2
+ px_y = 12
+ stam_heal_tick = STAM_RECOVERY_LIMB
+ max_stamina_damage = 50
+
+/obj/item/bodypart/l_leg/is_disabled()
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/l_leg/set_disabled(new_disabled)
+ . = ..()
+ if(!. || owner.stat >= UNCONSCIOUS)
+ return
+ switch(disabled)
+ if(BODYPART_DISABLED_DAMAGE)
+ owner.emote("scream")
+ to_chat(owner, "Your [name] is too damaged to function!")
+ if(BODYPART_DISABLED_PARALYSIS)
+ to_chat(owner, "You can't feel your [name]!")
+
+/obj/item/bodypart/l_leg/digitigrade
+ name = "left digitigrade leg"
+ use_digitigrade = FULL_DIGITIGRADE
+
+/obj/item/bodypart/l_leg/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_l_leg"
+ animal_origin = MONKEY_BODYPART
+ px_y = 4
+
+/obj/item/bodypart/l_leg/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_l_leg"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/l_leg/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
+/obj/item/bodypart/r_leg
+ name = "right leg"
+ desc = "You put your right leg in, your right leg out. In, out, in, out, \
+ shake it all about. And apparently then it detaches.\n\
+ The hokey pokey has certainly changed a lot since space colonisation."
+ // alternative spellings of 'pokey' are availible
+ icon_state = "default_human_r_leg"
+ attack_verb = list("kicked", "stomped")
+ max_damage = 50
+ body_zone = BODY_ZONE_R_LEG
+ body_part = LEG_RIGHT
+ body_damage_coeff = 0.75
+ px_x = 2
+ px_y = 12
+ max_stamina_damage = 50
+ stam_heal_tick = STAM_RECOVERY_LIMB
+
+/obj/item/bodypart/r_leg/is_disabled()
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/r_leg/set_disabled(new_disabled)
+ . = ..()
+ if(!. || owner.stat >= UNCONSCIOUS)
+ return
+ switch(disabled)
+ if(BODYPART_DISABLED_DAMAGE)
+ owner.emote("scream")
+ to_chat(owner, "Your [name] is too damaged to function!")
+ if(BODYPART_DISABLED_PARALYSIS)
+ to_chat(owner, "You can't feel your [name]!")
+
+/obj/item/bodypart/r_leg/digitigrade
+ name = "right digitigrade leg"
+ use_digitigrade = FULL_DIGITIGRADE
+
+/obj/item/bodypart/r_leg/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_r_leg"
+ animal_origin = MONKEY_BODYPART
+ px_y = 4
+
+/obj/item/bodypart/r_leg/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_r_leg"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/r_leg/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
diff --git a/code/modules/surgery/bone_mending.dm b/code/modules/surgery/bone_mending.dm
new file mode 100644
index 0000000000..0c0083575b
--- /dev/null
+++ b/code/modules/surgery/bone_mending.dm
@@ -0,0 +1,139 @@
+
+/////BONE FIXING SURGERIES//////
+
+///// Repair Hairline Fracture (Severe)
+/datum/surgery/repair_bone_hairline
+ name = "Repair bone fracture (hairline)"
+ steps = list(/datum/surgery_step/incise, /datum/surgery_step/repair_bone_hairline, /datum/surgery_step/close)
+ target_mobtypes = list(/mob/living/carbon/human)
+ possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
+ requires_real_bodypart = TRUE
+ targetable_wound = /datum/wound/blunt/severe
+
+/datum/surgery/repair_bone_hairline/can_start(mob/living/user, mob/living/carbon/target)
+ if(..())
+ var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
+ return(targeted_bodypart.get_wound_type(targetable_wound))
+
+
+///// Repair Compound Fracture (Critical)
+/datum/surgery/repair_bone_compound
+ name = "Repair Compound Fracture"
+ steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/reset_compound_fracture, /datum/surgery_step/repair_bone_compound, /datum/surgery_step/close)
+ target_mobtypes = list(/mob/living/carbon/human)
+ possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
+ requires_real_bodypart = TRUE
+ targetable_wound = /datum/wound/blunt/critical
+
+/datum/surgery/repair_bone_compound/can_start(mob/living/user, mob/living/carbon/target)
+ if(..())
+ var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
+ return(targeted_bodypart.get_wound_type(targetable_wound))
+
+
+
+//SURGERY STEPS
+
+///// Repair Hairline Fracture (Severe)
+/datum/surgery_step/repair_bone_hairline
+ name = "repair hairline fracture (bonesetter/bone gel/tape)"
+ implements = list(/obj/item/bonesetter = 100, /obj/item/stack/medical/bone_gel = 100, /obj/item/stack/sticky_tape/surgical = 100, /obj/item/stack/sticky_tape/super = 50, /obj/item/stack/sticky_tape = 30)
+ time = 40
+
+/datum/surgery_step/repair_bone_hairline/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(surgery.operated_wound)
+ display_results(user, target, "You begin to repair the fracture in [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)].")
+ else
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+
+/datum/surgery_step/repair_bone_hairline/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ if(surgery.operated_wound)
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
+ display_results(user, target, "You successfully repair the fracture in [target]'s [parse_zone(target_zone)].",
+ "[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "repaired a hairline fracture in", addition="INTENT: [uppertext(user.a_intent)]")
+ qdel(surgery.operated_wound)
+ else
+ to_chat(user, "[target] has no hairline fracture there!")
+ return ..()
+
+/datum/surgery_step/repair_bone_hairline/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, var/fail_prob = 0)
+ ..()
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
+
+
+
+///// Reset Compound Fracture (Crticial)
+/datum/surgery_step/reset_compound_fracture
+ name = "reset bone"
+ implements = list(/obj/item/bonesetter = 100, /obj/item/stack/sticky_tape/surgical = 60, /obj/item/stack/sticky_tape/super = 40, /obj/item/stack/sticky_tape = 20)
+ time = 40
+
+/datum/surgery_step/reset_compound_fracture/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(surgery.operated_wound)
+ display_results(user, target, "You begin to reset the bone in [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to reset the bone in [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to reset the bone in [target]'s [parse_zone(user.zone_selected)].")
+ else
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+
+/datum/surgery_step/reset_compound_fracture/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ if(surgery.operated_wound)
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
+ display_results(user, target, "You successfully reset the bone in [target]'s [parse_zone(target_zone)].",
+ "[user] successfully resets the bone in [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully resets the bone in [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "reset a compound fracture in", addition="INTENT: [uppertext(user.a_intent)]")
+ else
+ to_chat(user, "[target] has no compound fracture there!")
+ return ..()
+
+/datum/surgery_step/reset_compound_fracture/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, var/fail_prob = 0)
+ ..()
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
+
+
+///// Repair Compound Fracture (Crticial)
+/datum/surgery_step/repair_bone_compound
+ name = "repair compound fracture (bone gel/tape)"
+ implements = list(/obj/item/stack/medical/bone_gel = 100, /obj/item/stack/sticky_tape/surgical = 100, /obj/item/stack/sticky_tape/super = 50, /obj/item/stack/sticky_tape = 30)
+ time = 40
+
+/datum/surgery_step/repair_bone_compound/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(surgery.operated_wound)
+ display_results(user, target, "You begin to repair the fracture in [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)].")
+ else
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+
+/datum/surgery_step/repair_bone_compound/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ if(surgery.operated_wound)
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
+ display_results(user, target, "You successfully repair the fracture in [target]'s [parse_zone(target_zone)].",
+ "[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "repaired a compound fracture in", addition="INTENT: [uppertext(user.a_intent)]")
+ qdel(surgery.operated_wound)
+ else
+ to_chat(user, "[target] has no compound fracture there!")
+ return ..()
+
+/datum/surgery_step/repair_bone_compound/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, var/fail_prob = 0)
+ ..()
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
diff --git a/code/modules/surgery/burn_dressing.dm b/code/modules/surgery/burn_dressing.dm
new file mode 100644
index 0000000000..8bfa52d245
--- /dev/null
+++ b/code/modules/surgery/burn_dressing.dm
@@ -0,0 +1,107 @@
+
+/////BURN FIXING SURGERIES//////
+
+///// Debride burnt flesh
+/datum/surgery/debride
+ name = "Debride infected flesh"
+ steps = list(/datum/surgery_step/debride, /datum/surgery_step/dress)
+ target_mobtypes = list(/mob/living/carbon/human)
+ possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
+ requires_real_bodypart = TRUE
+ targetable_wound = /datum/wound/burn
+
+/datum/surgery/debride/can_start(mob/living/user, mob/living/carbon/target)
+ if(..())
+ var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
+ var/datum/wound/burn/burn_wound = targeted_bodypart.get_wound_type(targetable_wound)
+ return(burn_wound && burn_wound.infestation > 0)
+
+//SURGERY STEPS
+
+///// Debride
+/datum/surgery_step/debride
+ name = "excise infection"
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCALPEL = 85, TOOL_SAW = 60, TOOL_WIRECUTTER = 40)
+ time = 30
+ repeatable = TRUE
+
+/datum/surgery_step/debride/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(surgery.operated_wound)
+ var/datum/wound/burn/burn_wound = surgery.operated_wound
+ if(burn_wound.infestation <= 0)
+ to_chat(user, "[target]'s [parse_zone(user.zone_selected)] has no infected flesh to remove!")
+ surgery.status++
+ repeatable = FALSE
+ return
+ display_results(user, target, "You begin to excise infected flesh from [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to excise infected flesh from [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to excise infected flesh from [target]'s [parse_zone(user.zone_selected)].")
+ else
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+
+/datum/surgery_step/debride/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ var/datum/wound/burn/burn_wound = surgery.operated_wound
+ if(burn_wound)
+ display_results(user, target, "You successfully excise some of the infected flesh from [target]'s [parse_zone(target_zone)].",
+ "[user] successfully excises some of the infected flesh from [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully excises some of the infected flesh from [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "excised infected flesh in", addition="INTENT: [uppertext(user.a_intent)]")
+ surgery.operated_bodypart.receive_damage(brute=3, wound_bonus=CANT_WOUND)
+ burn_wound.infestation -= 0.5
+ burn_wound.sanitization += 0.5
+ if(burn_wound.infestation <= 0)
+ repeatable = FALSE
+ else
+ to_chat(user, "[target] has no infected flesh there!")
+ return ..()
+
+/datum/surgery_step/debride/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, var/fail_prob = 0)
+ ..()
+ display_results(user, target, "You carve away some of the healthy flesh from [target]'s [parse_zone(target_zone)].",
+ "[user] carves away some of the healthy flesh from [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] carves away some of the healthy flesh from [target]'s [parse_zone(target_zone)]!")
+ surgery.operated_bodypart.receive_damage(brute=rand(4,8), sharpness=TRUE)
+
+/datum/surgery_step/debride/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
+ if(!..())
+ return
+ var/datum/wound/burn/burn_wound = surgery.operated_wound
+ while(burn_wound && burn_wound.infestation > 0.25)
+ if(!..())
+ break
+
+///// Dressing burns
+/datum/surgery_step/dress
+ name = "bandage burns"
+ implements = list(/obj/item/stack/medical/gauze = 100, /obj/item/stack/sticky_tape/surgical = 100)
+ time = 40
+
+/datum/surgery_step/dress/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ var/datum/wound/burn/burn_wound = surgery.operated_wound
+ if(burn_wound)
+ display_results(user, target, "You begin to dress the burns on [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to dress the burns on [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to dress the burns on [target]'s [parse_zone(user.zone_selected)].")
+ else
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+
+/datum/surgery_step/dress/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ var/datum/wound/burn/burn_wound = surgery.operated_wound
+ if(burn_wound)
+ display_results(user, target, "You successfully wrap [target]'s [parse_zone(target_zone)] with [tool].",
+ "[user] successfully wraps [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully wraps [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "dressed burns in", addition="INTENT: [uppertext(user.a_intent)]")
+ burn_wound.sanitization += 3
+ burn_wound.flesh_healing += 5
+ var/obj/item/bodypart/the_part = target.get_bodypart(target_zone)
+ the_part.apply_gauze(tool)
+ else
+ to_chat(user, "[target] has no burns there!")
+ return ..()
+
+/datum/surgery_step/dress/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, var/fail_prob = 0)
+ ..()
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/used_stack = tool
+ used_stack.use(1)
diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm
index af736e393c..d1d478ddfe 100644
--- a/code/modules/surgery/coronary_bypass.dm
+++ b/code/modules/surgery/coronary_bypass.dm
@@ -31,7 +31,8 @@
display_results(user, target, "Blood pools around the incision in [H]'s heart.",
"Blood pools around the incision in [H]'s heart.",
"")
- H.bleed_rate += 10
+ var/obj/item/bodypart/BP = H.get_bodypart(target_zone)
+ BP.generic_bleedstacks += 10
H.adjustBruteLoss(10)
return TRUE
@@ -41,7 +42,8 @@
display_results(user, target, "You screw up, cutting too deeply into the heart!",
"[user] screws up, causing blood to spurt out of [H]'s chest!",
"[user] screws up, causing blood to spurt out of [H]'s chest!")
- H.bleed_rate += 20
+ var/obj/item/bodypart/BP = H.get_bodypart(target_zone)
+ BP.generic_bleedstacks += 10
H.adjustOrganLoss(ORGAN_SLOT_HEART, 10)
H.adjustBruteLoss(10)
@@ -73,5 +75,6 @@
"[user] screws up, causing blood to spurt out of [H]'s chest profusely!",
"[user] screws up, causing blood to spurt out of [H]'s chest profusely!")
H.adjustOrganLoss(ORGAN_SLOT_HEART, 20)
- H.bleed_rate += 30
+ var/obj/item/bodypart/BP = H.get_bodypart(target_zone)
+ BP.generic_bleedstacks += 30
return FALSE
diff --git a/code/modules/surgery/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm
index 6110bb6202..b9d877d0c1 100644
--- a/code/modules/surgery/experimental_dissection.dm
+++ b/code/modules/surgery/experimental_dissection.dm
@@ -78,7 +78,7 @@
"[user] dissects [target]!")
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points_earned))
var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST)
- target.apply_damage(80, BRUTE, L)
+ target.apply_damage(80, BRUTE, L, wound_bonus=CANT_WOUND)
ADD_TRAIT(target, TRAIT_DISSECTED, "[surgery.name]")
repeatable = FALSE
return TRUE
@@ -89,7 +89,7 @@
"[user] dissects [target], but looks a little dissapointed.")
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = (round(check_value(target, surgery) * 0.01))))
var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST)
- target.apply_damage(80, BRUTE, L)
+ target.apply_damage(80, BRUTE, L, wound_bonus=CANT_WOUND)
return TRUE
/datum/surgery/advanced/experimental_dissection/adv
diff --git a/code/modules/surgery/healing.dm b/code/modules/surgery/healing.dm
index 4069199864..0680dda404 100644
--- a/code/modules/surgery/healing.dm
+++ b/code/modules/surgery/healing.dm
@@ -87,7 +87,7 @@
urdamageamt_brute += round((target.getBruteLoss()/ (missinghpbonus*2)),0.1)
urdamageamt_burn += round((target.getFireLoss()/ (missinghpbonus*2)),0.1)
- target.take_bodypart_damage(urdamageamt_brute, urdamageamt_burn)
+ target.take_bodypart_damage(urdamageamt_brute, urdamageamt_burn, wound_bonus=CANT_WOUND)
return FALSE
/***************************BRUTE***************************/
diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm
index 0b38ecc2fe..8e893875a9 100644
--- a/code/modules/surgery/organic_steps.dm
+++ b/code/modules/surgery/organic_steps.dm
@@ -21,7 +21,9 @@
display_results(user, target, "Blood pools around the incision in [H]'s [parse_zone(target_zone)].",
"Blood pools around the incision in [H]'s [parse_zone(target_zone)].",
"")
- H.bleed_rate += 3
+ var/obj/item/bodypart/BP = target.get_bodypart(target_zone)
+ if(BP)
+ BP.generic_bleedstacks += 10
return TRUE
/datum/surgery_step/incise/nobleed //silly friendly!
@@ -50,7 +52,9 @@
target.heal_bodypart_damage(20,0)
if (ishuman(target))
var/mob/living/carbon/human/H = target
- H.bleed_rate = max( (H.bleed_rate - 3), 0)
+ var/obj/item/bodypart/BP = H.get_bodypart(target_zone)
+ if(BP)
+ BP.generic_bleedstacks -= 3
return ..()
//retract skin
/datum/surgery_step/retract_skin
@@ -86,7 +90,9 @@
target.heal_bodypart_damage(45,0)
if (ishuman(target))
var/mob/living/carbon/human/H = target
- H.bleed_rate = max( (H.bleed_rate - 3), 0)
+ var/obj/item/bodypart/BP = H.get_bodypart(target_zone)
+ if(BP)
+ BP.generic_bleedstacks -= 3
return ..()
//saw bone
/datum/surgery_step/saw
@@ -100,7 +106,7 @@
"[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- target.apply_damage(50, BRUTE, "[target_zone]")
+ target.apply_damage(50, BRUTE, "[target_zone]", wound_bonus=CANT_WOUND)
display_results(user, target, "You saw [target]'s [parse_zone(target_zone)] open.",
"[user] saws [target]'s [parse_zone(target_zone)] open!",
"[user] saws [target]'s [parse_zone(target_zone)] open!")
diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm
index 2465b63800..f0f98a5fa5 100755
--- a/code/modules/surgery/organs/liver.dm
+++ b/code/modules/surgery/organs/liver.dm
@@ -73,8 +73,8 @@
/obj/item/organ/liver/proc/sizeMoveMod(value, mob/living/carbon/C)
if(cachedmoveCalc == value)
return
- C.next_move_modifier /= cachedmoveCalc
- C.next_move_modifier *= value
+ C.action_cooldown_mod /= cachedmoveCalc
+ C.action_cooldown_mod *= value
cachedmoveCalc = value
/obj/item/organ/liver/fly
diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm
index d9cbf9be03..44b4f6362a 100755
--- a/code/modules/surgery/organs/stomach.dm
+++ b/code/modules/surgery/organs/stomach.dm
@@ -91,3 +91,36 @@
/obj/item/organ/stomach/ipc
name = "ipc stomach"
icon_state = "stomach-ipc"
+
+
+/obj/item/organ/stomach/ethereal
+ name = "biological battery"
+ icon_state = "stomach-p" //Welp. At least it's more unique in functionaliy.
+ desc = "A crystal-like organ that stores the electric charge of ethereals."
+ var/crystal_charge = ETHEREAL_CHARGE_FULL
+
+/obj/item/organ/stomach/ethereal/on_life()
+ ..()
+ adjust_charge(-ETHEREAL_CHARGE_FACTOR)
+
+/obj/item/organ/stomach/ethereal/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
+ ..()
+ RegisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge)
+ RegisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_electrocute)
+
+/obj/item/organ/stomach/ethereal/Remove(mob/living/carbon/M, special = 0)
+ UnregisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT)
+ UnregisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT)
+ ..()
+
+/obj/item/organ/stomach/ethereal/proc/charge(datum/source, amount, repairs)
+ adjust_charge(amount / 70)
+
+/obj/item/organ/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
+ if(flags & SHOCK_ILLUSION)
+ return
+ adjust_charge(shock_damage * siemens_coeff * 2)
+ to_chat(owner, "You absorb some of the shock into your body!")
+
+/obj/item/organ/stomach/ethereal/proc/adjust_charge(amount)
+ crystal_charge = clamp(crystal_charge + amount, ETHEREAL_CHARGE_NONE, ETHEREAL_CHARGE_DANGEROUS)
diff --git a/code/modules/surgery/organs/tails.dm b/code/modules/surgery/organs/tails.dm
index 55a656f42d..289e9df9d4 100644
--- a/code/modules/surgery/organs/tails.dm
+++ b/code/modules/surgery/organs/tails.dm
@@ -45,14 +45,20 @@
/obj/item/organ/tail/lizard/Insert(mob/living/carbon/human/H, special = 0, drop_if_replaced = TRUE)
..()
if(istype(H))
- // Checks here are necessary so it wouldn't overwrite the tail of a lizard it spawned in
+ // Checks here are necessary so it wouldn't overwrite the tail of a lizard it spawned in //yes, the if checks may cause snowflakes so that you can't insert another person's tail (haven't actually tested it but I assume that's the result of my addition) but it makes it so never again will lizards break their spine if set_species is called twice in a row (hopefully)
if(!H.dna.species.mutant_bodyparts["tail_lizard"])
- H.dna.features["tail_lizard"] = tail_type
- H.dna.species.mutant_bodyparts["tail_lizard"] = tail_type
+ if (!H.dna.features["tail_lizard"])
+ H.dna.features["tail_lizard"] = tail_type
+ H.dna.species.mutant_bodyparts["tail_lizard"] = tail_type
+ else
+ H.dna.species.mutant_bodyparts["tail_lizard"] = H.dna.features["tail_lizard"]
if(!H.dna.species.mutant_bodyparts["spines"])
- H.dna.features["spines"] = spines
- H.dna.species.mutant_bodyparts["spines"] = spines
+ if (!H.dna.features["spines"])
+ H.dna.features["spines"] = spines
+ H.dna.species.mutant_bodyparts["spines"] = spines
+ else
+ H.dna.species.mutant_bodyparts["spines"] = H.dna.features["spines"]
H.update_body()
/obj/item/organ/tail/lizard/Remove(special = FALSE)
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index 1c4a2d3043..7090ab62e2 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -312,3 +312,26 @@
desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms."
electronics_magic = FALSE
organ_flags = ORGAN_SYNTHETIC
+
+/obj/item/organ/tongue/ethereal
+ name = "electric discharger"
+ desc = "A sophisticated ethereal organ, capable of synthesising speech via electrical discharge."
+ icon_state = "electrotongue"
+ say_mod = "crackles"
+ attack_verb = list("shocked", "jolted", "zapped")
+ taste_sensitivity = 101 // Not a tongue, they can't taste shit
+ var/static/list/languages_possible_ethereal = typecacheof(list(
+ /datum/language/common,
+ /datum/language/draconic,
+ /datum/language/codespeak,
+ /datum/language/monkey,
+ /datum/language/narsie,
+ /datum/language/beachbum,
+ /datum/language/aphasia,
+ /datum/language/sylvan,
+ /datum/language/voltaic
+ ))
+
+/obj/item/organ/tongue/ethereal/Initialize(mapload)
+ . = ..()
+ languages_possible = languages_possible_ethereal
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index fa49e3eff5..b6b74efe32 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -318,13 +318,14 @@
cooldown = COOLDOWN_DAMAGE
for(var/V in listeners)
var/mob/living/L = V
- L.apply_damage(15 * power_multiplier, def_zone = BODY_ZONE_CHEST)
+ L.apply_damage(15 * power_multiplier, def_zone = BODY_ZONE_CHEST, wound_bonus=CANT_WOUND)
//BLEED
else if((findtext(message, bleed_words)))
cooldown = COOLDOWN_DAMAGE
for(var/mob/living/carbon/human/H in listeners)
- H.bleed_rate += (5 * power_multiplier)
+ var/obj/item/bodypart/BP = pick(H.bodyparts)
+ BP.generic_bleedstacks += 5
//FIRE
else if((findtext(message, burn_words)))
diff --git a/code/modules/surgery/repair_puncture.dm b/code/modules/surgery/repair_puncture.dm
new file mode 100644
index 0000000000..12aefefc82
--- /dev/null
+++ b/code/modules/surgery/repair_puncture.dm
@@ -0,0 +1,108 @@
+
+/////BURN FIXING SURGERIES//////
+
+//the step numbers of each of these two, we only currently use the first to switch back and forth due to advancing after finishing steps anyway
+#define REALIGN_INNARDS 1
+#define WELD_VEINS 2
+
+///// Repair puncture wounds
+/datum/surgery/repair_puncture
+ name = "Repair puncture"
+ steps = list(/datum/surgery_step/incise, /datum/surgery_step/repair_innards, /datum/surgery_step/seal_veins, /datum/surgery_step/close) // repeat between steps 2 and 3 until healed
+ target_mobtypes = list(/mob/living/carbon)
+ possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
+ requires_real_bodypart = TRUE
+ targetable_wound = /datum/wound/pierce
+
+/datum/surgery/repair_puncture/can_start(mob/living/user, mob/living/carbon/target)
+ . = ..()
+ if(.)
+ var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
+ var/datum/wound/burn/pierce_wound = targeted_bodypart.get_wound_type(targetable_wound)
+ return(pierce_wound && pierce_wound.blood_flow > 0)
+
+//SURGERY STEPS
+
+///// realign the blood vessels so we can reweld them
+/datum/surgery_step/repair_innards
+ name = "realign blood vessels"
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCALPEL = 85, TOOL_WIRECUTTER = 40)
+ time = 3 SECONDS
+
+/datum/surgery_step/repair_innards/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ if(!pierce_wound)
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+ return
+
+ if(pierce_wound.blood_flow <= 0)
+ to_chat(user, "[target]'s [parse_zone(user.zone_selected)] has no puncture to repair!")
+ surgery.status++
+ return
+
+ display_results(user, target, "You begin to realign the torn blood vessels in [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to realign the torn blood vessels in [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to realign the torn blood vessels in [target]'s [parse_zone(user.zone_selected)].")
+
+/datum/surgery_step/repair_innards/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ if(!pierce_wound)
+ to_chat(user, "[target] has no puncture wound there!")
+ return ..()
+
+ display_results(user, target, "You successfully realign some of the blood vessels in [target]'s [parse_zone(target_zone)].",
+ "[user] successfully realigns some of the blood vessels in [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully realigns some of the blood vessels in [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "excised infected flesh in", addition="INTENT: [uppertext(user.a_intent)]")
+ surgery.operated_bodypart.receive_damage(brute=3, wound_bonus=CANT_WOUND)
+ pierce_wound.blood_flow -= 0.25
+ return ..()
+
+/datum/surgery_step/repair_innards/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, var/fail_prob = 0)
+ . = ..()
+ display_results(user, target, "You jerk apart some of the blood vessels in [target]'s [parse_zone(target_zone)].",
+ "[user] jerks apart some of the blood vessels in [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] jerk apart some of the blood vessels in [target]'s [parse_zone(target_zone)]!")
+ surgery.operated_bodypart.receive_damage(brute=rand(4,8), sharpness=SHARP_EDGED, wound_bonus = 10)
+
+///// Sealing the vessels back together
+/datum/surgery_step/seal_veins
+ name = "weld veins" // if your doctor says they're going to weld your blood vessels back together, you're either A) on SS13, or B) in grave mortal peril
+ implements = list(TOOL_CAUTERY = 100, /obj/item/gun/energy/laser = 90, TOOL_WELDER = 70, /obj/item = 30)
+ time = 4 SECONDS
+
+/datum/surgery_step/seal_veins/tool_check(mob/user, obj/item/tool)
+ if(implement_type == TOOL_WELDER || implement_type == /obj/item)
+ return tool.get_temperature()
+
+ return TRUE
+
+/datum/surgery_step/seal_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ if(!pierce_wound)
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
+ return
+ display_results(user, target, "You begin to meld some of the split blood vessels in [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to meld some of the split blood vessels in [target]'s [parse_zone(user.zone_selected)] with [tool].",
+ "[user] begins to meld some of the split blood vessels in [target]'s [parse_zone(user.zone_selected)].")
+
+/datum/surgery_step/seal_veins/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
+ var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ if(!pierce_wound)
+ to_chat(user, "[target] has no puncture there!")
+ return ..()
+
+ display_results(user, target, "You successfully meld some of the split blood vessels in [target]'s [parse_zone(target_zone)] with [tool].",
+ "[user] successfully melds some of the split blood vessels in [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully melds some of the split blood vessels in [target]'s [parse_zone(target_zone)]!")
+ log_combat(user, target, "dressed burns in", addition="INTENT: [uppertext(user.a_intent)]")
+ pierce_wound.blood_flow -= 0.5
+ if(pierce_wound.blood_flow > 0)
+ surgery.status = REALIGN_INNARDS
+ to_chat(user, "There still seems to be misaligned blood vessels to finish...")
+ else
+ to_chat(user, "You've repaired all the internal damage in [target]'s [parse_zone(target_zone)]!")
+ return ..()
+
+#undef REALIGN_INNARDS
+#undef WELD_VEINS
diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm
index 51ce2726b0..4d42cb6c23 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -18,6 +18,8 @@
var/lying_required = TRUE //Does the vicitm needs to be lying down.
var/requires_tech = FALSE
var/replaced_by
+ var/datum/wound/operated_wound //The actual wound datum instance we're targeting
+ var/datum/wound/targetable_wound //The wound type this surgery targets
/datum/surgery/New(surgery_target, surgery_location, surgery_bodypart)
..()
@@ -28,8 +30,13 @@
location = surgery_location
if(surgery_bodypart)
operated_bodypart = surgery_bodypart
+ if(targetable_wound)
+ operated_wound = operated_bodypart.get_wound_type(targetable_wound)
+ operated_wound.attached_surgery = src
/datum/surgery/Destroy()
+ if(operated_wound)
+ operated_wound.attached_surgery = null
if(target)
target.surgeries -= src
target = null
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 584a0a189a..c4ded65e9c 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -163,9 +163,10 @@
item_flags = SURGICAL_TOOL
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP_ACCURATE
+ sharpness = SHARP_POINTY
tool_behaviour = TOOL_SCALPEL
toolspeed = 1
+ bare_wound_bonus = 20
/obj/item/scalpel/Initialize()
. = ..()
@@ -180,7 +181,7 @@
force = 16
toolspeed = 0.7
light_color = LIGHT_COLOR_GREEN
- sharpness = IS_SHARP_ACCURATE
+ sharpness = SHARP_POINTY
/obj/item/scalpel/advanced/Initialize()
. = ..()
@@ -220,7 +221,7 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
toolspeed = 0.5
hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP_ACCURATE
+ sharpness = SHARP_POINTY
/obj/item/scalpel/suicide_act(mob/user)
user.visible_message("[user] is slitting [user.p_their()] [pick("wrists", "throat", "stomach")] with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -244,9 +245,11 @@
throw_range = 5
custom_materials = list(/datum/material/iron=10000, /datum/material/glass=6000)
attack_verb = list("attacked", "slashed", "sawed", "cut")
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
tool_behaviour = TOOL_SAW
toolspeed = 1
+ wound_bonus = 5
+ bare_wound_bonus = 10
/obj/item/circular_saw/Initialize()
. = ..()
@@ -269,7 +272,7 @@
custom_materials = list(/datum/material/iron=10000, /datum/material/glass=6000)
toolspeed = 0.5
attack_verb = list("attacked", "slashed", "sawed", "cut")
- sharpness = IS_SHARP
+ sharpness = SHARP_EDGED
/obj/item/surgical_drapes
name = "surgical drapes"
@@ -374,3 +377,18 @@
advanced_surgeries |= OC.advanced_surgeries
return TRUE
return
+
+/obj/item/bonesetter
+ name = "bonesetter"
+ desc = "For setting things right."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "bone setter"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ custom_materials = list(/datum/material/iron=5000, /datum/material/glass=2500)
+ flags_1 = CONDUCT_1
+ item_flags = SURGICAL_TOOL
+ w_class = WEIGHT_CLASS_SMALL
+ attack_verb = list("corrected", "properly set")
+ tool_behaviour = TOOL_BONESET
+ toolspeed = 1
diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm
index 5de54c439c..46b324e151 100644
--- a/code/modules/tgui/external.dm
+++ b/code/modules/tgui/external.dm
@@ -1,7 +1,8 @@
/**
- * tgui external
+ * External tgui definitions, such as src_object APIs.
*
- * Contains all external tgui declarations.
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
/**
@@ -11,13 +12,9 @@
* If this proc is not implemented properly, the UI will not update correctly.
*
* required user mob The mob who opened/is using the UI.
- * optional ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
- * optional force_open bool If the UI should be re-opened instead of updated.
- * optional master_ui datum/tgui The parent UI.
- * optional state datum/ui_state The state used to determine status.
*/
-/datum/proc/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)
+/datum/proc/ui_interact(mob/user, datum/tgui/ui)
return FALSE // Not implemented.
/**
@@ -37,10 +34,11 @@
* public
*
* Static Data to be sent to the UI.
- * Static data differs from normal data in that it's large data that should be sent infrequently
- * This is implemented optionally for heavy uis that would be sending a lot of redundant data
- * frequently.
- * Gets squished into one object on the frontend side, but the static part is cached.
+ *
+ * Static data differs from normal data in that it's large data that should be
+ * sent infrequently. This is implemented optionally for heavy uis that would
+ * be sending a lot of redundant data frequently. Gets squished into one
+ * object on the frontend side, but the static part is cached.
*
* required user mob The mob interacting with the UI.
*
@@ -52,18 +50,17 @@
/**
* public
*
- * Forces an update on static data. Should be done manually whenever something happens to change static data.
+ * Forces an update on static data. Should be done manually whenever something
+ * happens to change static data.
*
* required user the mob currently interacting with the ui
* optional ui ui to be updated
- * optional ui_key ui key of ui to be updated
*/
-/datum/proc/update_static_data(mob/user, datum/tgui/ui, ui_key = "main")
- ui = SStgui.try_update_ui(user, src, ui_key, ui)
- // If there was no ui to update, there's no static data to update either.
+/datum/proc/update_static_data(mob/user, datum/tgui/ui)
if(!ui)
- return
- ui.push_data(null, ui_static_data(), TRUE)
+ ui = SStgui.get_open_ui(user, src)
+ if(ui)
+ ui.send_full_update()
/**
* public
@@ -85,17 +82,12 @@
* public
*
* Called on an object when a tgui object is being created, allowing you to
- * customise the html
- * For example: inserting a custom stylesheet that you need in the head
+ * push various assets to tgui, for examples spritesheets.
*
- * For this purpose, some tags are available in the html, to be parsed out
- ^ with replacetext
- * (customheadhtml) - Additions to the head tag
- *
- * required html the html base text
+ * return list List of asset datums or file paths.
*/
-/datum/proc/ui_base_html(html)
- return html
+/datum/proc/ui_assets(mob/user)
+ return list()
/**
* private
@@ -107,6 +99,15 @@
/datum/proc/ui_host(mob/user)
return src // Default src.
+/**
+ * private
+ *
+ * The UI's state controller to be used for created uis
+ * This is a proc over a var for memory reasons
+ */
+/datum/proc/ui_state(mob/user)
+ return GLOB.default_state
+
/**
* global
*
@@ -118,9 +119,17 @@
/**
* global
*
- * Used to track UIs for a mob.
+ * Tracks open UIs for a user.
*/
-/mob/var/list/open_uis = list()
+/mob/var/list/tgui_open_uis = list()
+
+/**
+ * global
+ *
+ * Tracks open windows for a user.
+ */
+/client/var/list/tgui_windows = list()
+
/**
* public
*
@@ -137,17 +146,43 @@
*
* required uiref ref The UI that was closed.
*/
-/client/verb/uiclose(ref as text)
+/client/verb/uiclose(window_id as text)
// Name the verb, and hide it from the user panel.
set name = "uiclose"
- set hidden = 1
+ set hidden = TRUE
+ var/mob/user = src && src.mob
+ if(!user)
+ return
+ // Close all tgui datums based on window_id.
+ SStgui.force_close_window(user, window_id)
- // Get the UI based on the ref.
- var/datum/tgui/ui = locate(ref)
-
- // If we found the UI, close it.
- if(istype(ui))
- ui.close()
- // Unset machine just to be sure.
- if(src && src.mob)
- src.mob.unset_machine()
+/**
+ * Middleware for /client/Topic.
+ *
+ * return bool Whether the topic is passed (TRUE), or cancelled (FALSE).
+ */
+/proc/tgui_Topic(href_list)
+ // Skip non-tgui topics
+ if(!href_list["tgui"])
+ return TRUE
+ var/type = href_list["type"]
+ // Unconditionally collect tgui logs
+ if(type == "log")
+ log_tgui(usr, href_list["message"])
+ // Locate window
+ var/window_id = href_list["window_id"]
+ var/datum/tgui_window/window
+ if(window_id)
+ window = usr.client.tgui_windows[window_id]
+ if(!window)
+ log_tgui(usr, "Error: Couldn't find the window datum, force closing.")
+ SStgui.force_close_window(usr, window_id)
+ return FALSE
+ // Decode payload
+ var/payload
+ if(href_list["payload"])
+ payload = json_decode(href_list["payload"])
+ // Pass message to window
+ if(window)
+ window.on_message(type, payload, href_list)
+ return FALSE
diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm
index e626b98815..fa88cc1338 100644
--- a/code/modules/tgui/states.dm
+++ b/code/modules/tgui/states.dm
@@ -1,7 +1,9 @@
/**
- * tgui states
+ * Base state and helpers for states. Just does some sanity checks,
+ * implement a proper state for in-depth checks.
*
- * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks.
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
/**
@@ -26,9 +28,10 @@
. = max(., UI_INTERACTIVE)
// Regular ghosts can always at least view if in range.
- var/clientviewlist = getviewsize(user.client.view)
- if(get_dist(src_object, user) < max(clientviewlist[1],clientviewlist[2]))
- . = max(., UI_UPDATE)
+ if(user.client)
+ var/clientviewlist = getviewsize(user.client.view)
+ if(get_dist(src_object, user) < max(clientviewlist[1], clientviewlist[2]))
+ . = max(., UI_UPDATE)
// Check if the state allows interaction
var/result = state.can_use_topic(src_object, user)
@@ -46,7 +49,8 @@
* return UI_state The state of the UI.
*/
/datum/ui_state/proc/can_use_topic(src_object, mob/user)
- return UI_CLOSE // Don't allow interaction by default.
+ // Don't allow interaction by default.
+ return UI_CLOSE
/**
* public
@@ -56,21 +60,31 @@
* return UI_state The state of the UI.
*/
/mob/proc/shared_ui_interaction(src_object)
- if(!client) // Close UIs if mindless.
+ // Close UIs if mindless.
+ if(!client)
return UI_CLOSE
- else if(stat) // Disable UIs if unconcious.
+ // Disable UIs if unconcious.
+ else if(stat)
return UI_DISABLED
- else if(incapacitated() || lying) // Update UIs if incapicitated but concious.
+ // Update UIs if incapicitated but concious.
+ else if(incapacitated())
return UI_UPDATE
return UI_INTERACTIVE
+/mob/living/shared_ui_interaction(src_object)
+ . = ..()
+ if(!(mobility_flags & MOBILITY_UI) && . == UI_INTERACTIVE)
+ return UI_UPDATE
+
/mob/living/silicon/ai/shared_ui_interaction(src_object)
- if(lacks_power()) // Disable UIs if the AI is unpowered.
+ // Disable UIs if the AI is unpowered.
+ if(lacks_power())
return UI_DISABLED
return ..()
/mob/living/silicon/robot/shared_ui_interaction(src_object)
- if(!cell || cell.charge <= 0 || locked_down) // Disable UIs if the Borg is unpowered or locked.
+ // Disable UIs if the Borg is unpowered or locked.
+ if(!cell || cell.charge <= 0 || locked_down)
return UI_DISABLED
return ..()
@@ -87,7 +101,8 @@
* return UI_state The state of the UI.
*/
/atom/proc/contents_ui_distance(src_object, mob/living/user)
- return user.shared_living_ui_distance(src_object) // Just call this mob's check.
+ // Just call this mob's check.
+ return user.shared_living_ui_distance(src_object)
/**
* public
@@ -99,17 +114,21 @@
* return UI_state The state of the UI.
*/
/mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE)
- if(viewcheck && !(src_object in view(src))) // If the object is obscured, close it.
+ // If the object is obscured, close it.
+ if(viewcheck && !(src_object in view(src)))
return UI_CLOSE
-
var/dist = get_dist(src_object, src)
- if(dist <= 1 || src_object.hasSiliconAccessInArea(src)) // Open and interact if 1-0 tiles away.
+ // Open and interact if 1-0 tiles away.
+ if(dist <= 1)
return UI_INTERACTIVE
- else if(dist <= 2) // View only if 2-3 tiles away.
+ // View only if 2-3 tiles away.
+ else if(dist <= 2)
return UI_UPDATE
- else if(dist <= 5) // Disable if 5 tiles away.
+ // Disable if 5 tiles away.
+ else if(dist <= 5)
return UI_DISABLED
- return UI_CLOSE // Otherwise, we got nothing.
+ // Otherwise, we got nothing.
+ return UI_CLOSE
/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE)
if(dna.check_mutation(TK) && tkMaxRangeCheck(src, src_object))
diff --git a/code/modules/tgui/states/admin.dm b/code/modules/tgui/states/admin.dm
index 61fc373118..227a294078 100644
--- a/code/modules/tgui/states/admin.dm
+++ b/code/modules/tgui/states/admin.dm
@@ -2,6 +2,9 @@
* tgui state: admin_state
*
* Checks that the user is an admin, end-of-story.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(admin_state, /datum/ui_state/admin_state, new)
diff --git a/code/modules/tgui/states/always.dm b/code/modules/tgui/states/always.dm
index a741e2e3d4..210f0896a2 100644
--- a/code/modules/tgui/states/always.dm
+++ b/code/modules/tgui/states/always.dm
@@ -2,6 +2,9 @@
* tgui state: always_state
*
* Always grants the user UI_INTERACTIVE. Period.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(always_state, /datum/ui_state/always_state, new)
diff --git a/code/modules/tgui/states/conscious.dm b/code/modules/tgui/states/conscious.dm
index 4e2793d130..670ca7c07e 100644
--- a/code/modules/tgui/states/conscious.dm
+++ b/code/modules/tgui/states/conscious.dm
@@ -2,6 +2,9 @@
* tgui state: conscious_state
*
* Only checks if the user is conscious.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(conscious_state, /datum/ui_state/conscious_state, new)
diff --git a/code/modules/tgui/states/contained.dm b/code/modules/tgui/states/contained.dm
index f02424d01e..1eb8edba25 100644
--- a/code/modules/tgui/states/contained.dm
+++ b/code/modules/tgui/states/contained.dm
@@ -2,6 +2,9 @@
* tgui state: contained_state
*
* Checks that the user is inside the src_object.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(contained_state, /datum/ui_state/contained_state, new)
diff --git a/code/modules/tgui/states/deep_inventory.dm b/code/modules/tgui/states/deep_inventory.dm
index 43758cbab1..a2b9276a59 100644
--- a/code/modules/tgui/states/deep_inventory.dm
+++ b/code/modules/tgui/states/deep_inventory.dm
@@ -1,7 +1,11 @@
/**
* tgui state: deep_inventory_state
*
- * Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory.
+ * Checks that the src_object is in the user's deep
+ * (backpack, box, toolbox, etc) inventory.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(deep_inventory_state, /datum/ui_state/deep_inventory_state, new)
diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm
index 6bb159640e..367e57beff 100644
--- a/code/modules/tgui/states/default.dm
+++ b/code/modules/tgui/states/default.dm
@@ -1,7 +1,11 @@
/**
* tgui state: default_state
*
- * Checks a number of things -- mostly physical distance for humans and view for robots.
+ * Checks a number of things -- mostly physical distance for humans
+ * and view for robots.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
diff --git a/code/modules/tgui/states/default_contained.dm b/code/modules/tgui/states/default_contained.dm
deleted file mode 100644
index c532e9f5d1..0000000000
--- a/code/modules/tgui/states/default_contained.dm
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * tgui state: default_contained
- *
- * Basically default and contained combined, allowing for both
- */
-
-GLOBAL_DATUM_INIT(default_contained_state, /datum/ui_state/default/contained, new)
-
-/datum/ui_state/default/contained/can_use_topic(atom/src_object, mob/user)
- if(src_object.contains(user))
- return UI_INTERACTIVE
- return ..()
-
\ No newline at end of file
diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm
index d73d1058ea..1c885ed414 100644
--- a/code/modules/tgui/states/hands.dm
+++ b/code/modules/tgui/states/hands.dm
@@ -2,6 +2,9 @@
* tgui state: hands_state
*
* Checks that the src_object is in the user's hands.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new)
@@ -19,7 +22,7 @@ GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new)
return UI_INTERACTIVE
return UI_CLOSE
-/mob/living/silicon/robot/hands_can_use_topic(obj/src_object)
- if(activated(src_object) || istype(src_object.loc, /obj/item/weapon/gripper))
+/mob/living/silicon/robot/hands_can_use_topic(src_object)
+ if(activated(src_object))
return UI_INTERACTIVE
return UI_CLOSE
diff --git a/code/modules/tgui/states/human_adjacent.dm b/code/modules/tgui/states/human_adjacent.dm
index 7aefe43e44..2ac7c8637b 100644
--- a/code/modules/tgui/states/human_adjacent.dm
+++ b/code/modules/tgui/states/human_adjacent.dm
@@ -3,6 +3,9 @@
*
* In addition to default checks, only allows interaction for a
* human adjacent user.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(human_adjacent_state, /datum/ui_state/human_adjacent_state, new)
diff --git a/code/modules/tgui/states/inventory.dm b/code/modules/tgui/states/inventory.dm
index 43fe2cb451..dc5dd0d57e 100644
--- a/code/modules/tgui/states/inventory.dm
+++ b/code/modules/tgui/states/inventory.dm
@@ -1,7 +1,11 @@
/**
* tgui state: inventory_state
*
- * Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory.
+ * Checks that the src_object is in the user's top-level
+ * (hand, ear, pocket, belt, etc) inventory.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(inventory_state, /datum/ui_state/inventory_state, new)
diff --git a/code/modules/tgui/states/language_menu.dm b/code/modules/tgui/states/language_menu.dm
index 5c816c8922..6389b05cd5 100644
--- a/code/modules/tgui/states/language_menu.dm
+++ b/code/modules/tgui/states/language_menu.dm
@@ -1,5 +1,8 @@
/**
* tgui state: language_menu_state
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new)
diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm
index 364b59424d..16dcb7881e 100644
--- a/code/modules/tgui/states/not_incapacitated.dm
+++ b/code/modules/tgui/states/not_incapacitated.dm
@@ -2,6 +2,9 @@
* tgui state: not_incapacitated_state
*
* Checks that the user isn't incapacitated
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(not_incapacitated_state, /datum/ui_state/not_incapacitated_state, new)
@@ -24,6 +27,10 @@ GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitate
/datum/ui_state/not_incapacitated_state/can_use_topic(src_object, mob/user)
if(user.stat)
return UI_CLOSE
- if(user.incapacitated() || user.lying || (turf_check && !isturf(user.loc)))
+ if(user.incapacitated() || (turf_check && !isturf(user.loc)))
return UI_DISABLED
- return UI_INTERACTIVE
\ No newline at end of file
+ if(isliving(user))
+ var/mob/living/L = user
+ if(!(L.mobility_flags & MOBILITY_STAND))
+ return UI_DISABLED
+ return UI_INTERACTIVE
diff --git a/code/modules/tgui/states/notcontained.dm b/code/modules/tgui/states/notcontained.dm
index 642c6ce95f..1d4e6aec19 100644
--- a/code/modules/tgui/states/notcontained.dm
+++ b/code/modules/tgui/states/notcontained.dm
@@ -1,7 +1,11 @@
/**
* tgui state: notcontained_state
*
- * Checks that the user is not inside src_object, and then makes the default checks.
+ * Checks that the user is not inside src_object, and then makes the
+ * default checks.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(notcontained_state, /datum/ui_state/notcontained_state, new)
diff --git a/code/modules/tgui/states/observer.dm b/code/modules/tgui/states/observer.dm
index 86ad776b13..d105de1c0c 100644
--- a/code/modules/tgui/states/observer.dm
+++ b/code/modules/tgui/states/observer.dm
@@ -2,6 +2,9 @@
* tgui state: observer_state
*
* Checks that the user is an observer/ghost.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(observer_state, /datum/ui_state/observer_state, new)
diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm
index 88c8a291aa..3073039d14 100644
--- a/code/modules/tgui/states/physical.dm
+++ b/code/modules/tgui/states/physical.dm
@@ -2,6 +2,9 @@
* tgui state: physical_state
*
* Short-circuits the default state to only check physical distance.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new)
diff --git a/code/modules/tgui/states/self.dm b/code/modules/tgui/states/self.dm
index b0c9500fbc..4b6e3b9fd9 100644
--- a/code/modules/tgui/states/self.dm
+++ b/code/modules/tgui/states/self.dm
@@ -2,6 +2,9 @@
* tgui state: self_state
*
* Only checks that the user and src_object are the same.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(self_state, /datum/ui_state/self_state, new)
diff --git a/code/modules/tgui/states/zlevel.dm b/code/modules/tgui/states/zlevel.dm
index 5e3ccfb7de..64ea2fa1c0 100644
--- a/code/modules/tgui/states/zlevel.dm
+++ b/code/modules/tgui/states/zlevel.dm
@@ -2,6 +2,9 @@
* tgui state: z_state
*
* Only checks that the Z-level of the user and src_object are the same.
+ *
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
GLOBAL_DATUM_INIT(z_state, /datum/ui_state/z_state, new)
diff --git a/code/modules/tgui/subsystem.dm b/code/modules/tgui/subsystem.dm
deleted file mode 100644
index cbe94e2d7f..0000000000
--- a/code/modules/tgui/subsystem.dm
+++ /dev/null
@@ -1,247 +0,0 @@
-/**
- * tgui subsystem
- *
- * Contains all tgui state and subsystem code.
- */
-
-/**
- * public
- *
- * Get a open UI given a user, src_object, and ui_key and try to update it with data.
- *
- * required user mob The mob who opened/is using the UI.
- * required src_object datum The object/datum which owns the UI.
- * required ui_key string The ui_key of the UI.
- * optional ui datum/tgui The UI to be updated, if it exists.
- * optional force_open bool If the UI should be re-opened instead of updated.
- *
- * return datum/tgui The found UI.
- */
-/datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE)
- if(isnull(ui)) // No UI was passed, so look for one.
- ui = get_open_ui(user, src_object, ui_key)
-
- if(!isnull(ui))
- var/data = src_object.ui_data(user) // Get data from the src_object.
- if(!force_open) // UI is already open; update it.
- ui.push_data(data)
- else // Re-open it anyways.
- ui.reinitialize(null, data)
- return ui // We found the UI, return it.
- else
- return null // We couldn't find a UI.
-
-/**
- * private
- *
- * Get a open UI given a user, src_object, and ui_key.
- *
- * required user mob The mob who opened/is using the UI.
- * required src_object datum The object/datum which owns the UI.
- * required ui_key string The ui_key of the UI.
- *
- * return datum/tgui The found UI.
- */
-/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key)
- var/src_object_key = "[REF(src_object)]"
- if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return null // No UIs open.
- else if(isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
- return null // No UIs open for this object.
-
- for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) // Find UIs for this object.
- if(ui.user == user) // Make sure we have the right user
- return ui
-
- return null // Couldn't find a UI!
-
-/**
- * private
- *
- * Update all UIs attached to src_object.
- *
- * required src_object datum The object/datum which owns the UIs.
- *
- * return int The number of UIs updated.
- */
-/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
- var/src_object_key = "[REF(src_object)]"
- if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return 0 // Couldn't find any UIs for this object.
-
- var/update_count = 0
- for(var/ui_key in open_uis[src_object_key])
- for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
- if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid.
- ui.process(force = 1) // Update the UI.
- update_count++ // Count each UI we update.
- return update_count
-
-/**
- * private
- *
- * Close all UIs attached to src_object.
- *
- * required src_object datum The object/datum which owns the UIs.
- *
- * return int The number of UIs closed.
- */
-/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
- var/src_object_key = "[REF(src_object)]"
- if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return 0 // Couldn't find any UIs for this object.
-
- var/close_count = 0
- for(var/ui_key in open_uis[src_object_key])
- for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
- if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid.
- ui.close() // Close the UI.
- close_count++ // Count each UI we close.
- return close_count
-
-/**
- * private
- *
- * Close *ALL* UIs
- *
- * return int The number of UIs closed.
- */
-/datum/controller/subsystem/tgui/proc/close_all_uis()
- var/close_count = 0
- for(var/src_object_key in open_uis)
- for(var/ui_key in open_uis[src_object_key])
- for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
- if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid.
- ui.close() // Close the UI.
- close_count++ // Count each UI we close.
- return close_count
-
-/**
- * private
- *
- * Update all UIs belonging to a user.
- *
- * required user mob The mob who opened/is using the UI.
- * optional src_object datum If provided, only update UIs belonging this src_object.
- * optional ui_key string If provided, only update UIs with this UI key.
- *
- * return int The number of UIs updated.
- */
-/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null)
- if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
- return 0 // Couldn't find any UIs for this user.
-
- var/update_count = 0
- for(var/datum/tgui/ui in user.open_uis)
- if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
- ui.process(force = 1) // Update the UI.
- update_count++ // Count each UI we upadte.
- return update_count
-
-/**
- * private
- *
- * Close all UIs belonging to a user.
- *
- * required user mob The mob who opened/is using the UI.
- * optional src_object datum If provided, only close UIs belonging this src_object.
- * optional ui_key string If provided, only close UIs with this UI key.
- *
- * return int The number of UIs closed.
- */
-/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null)
- if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
- return 0 // Couldn't find any UIs for this user.
-
- var/close_count = 0
- for(var/datum/tgui/ui in user.open_uis)
- if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
- ui.close() // Close the UI.
- close_count++ // Count each UI we close.
- return close_count
-
-/**
- * private
- *
- * Add a UI to the list of open UIs.
- *
- * required ui datum/tgui The UI to be added.
- */
-/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
- var/src_object_key = "[REF(ui.src_object)]"
- if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object.
- else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
- open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key.
-
- // Append the UI to all the lists.
- ui.user.open_uis |= ui
- var/list/uis = open_uis[src_object_key][ui.ui_key]
- uis |= ui
- processing_uis |= ui
-
-/**
- * private
- *
- * Remove a UI from the list of open UIs.
- *
- * required ui datum/tgui The UI to be removed.
- *
- * return bool If the UI was removed or not.
- */
-/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
- var/src_object_key = "[REF(ui.src_object)]"
- if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return 0 // It wasn't open.
- else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
- return 0 // It wasn't open.
-
- processing_uis.Remove(ui) // Remove it from the list of processing UIs.
- if(ui.user) // If the user exists, remove it from them too.
- ui.user.open_uis.Remove(ui)
- var/Ukey = ui.ui_key
- var/list/uis = open_uis[src_object_key][Ukey] // Remove it from the list of open UIs.
- uis.Remove(ui)
- if(!uis.len)
- var/list/uiobj = open_uis[src_object_key]
- uiobj.Remove(Ukey)
- if(!uiobj.len)
- open_uis.Remove(src_object_key)
-
- return 1 // Let the caller know we did it.
-
-/**
- * private
- *
- * Handle client logout, by closing all their UIs.
- *
- * required user mob The mob which logged out.
- *
- * return int The number of UIs closed.
- */
-/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
- return close_user_uis(user)
-
-/**
- * private
- *
- * Handle clients switching mobs, by transferring their UIs.
- *
- * required user source The client's original mob.
- * required user target The client's new mob.
- *
- * return bool If the UIs were transferred.
- */
-/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
- if(!source || isnull(source.open_uis) || !istype(source.open_uis, /list) || open_uis.len == 0)
- return 0 // The old mob had no open UIs.
-
- if(isnull(target.open_uis) || !istype(target.open_uis, /list))
- target.open_uis = list() // Create a list for the new mob if needed.
-
- for(var/datum/tgui/ui in source.open_uis)
- ui.user = target // Inform the UIs of their new owner.
- target.open_uis.Add(ui) // Transfer all the UIs.
-
- source.open_uis.Cut() // Clear the old list.
- return 1 // Let the caller know we did it.
diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm
index 7971a940d4..d0d5ff8ebb 100644
--- a/code/modules/tgui/tgui.dm
+++ b/code/modules/tgui/tgui.dm
@@ -1,7 +1,6 @@
/**
- * tgui
- *
- * /tg/station user interface library
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
*/
/**
@@ -14,34 +13,26 @@
var/datum/src_object
/// The title of te UI.
var/title
- /// The ui_key of the UI. This allows multiple UIs for one src_object.
- var/ui_key
/// The window_id for browse() and onclose().
- var/window_id
- /// The window width.
- var/width = 0
- /// The window height
- var/height = 0
+ var/datum/tgui_window/window
+ /// Key that is used for remembering the window geometry.
+ var/window_key
+ /// Deprecated: Window size.
+ var/window_size
/// The interface (template) to be used for this UI.
var/interface
/// Update the UI every MC tick.
var/autoupdate = TRUE
/// If the UI has been initialized yet.
var/initialized = FALSE
- /// The data (and datastructure) used to initialize the UI.
- var/list/initial_data
- /// The static data used to initialize the UI.
- var/list/initial_static_data
- /// Holder for the json string, that is sent during the initial update
- var/_initial_update
+ /// Time of opening the window.
+ var/opened_at
+ /// Stops further updates when close() was called.
+ var/closing = FALSE
/// The status/visibility of the UI.
var/status = UI_INTERACTIVE
/// Topic state used to determine status/interactability.
var/datum/ui_state/state = null
- /// The parent UI.
- var/datum/tgui/master_ui
- /// Children of this UI.
- var/list/datum/tgui/children = list()
/**
* public
@@ -50,38 +41,25 @@
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object or datum which owns the UI.
- * required ui_key string The ui_key of the UI.
* required interface string The interface used to render the UI.
* optional title string The title of the UI.
- * optional width int The window width.
- * optional height int The window height.
- * optional master_ui datum/tgui The parent UI.
- * optional state datum/ui_state The state used to determine status.
+ * optional ui_x int Deprecated: Window width.
+ * optional ui_y int Deprecated: Window height.
*
* return datum/tgui The requested UI.
*/
-/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+/datum/tgui/New(mob/user, datum/src_object, interface, title, ui_x, ui_y)
+ log_tgui(user, "new [interface] fancy [user.client.prefs.tgui_fancy]")
src.user = user
src.src_object = src_object
- src.ui_key = ui_key
- // DO NOT replace with \ref here. src_object could potentially be tagged
- src.window_id = "[REF(src_object)]-[ui_key]"
+ src.window_key = "[REF(src_object)]-main"
src.interface = interface
-
if(title)
- src.title = sanitize(title)
- if(width)
- src.width = width
- if(height)
- src.height = height
-
- src.master_ui = master_ui
- if(master_ui)
- master_ui.children += src
- src.state = state
-
- var/datum/asset/assets = get_asset_datum(/datum/asset/group/tgui)
- assets.send(user)
+ src.title = title
+ src.state = src_object.ui_state()
+ // Deprecated
+ if(ui_x && ui_y)
+ src.window_size = list(ui_x, ui_y)
/**
* public
@@ -90,85 +68,53 @@
*/
/datum/tgui/proc/open()
if(!user.client)
- return // Bail if there is no client.
-
- update_status(push = FALSE) // Update the window status.
+ return null
+ if(window)
+ return null
+ process_status()
if(status < UI_UPDATE)
- return // Bail if we're not supposed to open.
-
- // Build window options
- var/window_options = "can_minimize=0;auto_format=0;"
- // If we have a width and height, use them.
- if(width && height)
- window_options += "size=[width]x[height];"
- // Remove titlebar and resize handles for a fancy window
- if(user.client.prefs.tgui_fancy)
- window_options += "titlebar=0;can_resize=0;"
+ return null
+ window = SStgui.request_pooled_window(user)
+ if(!window)
+ return null
+ opened_at = world.time
+ window.acquire_lock(src)
+ if(!window.is_ready())
+ window.initialize(inline_assets = list(
+ get_asset_datum(/datum/asset/simple/tgui),
+ ))
else
- window_options += "titlebar=1;can_resize=1;"
-
- // Generate page html
- var/html
- html = SStgui.basehtml
- // Allow the src object to override the html if needed
- html = src_object.ui_base_html(html)
- // Replace template tokens with important UI data
- // NOTE: Intentional \ref usage; tgui datums can't/shouldn't
- // be tagged, so this is an effective unwrap
- html = replacetextEx(html, "\[tgui:ref]", "\ref[src]")
-
- // Open the window.
- user << browse(html, "window=[window_id];[window_options]")
-
- // Instruct the client to signal UI when the window is closed.
- // NOTE: Intentional \ref usage; tgui datums can't/shouldn't
- // be tagged, so this is an effective unwrap
- winset(user, window_id, "on-close=\"uiclose \ref[src]\"")
-
- // Pre-fetch initial state while browser is still loading in
- // another thread
- if(!initial_data) {
- initial_data = src_object.ui_data(user)
- }
- if(!initial_static_data) {
- initial_static_data = src_object.ui_static_data(user)
- }
- _initial_update = url_encode(get_json(initial_data, initial_static_data))
-
+ window.send_message("ping")
+ window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome))
+ for(var/datum/asset/asset in src_object.ui_assets(user))
+ window.send_asset(asset)
+ window.send_message("update", get_payload(
+ with_data = TRUE,
+ with_static_data = TRUE))
SStgui.on_open(src)
/**
* public
*
- * Reinitialize the UI.
- * (Possibly with a new interface and/or data).
+ * Close the UI.
*
- * optional template string The name of the new interface.
- * optional data list The new initial data.
+ * optional can_be_suspended bool
*/
-/datum/tgui/proc/reinitialize(interface, list/data, list/static_data)
- if(interface)
- src.interface = interface
- if(data)
- initial_data = data
- if(static_data)
- initial_static_data = static_data
- open()
-
-/**
- * public
- *
- * Close the UI, and all its children.
- */
-/datum/tgui/proc/close()
- user << browse(null, "window=[window_id]") // Close the window.
- src_object.ui_close(user)
- SStgui.on_close(src)
- for(var/datum/tgui/child in children) // Loop through and close all children.
- child.close()
- children.Cut()
+/datum/tgui/proc/close(can_be_suspended = TRUE)
+ if(closing)
+ return
+ closing = TRUE
+ // If we don't have window_id, open proc did not have the opportunity
+ // to finish, therefore it's safe to skip this whole block.
+ if(window)
+ // Windows you want to keep are usually blue screens of death
+ // and we want to keep them around, to allow user to read
+ // the error message properly.
+ window.release_lock()
+ window.close(can_be_suspended)
+ src_object.ui_close(user)
+ SStgui.on_close(src)
state = null
- master_ui = null
qdel(src)
/**
@@ -176,187 +122,173 @@
*
* Enable/disable auto-updating of the UI.
*
- * required state bool Enable/disable auto-updating.
+ * required value bool Enable/disable auto-updating.
*/
-/datum/tgui/proc/set_autoupdate(state = TRUE)
- autoupdate = state
+/datum/tgui/proc/set_autoupdate(autoupdate)
+ src.autoupdate = autoupdate
+
+/**
+ * public
+ *
+ * Replace current ui.state with a new one.
+ *
+ * required state datum/ui_state/state Next state
+ */
+/datum/tgui/proc/set_state(datum/ui_state/state)
+ src.state = state
+
+/**
+ * public
+ *
+ * Makes an asset available to use in tgui.
+ *
+ * required asset datum/asset
+ */
+/datum/tgui/proc/send_asset(datum/asset/asset)
+ if(!window)
+ CRASH("send_asset() can only be called after open().")
+ window.send_asset(asset)
+
+/**
+ * public
+ *
+ * Send a full update to the client (includes static data).
+ *
+ * optional custom_data list Custom data to send instead of ui_data.
+ * optional force bool Send an update even if UI is not interactive.
+ */
+/datum/tgui/proc/send_full_update(custom_data, force)
+ if(!user.client || !initialized || closing)
+ return
+ var/should_update_data = force || status >= UI_UPDATE
+ window.send_message("update", get_payload(
+ custom_data,
+ with_data = should_update_data,
+ with_static_data = TRUE))
+
+/**
+ * public
+ *
+ * Send a partial update to the client (excludes static data).
+ *
+ * optional custom_data list Custom data to send instead of ui_data.
+ * optional force bool Send an update even if UI is not interactive.
+ */
+/datum/tgui/proc/send_update(custom_data, force)
+ if(!user.client || !initialized || closing)
+ return
+ var/should_update_data = force || status >= UI_UPDATE
+ window.send_message("update", get_payload(
+ custom_data,
+ with_data = should_update_data))
/**
* private
*
* Package the data to send to the UI, as JSON.
- * This includes the UI data and config_data.
*
- * return string The packaged JSON.
+ * return list
*/
-/datum/tgui/proc/get_json(list/data, list/static_data)
+/datum/tgui/proc/get_payload(custom_data, with_data, with_static_data)
var/list/json_data = list()
-
json_data["config"] = list(
"title" = title,
"status" = status,
"interface" = interface,
- "fancy" = user.client.prefs.tgui_fancy,
- "locked" = user.client.prefs.tgui_lock,
- "observer" = isobserver(user),
- "window" = window_id,
- // NOTE: Intentional \ref usage; tgui datums can't/shouldn't
- // be tagged, so this is an effective unwrap
- "ref" = "\ref[src]"
+ "window" = list(
+ "key" = window_key,
+ "size" = window_size,
+ "fancy" = user.client.prefs.tgui_fancy,
+ "locked" = user.client.prefs.tgui_lock
+ ),
+ "user" = list(
+ "name" = "[user]",
+ "ckey" = "[user.ckey]",
+ "observer" = isobserver(user)
+ )
)
-
- if(!isnull(data))
+ var/data = custom_data || with_data && src_object.ui_data(user)
+ if(data)
json_data["data"] = data
- if(!isnull(static_data))
+ var/static_data = with_static_data && src_object.ui_static_data(user)
+ if(static_data)
json_data["static_data"] = static_data
-
- // Send shared states
if(src_object.tgui_shared_states)
json_data["shared"] = src_object.tgui_shared_states
-
- // Generate the JSON.
- var/json = json_encode(json_data)
- // Strip #255/improper.
- json = replacetext(json, "\proper", "")
- json = replacetext(json, "\improper", "")
- return json
+ return json_data
/**
* private
*
- * Handle clicks from the UI.
- * Call the src_object's ui_act() if status is UI_INTERACTIVE.
- * If the src_object's ui_act() returns 1, update all UIs attacked to it.
- */
-/datum/tgui/Topic(href, href_list)
- if(user != usr)
- return // Something is not right here.
-
- var/action = href_list["action"]
- var/params = href_list; params -= "action"
-
- switch(action)
- if("tgui:initialize")
- user << output(_initial_update, "[window_id].browser:update")
- initialized = TRUE
- if("tgui:setSharedState")
- // Update the window state.
- update_status(push = FALSE)
- // Bail if UI is not interactive or usr calling Topic
- // is not the UI user.
- if(status != UI_INTERACTIVE)
- return
- var/key = params["key"]
- var/value = params["value"]
- if(!src_object.tgui_shared_states)
- src_object.tgui_shared_states = list()
- src_object.tgui_shared_states[key] = value
- SStgui.update_uis(src_object)
- if("tgui:setFancy")
- var/value = text2num(params["value"])
- user.client.prefs.tgui_fancy = value
- if("tgui:log")
- // Force window to show frills on fatal errors
- if(params["fatal"])
- winset(user, window_id, "titlebar=1;can-resize=1;size=600x600")
- log_message(params["log"])
- if("tgui:link")
- user << link(params["url"])
- else
- // Update the window state.
- update_status(push = FALSE)
- // Call ui_act() on the src_object.
- if(src_object.ui_act(action, params, src, state))
- // Update if the object requested it.
- SStgui.update_uis(src_object)
-
-/**
- * private
- *
- * Update the UI.
- * Only updates the data if update is true, otherwise only updates the status.
- *
- * optional force bool If the UI should be forced to update.
+ * Run an update cycle for this UI. Called internally by SStgui
+ * every second or so.
*/
/datum/tgui/process(force = FALSE)
+ if(closing)
+ return
var/datum/host = src_object.ui_host(user)
- if(!src_object || !host || !user) // If the object or user died (or something else), abort.
+ // If the object or user died (or something else), abort.
+ if(!src_object || !host || !user || !window)
+ close(can_be_suspended = FALSE)
+ return
+ // Validate ping
+ if(!initialized && world.time - opened_at > TGUI_PING_TIMEOUT)
+ log_tgui(user, \
+ "Error: Zombie window detected, killing it with fire.\n" \
+ + "window_id: [window.id]\n" \
+ + "opened_at: [opened_at]\n" \
+ + "world.time: [world.time]")
+ close(can_be_suspended = FALSE)
+ return
+ // Update through a normal call to ui_interact
+ if(status != UI_DISABLED && (autoupdate || force))
+ src_object.ui_interact(user, src)
+ return
+ // Update status only
+ var/needs_update = process_status()
+ if(status <= UI_CLOSE)
close()
return
-
- if(status && (force || autoupdate))
- update() // Update the UI if the status and update settings allow it.
- else
- update_status(push = TRUE) // Otherwise only update status.
+ if(needs_update)
+ window.send_message("update", get_payload())
/**
* private
*
- * Push data to an already open UI.
- *
- * required data list The data to send.
- * optional force bool If the update should be sent regardless of state.
+ * Updates the status, and returns TRUE if status has changed.
*/
-/datum/tgui/proc/push_data(data, static_data, force = FALSE)
- // Update the window state.
- update_status(push = FALSE)
- // Cannot update UI if it is not set up yet.
- if(!initialized)
- return
- // Cannot update UI, we have no visibility.
- if(status <= UI_DISABLED && !force)
- return
- // Send the new JSON to the update() Javascript function.
- user << output(
- url_encode(get_json(data, static_data)),
- "[window_id].browser:update")
+/datum/tgui/proc/process_status()
+ var/prev_status = status
+ status = src_object.ui_status(user, state)
+ return prev_status != status
/**
* private
*
- * Updates the UI by interacting with the src_object again, which will hopefully
- * call try_ui_update on it.
- *
- * optional force_open bool If force_open should be passed to ui_interact.
+ * Callback for handling incoming tgui messages.
*/
-/datum/tgui/proc/update(force_open = FALSE)
- src_object.ui_interact(user, ui_key, src, force_open, master_ui, state)
-
-/**
- * private
- *
- * Update the status/visibility of the UI for its user.
- *
- * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
- */
-/datum/tgui/proc/update_status(push = FALSE)
- var/status = src_object.ui_status(user, state)
- if(master_ui)
- status = min(status, master_ui.status)
- set_status(status, push)
- if(status == UI_CLOSE)
- close()
-
-/**
- * private
- *
- * Set the status/visibility of the UI.
- *
- * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE).
- * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
- */
-/datum/tgui/proc/set_status(status, push = FALSE)
- // Only update if status has changed.
- if(src.status != status)
- if(src.status == UI_DISABLED)
- src.status = status
- if(push)
- update()
- else
- src.status = status
- // Update if the UI just because disabled, or a push is requested.
- if(status == UI_DISABLED || push)
- push_data(null, force = TRUE)
-
-/datum/tgui/proc/log_message(message)
- log_tgui("[user] ([user.ckey]) using \"[title]\":\n[message]")
+/datum/tgui/proc/on_message(type, list/payload, list/href_list)
+ // Pass act type messages to ui_act
+ if(type && copytext(type, 1, 5) == "act/")
+ process_status()
+ if(src_object.ui_act(copytext(type, 5), payload, src, state))
+ SStgui.update_uis(src_object)
+ return FALSE
+ switch(type)
+ if("ready")
+ initialized = TRUE
+ if("pingReply")
+ initialized = TRUE
+ if("suspend")
+ close(can_be_suspended = TRUE)
+ if("close")
+ close(can_be_suspended = FALSE)
+ if("log")
+ if(href_list["fatal"])
+ close(can_be_suspended = FALSE)
+ if("setSharedState")
+ if(status != UI_INTERACTIVE)
+ return
+ LAZYINITLIST(src_object.tgui_shared_states)
+ src_object.tgui_shared_states[href_list["key"]] = href_list["value"]
+ SStgui.update_uis(src_object)
diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm
new file mode 100644
index 0000000000..3f271163c9
--- /dev/null
+++ b/code/modules/tgui/tgui_window.dm
@@ -0,0 +1,238 @@
+/**
+ * Copyright (c) 2020 Aleksej Komarov
+ * SPDX-License-Identifier: MIT
+ */
+
+/datum/tgui_window
+ var/id
+ var/client/client
+ var/pooled
+ var/pool_index
+ var/status = TGUI_WINDOW_CLOSED
+ var/locked = FALSE
+ var/datum/tgui/locked_by
+ var/fatally_errored = FALSE
+ var/message_queue
+ var/sent_assets = list()
+
+/**
+ * public
+ *
+ * Create a new tgui window.
+ *
+ * required client /client
+ * required id string A unique window identifier.
+ */
+/datum/tgui_window/New(client/client, id, pooled = FALSE)
+ src.id = id
+ src.client = client
+ src.pooled = pooled
+ if(pooled)
+ client.tgui_windows[id] = src
+ src.pool_index = TGUI_WINDOW_INDEX(id)
+
+/**
+ * public
+ *
+ * Initializes the window with a fresh page. Puts window into the "loading"
+ * state. You can begin sending messages right after initializing. Messages
+ * will be put into the queue until the window finishes loading.
+ *
+ * optional inline_assets list List of assets to inline into the html.
+ */
+/datum/tgui_window/proc/initialize(inline_assets = list())
+ log_tgui(client, "[id]/initialize")
+ if(!client)
+ return
+ status = TGUI_WINDOW_LOADING
+ fatally_errored = FALSE
+ message_queue = null
+ // Build window options
+ var/options = "file=[id].html;can_minimize=0;auto_format=0;"
+ // Remove titlebar and resize handles for a fancy window
+ if(client.prefs.tgui_fancy)
+ options += "titlebar=0;can_resize=0;"
+ else
+ options += "titlebar=1;can_resize=1;"
+ // Generate page html
+ var/html = SStgui.basehtml
+ html = replacetextEx(html, "\[tgui:windowId]", id)
+ // Process inline assets
+ var/inline_styles = ""
+ var/inline_scripts = ""
+ for(var/datum/asset/asset in inline_assets)
+ var/mappings = asset.get_url_mappings()
+ for(var/name in mappings)
+ var/url = mappings[name]
+ // Not urlencoding since asset strings are considered safe
+ if(copytext(name, -4) == ".css")
+ inline_styles += "\n"
+ else if(copytext(name, -3) == ".js")
+ inline_scripts += "\n"
+ asset.send()
+ html = replacetextEx(html, "\n", inline_styles)
+ html = replacetextEx(html, "\n", inline_scripts)
+ // Open the window
+ client << browse(html, "window=[id];[options]")
+ // Instruct the client to signal UI when the window is closed.
+ winset(client, id, "on-close=\"uiclose [id]\"")
+
+/**
+ * public
+ *
+ * Checks if the window is ready to receive data.
+ *
+ * return bool
+ */
+/datum/tgui_window/proc/is_ready()
+ return status == TGUI_WINDOW_READY
+
+/**
+ * public
+ *
+ * Checks if the window can be sanely suspended.
+ *
+ * return bool
+ */
+/datum/tgui_window/proc/can_be_suspended()
+ return !fatally_errored \
+ && pooled \
+ && pool_index > 0 \
+ && pool_index <= TGUI_WINDOW_SOFT_LIMIT \
+ && status == TGUI_WINDOW_READY
+
+/**
+ * public
+ *
+ * Acquire the window lock. Pool will not be able to provide this window
+ * to other UIs for the duration of the lock.
+ *
+ * Can be given an optional tgui datum, which will hook its on_message
+ * callback into the message stream.
+ *
+ * optional ui /datum/tgui
+ */
+/datum/tgui_window/proc/acquire_lock(datum/tgui/ui)
+ locked = TRUE
+ locked_by = ui
+
+/**
+ * Release the window lock.
+ */
+/datum/tgui_window/proc/release_lock()
+ // Clean up assets sent by tgui datum which requested the lock
+ if(locked)
+ sent_assets = list()
+ locked = FALSE
+ locked_by = null
+
+/**
+ * public
+ *
+ * Close the UI.
+ *
+ * optional can_be_suspended bool
+ */
+/datum/tgui_window/proc/close(can_be_suspended = TRUE)
+ if(!client)
+ return
+ if(can_be_suspended && can_be_suspended())
+ log_tgui(client, "[id]/close: suspending")
+ status = TGUI_WINDOW_READY
+ send_message("suspend")
+ return
+ log_tgui(client, "[id]/close")
+ release_lock()
+ status = TGUI_WINDOW_CLOSED
+ message_queue = null
+ // Do not close the window to give user some time
+ // to read the error message.
+ if(!fatally_errored)
+ client << browse(null, "window=[id]")
+
+/**
+ * public
+ *
+ * Sends a message to tgui window.
+ *
+ * required type string Message type
+ * required payload list Message payload
+ * optional force bool Send regardless of the ready status.
+ */
+/datum/tgui_window/proc/send_message(type, list/payload, force)
+ if(!client)
+ return
+ var/message = json_encode(list(
+ "type" = type,
+ "payload" = payload,
+ ))
+ // Strip #255/improper.
+ message = replacetext(message, "\proper", "")
+ message = replacetext(message, "\improper", "")
+ // Pack for sending via output()
+ message = url_encode(message)
+ // Place into queue if window is still loading
+ if(!force && status != TGUI_WINDOW_READY)
+ if(!message_queue)
+ message_queue = list()
+ message_queue += list(message)
+ return
+ client << output(message, "[id].browser:update")
+
+/**
+ * public
+ *
+ * Makes an asset available to use in tgui.
+ *
+ * required asset datum/asset
+ */
+/datum/tgui_window/proc/send_asset(datum/asset/asset)
+ if(!client || !asset)
+ return
+ if(istype(asset, /datum/asset/spritesheet))
+ var/datum/asset/spritesheet/spritesheet = asset
+ send_message("asset/stylesheet", spritesheet.css_filename())
+ send_message("asset/mappings", asset.get_url_mappings())
+ sent_assets += list(asset)
+ asset.send(client)
+
+/**
+ * private
+ *
+ * Sends queued messages if the queue wasn't empty.
+ */
+/datum/tgui_window/proc/flush_message_queue()
+ if(!client || !message_queue)
+ return
+ for(var/message in message_queue)
+ client << output(message, "[id].browser:update")
+ message_queue = null
+
+/**
+ * private
+ *
+ * Callback for handling incoming tgui messages.
+ */
+/datum/tgui_window/proc/on_message(type, list/payload, list/href_list)
+ switch(type)
+ if("ready")
+ // Status can be READY if user has refreshed the window.
+ if(status == TGUI_WINDOW_READY)
+ // Resend the assets
+ for(var/asset in sent_assets)
+ send_asset(asset)
+ status = TGUI_WINDOW_READY
+ if("log")
+ if(href_list["fatal"])
+ fatally_errored = TRUE
+ // Pass message to UI that requested the lock
+ if(locked && locked_by)
+ locked_by.on_message(type, payload, href_list)
+ flush_message_queue()
+ return
+ // If not locked, handle these message types
+ switch(type)
+ if("suspend")
+ close(can_be_suspended = TRUE)
+ if("close")
+ close(can_be_suspended = FALSE)
diff --git a/code/modules/uplink/uplink_items/uplink_ammo.dm b/code/modules/uplink/uplink_items/uplink_ammo.dm
index ce74773f8d..853f6111b2 100644
--- a/code/modules/uplink/uplink_items/uplink_ammo.dm
+++ b/code/modules/uplink/uplink_items/uplink_ammo.dm
@@ -291,10 +291,17 @@
/datum/uplink_item/ammo/bolt_action
name = "Surplus Rifle Clip"
desc = "A stripper clip used to quickly load bolt action rifles. Contains 5 rounds."
- item = /obj/item/ammo_box/a762
+ item = /obj/item/ammo_box/a762
cost = 1
include_modes = list(/datum/game_mode/nuclear)
+/datum/uplink_item/ammo/bolt_action_bulk
+ name = "Surplus Rifle Clip Box"
+ desc = "An ammo box we found in a warehouse, holding 7 clips of 5 rounds for bolt-action rifles. Yes, the cheap ones."
+ item = /obj/item/storage/toolbox/ammo
+ cost = 4
+ include_modes = list(/datum/game_mode/nuclear)
+
/datum/uplink_item/ammo/dark_gygax/bag
name = "Dark Gygax Ammo Bag"
desc = "A duffel bag containing ammo for three full reloads of the incendiary carbine and flash bang launcher that are equipped on a standard Dark Gygax exosuit."
diff --git a/code/modules/uplink/uplink_items/uplink_bundles.dm b/code/modules/uplink/uplink_items/uplink_bundles.dm
index d40e2fcbda..1b7909a50d 100644
--- a/code/modules/uplink/uplink_items/uplink_bundles.dm
+++ b/code/modules/uplink/uplink_items/uplink_bundles.dm
@@ -50,7 +50,7 @@
Combines with all martial arts, but the user will be unable to bring themselves to use guns, nor remove the armbands."
item = /obj/item/storage/box/syndie_kit/northstar
cost = 20
- exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/suits/infiltrator_bundle
name = "Insidious Infiltration Gear Case"
@@ -117,7 +117,7 @@
you will receive. May contain discontinued and/or exotic items."
item = /obj/item/storage/box/syndicate
cost = 20
- exclude_modes = list(/datum/game_mode/nuclear)
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/traitor/internal_affairs)
cant_discount = TRUE
/datum/uplink_item/bundles_TC/surplus
@@ -127,7 +127,7 @@
item = /obj/structure/closet/crate
cost = 20
player_minimum = 25
- exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
cant_discount = TRUE
var/starting_crate_value = 50
@@ -163,7 +163,7 @@
/datum/uplink_item/bundles_TC/reroll
name = "Renegotiate Contract"
- desc = "Selecting this will inform the syndicate that you wish to change employers. Can only be done once; no take-backs."
+ desc = "Selecting this will inform your employers that you wish for new objectives. Can only be done once; no take-backs."
item = /obj/effect/gibspawner/generic
cost = 0
cant_discount = TRUE
@@ -173,8 +173,7 @@
/datum/uplink_item/bundles_TC/reroll/purchase(mob/user, datum/component/uplink/U)
var/datum/antagonist/traitor/T = user?.mind?.has_antag_datum(/datum/antagonist/traitor)
if(istype(T))
- var/new_traitor_kind = get_random_traitor_kind(list(T.traitor_kind.type))
- T.set_traitor_kind(new_traitor_kind)
+ T.set_traitor_kind(/datum/traitor_class/human/subterfuge)
else
to_chat(user,"Invalid user for contract renegotiation.")
@@ -184,6 +183,7 @@
item = /obj/effect/gibspawner/generic // non-tangible item because techwebs use this path to determine illegal tech
cost = 0
cant_discount = TRUE
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/bundles_TC/random/purchase(mob/user, datum/component/uplink/U)
var/list/uplink_items = U.uplink_items
diff --git a/code/modules/uplink/uplink_items/uplink_dangerous.dm b/code/modules/uplink/uplink_items/uplink_dangerous.dm
index 7d96390115..a43e3fc2ce 100644
--- a/code/modules/uplink/uplink_items/uplink_dangerous.dm
+++ b/code/modules/uplink/uplink_items/uplink_dangerous.dm
@@ -21,7 +21,7 @@
item = /obj/item/storage/box/syndie_kit/revolver
cost = 13
surplus = 50
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/dangerous/rawketlawnchair
name = "84mm Rocket Propelled Grenade Launcher"
@@ -112,7 +112,7 @@
item = /obj/item/dualsaber
player_minimum = 25
cost = 16
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/dangerous/doublesword/get_discount()
return pick(4;0.8,2;0.65,1;0.5)
@@ -123,7 +123,7 @@
pocketed when inactive. Activating it produces a loud, distinctive noise."
item = /obj/item/melee/transforming/energy/sword/saber
cost = 8
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/dangerous/shield
name = "Energy Shield"
@@ -141,7 +141,7 @@
However, due to the size of the blade and obvious nature of the sheath, the weapon stands out as being obviously nefarious."
item = /obj/item/storage/belt/sabre/rapier
cost = 8
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/dangerous/flamethrower
name = "Flamethrower"
@@ -180,11 +180,22 @@
refundable = TRUE
cant_discount = TRUE
surplus = 0
- exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
player_minimum = 25
restricted = TRUE
refund_path = /obj/item/guardiancreator/tech/choose/traitor
+/datum/uplink_item/dangerous/nukieguardian // just like the normal holoparasites but without the support or deffensive stands because nukies shouldnt turtle
+ name = "Holoparasites"
+ desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an \
+ organic host as a home base and source of fuel. Holoparasites come in various types and share damage with their host."
+ item = /obj/item/storage/box/syndie_kit/nukieguardian
+ cost = 15
+ refundable = TRUE
+ surplus = 50
+ refund_path = /obj/item/guardiancreator/tech/choose/nukie
+ include_modes = list(/datum/game_mode/nuclear)
+
/datum/uplink_item/dangerous/machinegun
name = "L6 Squad Automatic Weapon"
desc = "A fully-loaded Aussec Armoury belt-fed machine gun. \
@@ -211,6 +222,7 @@
deal extra damage and hit targets further. Use a screwdriver to take out any attached tanks."
item = /obj/item/melee/powerfist
cost = 8
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/dangerous/sniper
name = "Sniper Rifle"
@@ -250,4 +262,4 @@
darts effective at incapacitating a target."
item = /obj/item/gun/ballistic/automatic/toy/pistol/riot
cost = 3
- surplus = 10
\ No newline at end of file
+ surplus = 10
diff --git a/code/modules/uplink/uplink_items/uplink_devices.dm b/code/modules/uplink/uplink_items/uplink_devices.dm
index ccaa998cf7..5f5eb91a04 100644
--- a/code/modules/uplink/uplink_items/uplink_devices.dm
+++ b/code/modules/uplink/uplink_items/uplink_devices.dm
@@ -147,6 +147,12 @@
item = /obj/item/aiModule/syndicate
cost = 9
+/datum/uplink_item/device_tools/damaged_module
+ name = "Damaged AI Law Upload Module"
+ desc = "This AI law upload module has been laying around our warehouse for god knows how long. We do not know why you would ever use this."
+ item = /obj/item/aiModule/core/full/damaged
+ cost = 5
+
/datum/uplink_item/device_tools/headsetupgrade
name = "Headset Upgrader"
desc = "A device that can be used to make one headset immune to flashbangs."
@@ -200,16 +206,14 @@
this primer of questionable worth and value is rumored to increase your rifle-bolt-working and/or shotgun \
racking fivefold. Then again, the techniques here only work on bolt-actions and pump-actions..."
item = /obj/item/book/granter/trait/rifleman
- cost = 3
- restricted_roles = list("Operative") // i want it to be surplusable but i also want it to be mostly nukie only, please advise
- surplus = 90
+ cost = 3 // fuck it available for everyone
/datum/uplink_item/device_tools/stimpack
name = "Stimpack"
- desc = "Stimpacks, the tool of many great heroes, make you nearly immune to stuns and knockdowns for about \
+ desc = "Stimpacks, the tool of many great heroes. Makes you nearly immune to non-lethal weaponry for about \
5 minutes after injection."
item = /obj/item/reagent_containers/syringe/stimulants
- cost = 3
+ cost = 5
surplus = 90
/datum/uplink_item/device_tools/medkit
diff --git a/code/modules/uplink/uplink_items/uplink_explosives.dm b/code/modules/uplink/uplink_items/uplink_explosives.dm
index c52651fee9..6cc1c9fe05 100644
--- a/code/modules/uplink/uplink_items/uplink_explosives.dm
+++ b/code/modules/uplink/uplink_items/uplink_explosives.dm
@@ -58,6 +58,7 @@
item = /obj/item/storage/backpack/duffelbag/syndie/x4
cost = 4 //
cant_discount = TRUE
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/explosives/clown_bomb_clownops
name = "Clown Bomb"
@@ -123,6 +124,7 @@
be defused, and some crew may attempt to do so."
item = /obj/item/sbeacondrop/bomb
cost = 11
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/explosives/syndicate_detonator
name = "Syndicate Detonator"
@@ -140,7 +142,7 @@
in addition to dealing high amounts of damage to nearby personnel."
item = /obj/item/grenade/syndieminibomb
cost = 6
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/explosives/tearstache
name = "Teachstache Grenade"
diff --git a/code/modules/uplink/uplink_items/uplink_implants.dm b/code/modules/uplink/uplink_items/uplink_implants.dm
index 02b8b1e01d..bb4e0c7960 100644
--- a/code/modules/uplink/uplink_items/uplink_implants.dm
+++ b/code/modules/uplink/uplink_items/uplink_implants.dm
@@ -29,6 +29,13 @@
item = /obj/item/storage/box/syndie_kit/imp_freedom
cost = 5
+/datum/uplink_item/implants/warp
+ name = "Warp Implant"
+ desc = "An implant injected into the body and later activated at the user's will. It will inject eigenstasium which saves the user's location and teleports them there after five seconds. Lasts only fifteen times."
+ item = /obj/item/storage/box/syndie_kit/imp_warp
+ cost = 6
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+
/datum/uplink_item/implants/hijack
name = "Hijack Implant"
desc = "An implant that will let you hack into the APCs on station, allowing you to control them at will and the machinery within those rooms."
diff --git a/code/modules/uplink/uplink_items/uplink_roles.dm b/code/modules/uplink/uplink_items/uplink_roles.dm
index 859c8c0bd7..b8eaf41371 100644
--- a/code/modules/uplink/uplink_items/uplink_roles.dm
+++ b/code/modules/uplink/uplink_items/uplink_roles.dm
@@ -30,6 +30,7 @@
item = /obj/item/gun/blastcannon
cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled gas masked scientist.
restricted_roles = list("Research Director", "Scientist")
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/role_restricted/alientech
name = "Alien Research Disk"
@@ -100,6 +101,7 @@
player_minimum = 20
refundable = TRUE
restricted_roles = list("Chaplain")
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/role_restricted/arcane_tome
name = "Arcane Tome"
@@ -109,6 +111,7 @@
player_minimum = 20
refundable = TRUE
restricted_roles = list("Chaplain")
+ exclude_modes = list(/datum/game_mode/traitor/internal_affairs)
/datum/uplink_item/role_restricted/explosive_hot_potato
name = "Exploding Hot Potato"
diff --git a/code/modules/uplink/uplink_items/uplink_stealth.dm b/code/modules/uplink/uplink_items/uplink_stealth.dm
index c60d4ef177..ff6d66a483 100644
--- a/code/modules/uplink/uplink_items/uplink_stealth.dm
+++ b/code/modules/uplink/uplink_items/uplink_stealth.dm
@@ -65,6 +65,16 @@
surplus = 0
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+/datum/uplink_item/stealthy_weapons/martialartsthree
+ name = "Krav Maga Scroll"
+ desc = "This scroll contains the secrets of an ancient martial arts technique. You will gain special unarmed attacks for \
+ stealthy takedowns."
+ item = /obj/item/book/granter/martial/krav_maga
+ cost = 16
+ player_minimum = 25
+ surplus = 0
+ include_modes = list(/datum/game_mode/traitor/internal_affairs)
+
/datum/uplink_item/stealthy_weapons/crossbow
name = "Miniature Energy Crossbow"
desc = "A short bow mounted across a tiller in miniature. Small enough to \
diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm
index fb30e66f97..4545fab2a7 100644
--- a/code/modules/vehicles/cars/car.dm
+++ b/code/modules/vehicles/cars/car.dm
@@ -57,7 +57,7 @@
return FALSE
return ..()
-/obj/vehicle/sealed/car/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/vehicle/sealed/car/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(!(car_traits & CAN_KIDNAP))
return
diff --git a/code/modules/vehicles/pimpin_ride.dm b/code/modules/vehicles/pimpin_ride.dm
index 547eef7af2..8f9d553ec7 100644
--- a/code/modules/vehicles/pimpin_ride.dm
+++ b/code/modules/vehicles/pimpin_ride.dm
@@ -62,11 +62,8 @@
if(floorbuffer)
. += "cart_buffer"
-/obj/vehicle/ridden/janicart/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- . = ..()
- if(.)
- return
- else if(mybag)
+/obj/vehicle/ridden/janicart/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+ if(mybag)
mybag.forceMove(get_turf(user))
user.put_in_hands(mybag)
mybag = null
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index fca137a87d..a115300085 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -479,7 +479,7 @@ GLOBAL_LIST_EMPTY(vending_products)
var/crit_case
if(crit)
- crit_case = rand(1,5)
+ crit_case = rand(1,6)
if(forcecrit)
crit_case = forcecrit
@@ -491,7 +491,7 @@ GLOBAL_LIST_EMPTY(vending_products)
if(istype(C))
var/crit_rebate = 0 // lessen the normal damage we deal for some of the crits
- if(crit_case != 5) // the head asplode case has its own description
+ if(crit_case < 5) // the head asplode case has its own description
C.visible_message("[C] is crushed by [src]!", \
"You are crushed by [src]!")
@@ -526,7 +526,17 @@ GLOBAL_LIST_EMPTY(vending_products)
// the new paraplegic gets like 4 lines of losing their legs so skip them
visible_message("[C]'s spinal cord is obliterated with a sickening crunch!", ignored_mobs = list(C))
C.gain_trauma(/datum/brain_trauma/severe/paralysis/spinesnapped)
- if(5) // skull squish!
+ if(5) // limb squish!
+ for(var/i in C.bodyparts)
+ var/obj/item/bodypart/squish_part = i
+ if(squish_part.is_organic_limb())
+ var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate))
+ squish_part.force_wound_upwards(type_wound)
+ else
+ squish_part.receive_damage(brute=30)
+ C.visible_message("[C]'s body is maimed underneath the mass of [src]!", \
+ "Your body is maimed underneath the mass of [src]!")
+ if(6) // skull squish!
var/obj/item/bodypart/head/O = C.get_bodypart(BODY_ZONE_HEAD)
if(O)
C.visible_message("[O] explodes in a shower of gore beneath [src]!", \
@@ -536,7 +546,11 @@ GLOBAL_LIST_EMPTY(vending_products)
qdel(O)
new /obj/effect/gibspawner/human/bodypartless(get_turf(C))
- C.apply_damage(max(0, squish_damage - crit_rebate), forced=TRUE, spread_damage=TRUE)
+ if(prob(30))
+ C.apply_damage(max(0, squish_damage - crit_rebate), forced=TRUE, spread_damage=TRUE) // the 30% chance to spread the damage means you escape breaking any bones
+ else
+ C.take_bodypart_damage((squish_damage - crit_rebate)*0.5, wound_bonus = 5) // otherwise, deal it to 2 random limbs (or the same one) which will likely shatter something
+ C.take_bodypart_damage((squish_damage - crit_rebate)*0.5, wound_bonus = 5)
C.AddElement(/datum/element/squish, 18 SECONDS)
else
L.visible_message("[L] is crushed by [src]!", \
@@ -562,7 +576,7 @@ GLOBAL_LIST_EMPTY(vending_products)
"You right [src].")
unbuckle_all_mobs(TRUE)
-
+ anchored = FALSE //so you can push it back into position
tilted = FALSE
layer = initial(layer)
@@ -658,21 +672,21 @@ GLOBAL_LIST_EMPTY(vending_products)
return
return ..()
-/obj/machinery/vending/ui_base_html(html)
- var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending)
- . = replacetext(html, "", assets.css_tag())
+/obj/machinery/vending/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/vending),
+ )
-/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/vending/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending)
- assets.send(user)
- ui = new(user, src, ui_key, "Vending", ui_key, 450, 600, master_ui, state)
+ ui = new(user, src, "Vending")
ui.open()
/obj/machinery/vending/ui_static_data(mob/user)
. = list()
.["onstation"] = onstation
+ .["department"] = payment_department
.["product_records"] = list()
for (var/datum/data/vending_product/R in product_records)
var/list/data = list(
@@ -699,7 +713,7 @@ GLOBAL_LIST_EMPTY(vending_products)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
- price = R.custom_price || default_price,
+ price = R.custom_premium_price || extra_price, //may cause breakage. please note
max_amount = R.max_amount,
ref = REF(R),
premium = TRUE
@@ -708,28 +722,24 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/machinery/vending/ui_data(mob/user)
. = list()
- var/obj/item/card/id/C = user.get_idcard(TRUE)
- .["cost_mult"] = 1
- .["cost_text"] = ""
- if(C && C.registered_account)
- .["user"] = list()
- .["user"]["name"] = C.registered_account.account_holder
- .["user"]["cash"] = C.registered_account.account_balance
- if(C.registered_account.account_job)
- .["user"]["job"] = C.registered_account.account_job.title
- else
- .["user"]["job"] = "No Job"
- var/cost_mult = get_best_discount(C)
- if(cost_mult != 1)
- .["cost_mult"] = cost_mult
- if(cost_mult < 1)
- .["cost_text"] = " ([(1 - cost_mult) * 100]% OFF)"
+ var/mob/living/carbon/human/H
+ var/obj/item/card/id/C
+ if(ishuman(user))
+ H = user
+ C = H.get_idcard(TRUE)
+ if(C?.registered_account)
+ .["user"] = list()
+ .["user"]["name"] = C.registered_account.account_holder
+ .["user"]["cash"] = C.registered_account.account_balance
+ if(C.registered_account.account_job)
+ .["user"]["job"] = C.registered_account.account_job.title
+ .["user"]["department"] = C.registered_account.account_job.paycheck_department
else
- .["cost_text"] = " ([(cost_mult - 1) * 100]% EXTRA)"
+ .["user"]["job"] = "No Job"
+ .["user"]["department"] = "No Department"
.["stock"] = list()
for (var/datum/data/vending_product/R in product_records + coin_records + hidden_records)
.["stock"][R.name] = R.amount
- .
.["extended_inventory"] = extended_inventory
/obj/machinery/vending/ui_act(action, params)
@@ -752,7 +762,9 @@ GLOBAL_LIST_EMPTY(vending_products)
if(!R || !istype(R) || !R.product_path)
vend_ready = TRUE
return
- var/price_to_use = R.custom_price || default_price
+ var/price_to_use = default_price
+ if(R.custom_price)
+ price_to_use = R.custom_price
if(R in hidden_records)
if(!extended_inventory)
vend_ready = TRUE
@@ -766,8 +778,10 @@ GLOBAL_LIST_EMPTY(vending_products)
flick(icon_deny,src)
vend_ready = TRUE
return
- if(onstation && price_to_use >= 0)
- var/obj/item/card/id/C = usr.get_idcard(TRUE)
+ if(onstation && ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/card/id/C = H.get_idcard(TRUE)
+
if(!C)
say("No card found.")
flick(icon_deny,src)
@@ -778,11 +792,20 @@ GLOBAL_LIST_EMPTY(vending_products)
flick(icon_deny,src)
vend_ready = TRUE
return
+ // else if(age_restrictions && R.age_restricted && (!C.registered_age || C.registered_age < AGE_MINOR))
+ // say("You are not of legal age to purchase [R.name].")
+ // if(!(usr in GLOB.narcd_underages))
+ // Radio.set_frequency(FREQ_SECURITY)
+ // Radio.talk_into(src, "SECURITY ALERT: Underaged crewmember [H] recorded attempting to purchase [R.name] in [get_area(src)]. Please watch for substance abuse.", FREQ_SECURITY)
+ // GLOB.narcd_underages += H
+ // flick(icon_deny,src)
+ // vend_ready = TRUE
+ // return
var/datum/bank_account/account = C.registered_account
- if(coin_records.Find(R))
- price_to_use = R.custom_premium_price || extra_price
- else if(!hidden_records.Find(R))
- price_to_use = round(price_to_use * get_best_discount(C))
+ if(account.account_job && account.account_job.paycheck_department == payment_department)
+ price_to_use = 0
+ if(coin_records.Find(R) || hidden_records.Find(R))
+ price_to_use = R.custom_premium_price ? R.custom_premium_price : extra_price
if(price_to_use && !account.adjust_money(-price_to_use))
say("You do not possess the funds to purchase [R.name].")
flick(icon_deny,src)
@@ -791,6 +814,8 @@ GLOBAL_LIST_EMPTY(vending_products)
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
if(D)
D.adjust_money(price_to_use)
+ SSblackbox.record_feedback("amount", "vending_spent", price_to_use)
+ //log_econ("[price_to_use] credits were inserted into [src] by [D.account_holder] to buy [R].")
if(last_shopper != usr || purchase_message_cooldown < world.time)
say("Thank you for shopping with [src]!")
purchase_message_cooldown = world.time + 5 SECONDS
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 9dfb4c76a0..bc824cc994 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -84,8 +84,10 @@
/obj/item/clothing/suit/poncho = 1,
/obj/item/clothing/suit/poncho/green = 1,
/obj/item/clothing/suit/poncho/red = 1,
+ /obj/item/clothing/head/maid = 1,
/obj/item/clothing/under/costume/maid = 1,
/obj/item/clothing/under/rank/civilian/janitor/maid = 1,
+ /obj/item/clothing/gloves/evening = 1,
/obj/item/clothing/glasses/cold=1,
/obj/item/clothing/glasses/heat=1,
/obj/item/clothing/suit/whitedress = 1,
@@ -114,7 +116,8 @@
/obj/item/gun/magic/wand = 2,
/obj/item/clothing/glasses/sunglasses/garb = 2,
/obj/item/clothing/glasses/sunglasses/blindfold = 1,
- /obj/item/clothing/mask/muzzle = 2)
+ /obj/item/clothing/mask/muzzle = 2,
+ /obj/item/clothing/under/syndicate/camo/cosmetic = 3)
premium = list(/obj/item/clothing/suit/pirate/captain = 2,
/obj/item/clothing/head/pirate/captain = 2,
/obj/item/clothing/head/helmet/roman/fake = 1,
diff --git a/code/modules/vending/cartridge.dm b/code/modules/vending/cartridge.dm
index beaf6bb873..69635007c9 100644
--- a/code/modules/vending/cartridge.dm
+++ b/code/modules/vending/cartridge.dm
@@ -10,6 +10,7 @@
/obj/item/cartridge/security = 10,
/obj/item/cartridge/janitor = 10,
/obj/item/cartridge/signal/toxins = 10,
+ /obj/item/cartridge/roboticist = 10,
/obj/item/pda/heads = 10)
premium = list(/obj/item/cartridge/captain = 2,
/obj/item/cartridge/quartermaster = 2)
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index 2691906af4..7005a0b02f 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -14,6 +14,10 @@
/obj/item/clothing/head/beret/blue = 3,
/obj/item/clothing/glasses/monocle = 3,
/obj/item/clothing/suit/jacket = 4,
+ /obj/item/clothing/suit/jacket/flannel = 4,
+ /obj/item/clothing/suit/jacket/flannel/red = 4,
+ /obj/item/clothing/suit/jacket/flannel/aqua = 4,
+ /obj/item/clothing/suit/jacket/flannel/brown = 4,
/obj/item/clothing/suit/jacket/puffer/vest = 4,
/obj/item/clothing/suit/jacket/puffer = 4,
/obj/item/clothing/suit/hooded/cloak/david = 4,
diff --git a/code/modules/vending/coffee.dm b/code/modules/vending/coffee.dm
index ab64756868..fd555526c6 100644
--- a/code/modules/vending/coffee.dm
+++ b/code/modules/vending/coffee.dm
@@ -1,16 +1,20 @@
/obj/machinery/vending/coffee
name = "\improper Solar's Best Hot Drinks"
desc = "A vending machine which dispenses hot drinks."
- product_ads = "Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies"
+ product_ads = "Just what you need!;Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies"
icon_state = "coffee"
icon_vend = "coffee-vend"
products = list(/obj/item/reagent_containers/food/drinks/coffee = 25,
/obj/item/reagent_containers/food/drinks/mug/tea = 25,
+ /obj/item/reagent_containers/food/drinks/mug/tea/red = 10,
+ /obj/item/reagent_containers/food/drinks/mug/tea/green = 10,
/obj/item/reagent_containers/food/drinks/mug/coco = 25)
- contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12)
+ contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12,
+ /obj/item/reagent_containers/food/drinks/mug/tea/mush = 3,)
premium = list(/obj/item/reagent_containers/food/condiment/milk = 2,
/obj/item/reagent_containers/food/drinks/bottle/cream = 2,
- /obj/item/reagent_containers/food/condiment/sugar = 1)
+ /obj/item/reagent_containers/food/condiment/sugar = 1,
+ /obj/item/reagent_containers/food/drinks/mug/tea/forest = 3,)
refill_canister = /obj/item/vending_refill/coffee
default_price = PRICE_REALLY_CHEAP
diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm
index c416d87439..dc4f4e9273 100644
--- a/code/modules/vending/kinkmate.dm
+++ b/code/modules/vending/kinkmate.dm
@@ -6,8 +6,10 @@
product_slogans = "Kinky!;Sexy!;Check me out, big boy!"
vend_reply = "Have fun, you shameless pervert!"
products = list(
+ /obj/item/clothing/head/maid = 5,
/obj/item/clothing/under/costume/maid = 5,
/obj/item/clothing/under/rank/civilian/janitor/maid = 5,
+ /obj/item/clothing/gloves/evening = 5,
/obj/item/clothing/neck/petcollar = 5,
/obj/item/clothing/neck/petcollar/choker = 5,
/obj/item/clothing/neck/petcollar/leather = 5,
@@ -34,13 +36,10 @@
/obj/item/clothing/under/misc/keyholesweater = 2,
/obj/item/clothing/under/misc/stripper/mankini = 2,
/obj/item/clothing/under/costume/jabroni = 2,
- /obj/item/dildo/flared/huge = 3,
- /obj/item/reagent_containers/glass/bottle/crocin = 5,
- /obj/item/reagent_containers/glass/bottle/camphor = 5
+ /obj/item/dildo/flared/huge = 3
)
premium = list(
/obj/item/clothing/accessory/skullcodpiece/fake = 3,
- /obj/item/reagent_containers/glass/bottle/hexacrocin = 10,
/obj/item/clothing/under/pants/chaps = 5
)
refill_canister = /obj/item/vending_refill/kink
diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm
index 2cdc7891c7..795d35adc4 100644
--- a/code/modules/vending/medical.dm
+++ b/code/modules/vending/medical.dm
@@ -29,7 +29,12 @@
/obj/item/storage/hypospraykit/brute = 2,
/obj/item/storage/hypospraykit/enlarge = 2,
/obj/item/reagent_containers/glass/bottle/vial/small = 5,
- /obj/item/storage/briefcase/medical = 2)
+ /obj/item/storage/briefcase/medical = 2,
+ /obj/item/stack/sticky_tape/surgical = 3,
+ /obj/item/healthanalyzer/wound = 4,
+ /obj/item/stack/medical/ointment = 2,
+ /obj/item/stack/medical/suture = 2,
+ /obj/item/stack/medical/bone_gel = 4)
contraband = list(/obj/item/reagent_containers/pill/tox = 3,
/obj/item/reagent_containers/pill/morphine = 4,
/obj/item/reagent_containers/pill/charcoal = 6)
diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm
index 09719e1d56..31f3dc49f1 100644
--- a/code/modules/vending/medical_wall.dm
+++ b/code/modules/vending/medical_wall.dm
@@ -11,6 +11,8 @@
/obj/item/reagent_containers/medspray/silver_sulf = 2,
/obj/item/reagent_containers/pill/charcoal = 2,
/obj/item/reagent_containers/medspray/sterilizine = 1,
+ /obj/item/healthanalyzer/wound = 2,
+ /obj/item/stack/medical/bone_gel = 2,
/obj/item/reagent_containers/syringe/dart = 10)
contraband = list(/obj/item/reagent_containers/pill/tox = 2,
/obj/item/reagent_containers/pill/morphine = 2)
diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm
index 7aef2b627c..ff8fd46676 100644
--- a/code/modules/vending/snack.dm
+++ b/code/modules/vending/snack.dm
@@ -12,7 +12,8 @@
/obj/item/reagent_containers/food/snacks/no_raisin = 5,
/obj/item/reagent_containers/food/snacks/spacetwinkie = 5,
/obj/item/reagent_containers/food/snacks/cheesiehonkers = 5,
- /obj/item/reagent_containers/food/snacks/cornchips = 5)
+ /obj/item/reagent_containers/food/snacks/cornchips = 5,
+ /obj/item/reagent_containers/food/snacks/energybar = 6)
contraband = list(
/obj/item/reagent_containers/food/snacks/cracker = 10,
/obj/item/reagent_containers/food/snacks/honeybar = 5,
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index 8552d52b04..26beccaac0 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -248,6 +248,7 @@
vend_reply = "Thank you for using the BarDrobe!"
products = list(/obj/item/clothing/head/that = 3,
/obj/item/radio/headset/headset_srv = 3,
+ /obj/item/clothing/suit/hooded/wintercoat/bar = 3,
/obj/item/clothing/under/suit/sl = 3,
/obj/item/clothing/under/rank/civilian/bartender = 3,
/obj/item/clothing/under/rank/civilian/bartender/skirt = 2,
diff --git a/code/modules/vore/eating/belly_obj.dm b/code/modules/vore/eating/belly_obj.dm
index 50cdc32bf6..a367abb098 100644
--- a/code/modules/vore/eating/belly_obj.dm
+++ b/code/modules/vore/eating/belly_obj.dm
@@ -542,8 +542,6 @@
if (!(R in contents))
return // User is not in this belly
- R.changeNext_move(CLICK_CD_BREAKOUT*0.5)
-
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
to_chat(R,"You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)")
to_chat(owner,"Someone is attempting to climb out of your [lowertext(name)]!")
diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm
index 1c9bf029ea..9395cef952 100644
--- a/code/modules/vore/eating/living.dm
+++ b/code/modules/vore/eating/living.dm
@@ -349,7 +349,7 @@
if(incapacitated(ignore_restraints = TRUE))
to_chat(src, "You can't do that while incapacitated.")
return
- if(next_move > world.time)
+ if(!CheckActionCooldown())
to_chat(src, "You can't do that so fast, slow down.")
return
@@ -366,11 +366,10 @@
if(QDELETED(tasted) || (tasted.ckey && !(tasted.client?.prefs.vore_flags & LICKABLE)) || !Adjacent(tasted) || incapacitated(ignore_restraints = TRUE))
return
- changeNext_move(CLICK_CD_MELEE)
+ DelayNextAction(CLICK_CD_MELEE)
visible_message("[src] licks [tasted]!","You lick [tasted]. They taste rather like [tasted.get_taste_message()].","Slurp!")
-
/mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace)
if(!vore_taste && !allow_generic)
return FALSE
diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm
index d4d92f54c4..2cb3a83257 100644
--- a/code/modules/zombie/items.dm
+++ b/code/modules/zombie/items.dm
@@ -11,9 +11,13 @@
var/icon_left = "bloodhand_left"
var/icon_right = "bloodhand_right"
hitsound = 'sound/hallucinations/growl1.ogg'
- force = 21 // Just enough to break airlocks with melee attacks
+ force = 18
+ sharpness = SHARP_POINTY //it's a claw, they're sharp.
damtype = "brute"
total_mass = TOTAL_MASS_HAND_REPLACEMENT
+ sharpness = SHARP_EDGED
+ wound_bonus = -30
+ bare_wound_bonus = 15
/obj/item/zombie_hand/Initialize()
. = ..()
@@ -32,11 +36,15 @@
. = ..()
if(!proximity_flag)
return
- else if(isliving(target))
- if(ishuman(target))
- try_to_zombie_infect(target)
- else
- check_feast(target, user)
+ else
+ if(istype(target, /obj)) //do far more damage to non mobs so we can get through airlocks
+ var/obj/target_object = target
+ target_object.take_damage(force * 3, BRUTE, "melee", 0)
+ else if(isliving(target))
+ if(ishuman(target))
+ try_to_zombie_infect(target)
+ else
+ check_feast(target, user)
/proc/try_to_zombie_infect(mob/living/carbon/human/target)
CHECK_DNA_AND_SPECIES(target)
@@ -52,8 +60,6 @@
infection = new()
infection.Insert(target)
-
-
/obj/item/zombie_hand/suicide_act(mob/user)
user.visible_message("[user] is ripping [user.p_their()] brains out! It looks like [user.p_theyre()] trying to commit suicide!")
if(isliving(user))
@@ -75,3 +81,14 @@
user.updatehealth()
user.adjustOrganLoss(ORGAN_SLOT_BRAIN, -hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!"
user.adjust_nutrition(hp_gained, NUTRITION_LEVEL_FULL)
+
+/obj/item/paper/guides/antag/romerol_instructions
+ info = "How to do necromancy with chemicals: \
+
\
+
Use a dropper or syringe (provided) to inject the Romerol (provided) into a target (not provided)
\
+
Wait for said target to die, or speed the process up by doing it yourself
\
+
Run away from the target, as they will be hostile when rising back up
\
+
Optionally: Inject chemical into foods and drinks to further spread possible infection
\
+
???
\
+
Complete assigned objectives amidst the chaos
\
+
"
\ No newline at end of file
diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm
index 3d045ba31e..2681f781a9 100644
--- a/code/modules/zombie/organs.dm
+++ b/code/modules/zombie/organs.dm
@@ -93,7 +93,8 @@
playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1)
owner.do_jitter_animation(living_transformation_time)
owner.Stun(living_transformation_time)
- to_chat(owner, "You are now a zombie!")
+ to_chat(owner, "You are now a zombie! You claw and bite, turning your fellow crewmembers into friends that help spread the plague.")
+ to_chat(owner, "You are a zombie. Please act like one. Letting the crew remove the tumor inside your brain is a dick move to whoever infected you. Please do not do it.")
/obj/item/organ/zombie_infection/nodamage
causes_damage = FALSE
diff --git a/config/config.txt b/config/config.txt
index d6d0097c21..46f9a0cdc4 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -525,3 +525,7 @@ FAIL2TOPIC_RULE_NAME _dd_fail2topic
## Enable automatic profiling - Byond 513.1506 and newer only.
#AUTO_PROFILE
+
+## Uncomment to enable global ban DB using the provided URL. The API should expect to receive a ckey at the end of the URL.
+## More API details can be found here: https://centcom.melonmesa.com
+CENTCOM_BAN_DB https://centcom.melonmesa.com/ban/search
diff --git a/config/game_options.txt b/config/game_options.txt
index 405ec0405a..1585d45e6d 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -445,6 +445,7 @@ ROUNDSTART_RACES plasmaman
#ROUNDSTART_RACES shadow
ROUNDSTART_RACES felinid
ROUNDSTART_RACES dwarf
+ROUNDSTART_RACES ethereal
## Races that are better than humans in some ways, but worse in others
#ROUNDSTART_RACES jelly
diff --git a/html/changelog.html b/html/changelog.html
index 59426bb8d3..58a5dcd1b7 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,477 @@
-->
+
09 August 2020
+
Hatterhat updated:
+
+
Proto-kinetic glaives (not crushers) can parry now.
+
+
MrJWhit updated:
+
+
Adds a second shutter on the top of the hop line
+
+
silicons updated:
+
+
immovable rods no longer drop down chasms
+
fun removal: squeaking objects now have an 1 second cooldown between squeaks, and will have a 33% chance of interrupting any other squeaking object when Cross()ing, meaning no more ear-fuck conveyor belts.
+
+
+
08 August 2020
+
DeltaFire15 updated:
+
+
Roundstart cultists now start with a replica fabricator - no brass though, make your own.
+
Kindle cast time: 10 > 15, mute after stun end: 2 > 5, slur after mute end: 3 > 5
+
The ratvarian spear no longer adds negative vitality under very specific circumstances.
+
The Ratvarian Spear can parry now! Short parries with low leeway, but low cooldown.
+
The brass claw, a implant-based weapon which gains combo on consecutive hits against the same target.
+
The sigil of rites, a sigil used to perform various rites with a cost of power and materials
+
The Rite of Advancement: Used to add a organ or cyberimplant to a clockie without need for surgery.
+
The Rite of Woundmending: Used to heal all wounds on another cultist, causing toxins damage in return.
+
The Rite of the Claw: Used to summon a brass claw implant. Maximum of 4 uses per round.
+
+
Hatterhat updated:
+
+
You can now buy a toolbox's worth of Mosin-Nagant ammo for a fairly discounted price.
+
Revolvers from the dedicated kit now have reskinning capabilities.
+
You can now actually buy the riflery primer, which lets you pump shotguns and work the Mosin's bolt faster.
+
Bulldog slug magazines now have a unique sprite.
+
+
Ludox235 updated:
+
+
Removed an abductee objective that told you to remove all oxygen.
+
Added a new abductee objective to replace the removed one.
+
+
Sishen1542 updated:
+
+
🅱️oneless
+
squishy slime emotes
+
+
timothyteakettle updated:
+
+
heparin makes you bleed half as much now
+
cuts make you bleed 25% less now
+
more items in the loadout and loadout has subcategories now for easier searching
+
+
+
07 August 2020
+
dapnee updated:
+
+
fixed active tufs on some space ruins, murderdome VR, and a few on pubby, changed cargo autolathe to techfab, messed with pipe room leading to monastery.
+
+
lolman360 updated:
+
+
vendors are now unanchored when tipped. it just fell over it's not bolted to the ground anymore.
+
podpeople no fat when sunbathing.
+
+
silicons updated:
+
+
explosions only recurse one level into storage before dropping 1 level per storage layer.
+
volumetric storage is now minimum 16 pixels per item because 8 was ridiculous
+
shieldbash balanace --> balance
+
attempting to send too long of an emote will now reflect it back to you instead of cutting it off and discarding the overflow.
+
holoparasites can now play music
+
lethal blood now causes damaging bleeding instead of outright gibbing
+
+
+
06 August 2020
+
Auris456852 updated:
+
+
Added B.O.O.P. Remote Control cartridges to the PTech.
+
+
Hatterhat updated:
+
+
Proto-kinetic glaives! Essentially a proto-kinetic crusher with a different blade, handguard, and goliath hide grip. Expensive, but elegant.
+
Door charges no longer knock people out.
+
+
Ludox235 updated:
+
+
You can now buy damaged AI upload modules in the traitor's uplink.
+
+
Seris02 updated:
+
+
fixed ghost chilis
+
+
Trilbyspaceclone updated:
+
+
4 New blends of tea have been shipped to the station, and how to make them has been leaked!
+
+
b1tt3r1n0 updated:
+
+
Added the warp implant
+
+
dapnee updated:
+
+
added a hallway to telecoms for engineers to get there on meta
+
+
kappa-sama updated:
+
+
dildo circuit assemblies
+
+
lolman360 updated:
+
+
The Tendril-Mother on Lavaland has remembered how to make ashwalkers who know how to speak Draconic again.
+
+
timothyteakettle updated:
+
+
nanotrasen has decided to fire all disabled members of the security division and confiscate certain sentimental items from doctors
+
the custom tongue preference now passes through cloning so you spawn with your selected tongue
+
several changes to travelling traders so they look better and spawn slightly less often
+
+
zeroisthebiggay updated:
+
+
nukies can buy holoparasites
+
+
+
04 August 2020
+
Seris02 updated:
+
+
lizard spines
+
+
timothyteakettle updated:
+
+
due to further advancements in medical technology, you can now have holes poked into your body for fun and enjoyment
+
+
zeroisthebiggay updated:
+
+
prefs for headpat wagging
+
+
+
03 August 2020
+
KeRSedChaplain updated:
+
+
fixed clockwork guardians being able to reflect ranged weapons
+
+
Linzolle updated:
+
+
uv penlight no longer invisible
+
+
dapnee updated:
+
+
active turfs on box and xenohive, maintenance bar APC not being stringed correctly, turned a monitor to face a direction that makes sense, changed tag of camera in gravgen being misnamed
+
+
silicons updated:
+
+
shoves have been buffed to apply a status effect rather than a 0.85 movespeed modifier, meaning repeatedly shoving someone now renews the debuff
+
shoves now stagger for 3.5 seconds.
+
war operatives now actually time 20 minutes since roundstart to depart instead of 15.
+
explosive stand bombs can now be examined from any distance
+
explosive stand bombs are now a component.
+
+
+
02 August 2020
+
Auris456852 updated:
+
+
Added B.O.O.P. Remote Control cartridges to the PTech.
+
+
Hatterhat updated:
+
+
Durathread reinforcement kits! Sprites by Toriate, sets jumpsuit armor to durathread levels, craft in the crafting menu.
+
+
KeRSedChaplain updated:
+
+
The belligerent scripture and a brass multitool, and a new marauder variant which act similar to holoparasites/guardian spirits.
+
Removed the abductor teleport consoles they get, removes abscond for the time being as I've not seen much use for it other than just spamming it and hoping you end up in the armory.
+
moved around scriptures to make the cult work better as being based around the station, makes the Ark scream more often and work as a summonable object, clockwork armor now has a flat 0 defense up to 10 instead of negatives against laser damage. Makes the Ark work better in a station based setting, as well as the Heralds beacon in case It works for the mode.
+
added powerloaderstep.ogg for Neovgre
+
changes 'Dread_Ipad.dmi' to 'clockwork_slab.dmi'
+
+
MrJWhit updated:
+
+
Adjusts abductor spawntext
+
+
Seris02 updated:
+
+
fixed replica pods
+
+
dapnee updated:
+
+
fixed active turfs on wizard ruin and space hermit, fixed missing APC's and added a light on Delta
+
+
ike709 and bobbahbrown updated:
+
+
Admins can now see your bans on (some) other servers.
+
+
kappa-sama updated:
+
+
chaplain cultists being able to convert people to full clockwork cult status
+
+
timothyteakettle updated:
+
+
combat mode now has weaker buffs in terms of damage dealt and took for being or not being in the mode
+
damage debuff for laying down has been decreased from 0.5x to 0.7x
+
+
+
01 August 2020
+
dapnee updated:
+
+
added cake hat to bar, adds another atmostech spawn
+
sinks point in the right direction, APC won't spawn off the wall in circuits
+
changes commissary APC so it actually powers the room, adds a missing AIR alarm, arrivals no longer has active atmos tiles.
+
+
silicons updated:
+
+
toy shotguns no longer need 2 hands to fire
+
being on fire works again.
+
+
timothyteakettle updated:
+
+
monkeys no longer continuously bleed everywhere
+
+
+
30 July 2020
+
Adelphon updated:
+
+
Created a Cosmetic version of the camo.
+
+
Arturlang updated:
+
+
Bloodsucker LifeTick runs from BiologicalLife now
+
+
Ryll-Ryll ported by silicons updated:
+
+
Shoelaces are now a thing. You can untie them by laying down next to someone.
+
shoes now have lace delays and some can't be laced at all
+
do after now tracks who's interacting with who, meaning some actions now break when the target moves away.
+
+
SiliconMain updated:
+
+
Ported the long range atmos analyzer from sk*rat, credit to NotRanged
+
+
silicons updated:
+
+
energy sword perfect parries now reflect projectiles back at their shooters.
+
any mob can now parry if they have the right item
+
beam rifles now go into emitters properly
+
clickdelay has been refactored into an experimental hybrid system. Check code/modules/mob/clickdelay.dm for more information.
+
Resisting no longer checks clickdelay, but is standardized to a 2 second per resist system for most forms of resisting. It still sets clickdelay, though.
+
Meters have been added for estimating time until next attack/resist. Won't be that useful due to our clickdelay currently being very short, though. They're visible from your hand and resist HUD elements. experimental: Most attacks and forms of attacking (minus unarmed because it's too much of a pain to refactor how hugs/gloves of the north star works) now check for time-since-last-attack rather than making it so you can't attack for said time. This means you can very quickly switch to a gun from a melee weapon, whereas in the old system a melee weapon would put you on lockout for 0.8 seconds, in the new system all the gun cares about is that you did not attack for at least 0.4 seconds.
+
All clickdelay setting/reading are now procs, so it should be trivial to implement another system where drawing/switching to a weapon requires you to have it out for x seconds before using it. I am not personally doing it at this point in time though because it will likely just annoy everyone with no real gain unless we do something like putting a 0.8 second switch-to cooldown for guns (which I did not, yet)
+
attack_hand has been refactored to on_attack_hand remove: sexchems no longer impact click delay
+
turrets now automatically stagger their shots. Happy parrying/blocking.
+
turrets now speed_process, they were shooting slower than they should be
+
anything can now block with the right items
+
+
timothyteakettle updated:
+
+
some crafted crates won't contain items now, and thus have stopped breaking the laws of physics
+
beepskys hats now follow the laws of gravity and move up/down when he bobs up and down
+
+
+
29 July 2020
+
DeltaFire15 updated:
+
+
The 'Naked' outfit is no longer broken.
+
+
Ghommie updated:
+
+
fixed cremator trays, paleness examination strings, chat message for stamping paper, looping sounds, load away missions/VR admin verb, access requirements for using the sechuds.
+
Alt-Clicking a cigarette packet should pull the lighter out first if present, then cigarettes.
+
+
Hatterhat updated:
+
+
Directional windows can now be rotated counterclockwise properly again.
+
+
NecromancerAnne, Sirich96 updated:
+
+
Stunbaton sprites by Sirich96.
+
New sprites for the stunsword.
+
+
necromanceranne updated:
+
+
Adds some in-hands for the rapier sheath.
+
+
timothyteakettle updated:
+
+
tail wagging should work in all cases now
+
bluespace jars work as intended now
+
aliens can remove embeds now
+
bloodsuckers are not affected by bloodloss
+
+
zeroisthebiggay updated:
+
+
Flannel jackets and bartender winter coat
+
+
+
28 July 2020
+
Cacogen updated:
+
+
OSHA has more pull than anyone could have expected. All armor provided by Nanotrasen and the syndicate now have tags that accurately lists defenses and resistances of a piece of clothing.
+
+
CameronWoof updated:
+
+
Exotic seed crates now contain a spaceman's trumpet seed packet.
+
+
EmeraldSundisk updated:
+
+
Renovates Snow Taxi's northeast bathroom to have multiple non-urinal toilets and showers
+
Adds signage/labeling to improve map readability
+
Adds a bathroom to the northwest station
+
Adds a filing cabinet to the cargo department
+
Area designation adjustments to account for the above changes
+
Adds a missing airlock cyclelink near medical
+
+
Ludox235 updated:
+
+
Makes the flavour text that appears when you become a zombie tell you to act like one.
+
+
MrJWhit updated:
+
+
Decluttered toxins and hid the yellow mix line in atmos, for metastation
+
+
SiliconMain updated:
+
+
Paramedic heirloom is now a zippo
+
Durathread belts now protect their contents from radiation, and can hold full sized extinguishers
+
+
Sishen1542 updated:
+
+
removed zoomba
+
+
dapnee updated:
+
+
added a fan to the listening outpost
+
added two missing r-walls near the SM, removed random light and wire node below the engine, and fixed the missing cable in the courtroom on Kilo
+
+
kappa-sama updated:
+
+
Stimpaks cost 5tc once more, up from 3tc.
+
+
silicons updated:
+
+
polychromatic cloaks to loadout
+
no more self healing with medibeam guns
+
oh no, taser buff. alt fire delay dropped to 0.4 seconds.
+
you can now shoot yourself by disarm-intenting yourself with a gun.
+
+
timothyteakettle updated:
+
+
species code is now slightly less messy
+
slight tweak to how material crafting works
+
changed up pet carriers / bluespace jars a bit so you can't fit certain things inside them and also the text shown for resist times is accurate
+
+
zeroisthebiggay updated:
+
+
Black Box theft objective
+
+
+
27 July 2020
+
Hatterhat updated:
+
+
Training bokkens! Make 'em from wood, use 'em in-hand to toggle between harmful and not-so-harmful, practice your parrying with them!
+
Marker beacons should have a sprite again.
+
+
silicons updated:
+
+
clownops and clown mobs now share the same faction. HONK!
+
+
timothyteakettle updated:
+
+
modern pickle technology now allows people who have been turned into pickles, to be retrieved through the medical course of dying
+
+
+
26 July 2020
+
DeltaFire15 updated:
+
+
Organs now decay again.
+
+
Iatots updated:
+
+
Licking wounds now may cause you to spit out a hairball once in a while!
+
You can now craft a catgirl plushie with 3 of a new ingredient occasionally found in medbay!
+
+
dapnee updated:
+
+
removed legacy public mining shuttle area and remade lounge
+
+
+
25 July 2020
+
CameronWoof updated:
+
+
Aloe now has an icon.
+
+
timothyteakettle updated:
+
+
beepsky replaces the word THREAT_LEVEL with the actual threat level
+
+
+
24 July 2020
+
EmeraldSundisk updated:
+
+
Adds a CMO office, along with Virology and Genetics labs to Omega Station
+
Adds a second chemistry station to the chemistry lab
+
Adjusts the locations of some objects in medical to accommodate these new additions
+
Relocates the morgue
+
Relocates items in impacted areas of maintenance as well as the library
sanitization now doesn't cut off 15.7 or something million possible colors from character preferences (instead of only allowing 16 values for R G and B, it now allows 256 each)
+
projectiles are by default 17.5 tiles per second instead of 12.5
+
+
timothyteakettle updated:
+
+
due to recent innovative research in the medical field, you now have bones
+
zombie claws are now sharp and do less damage, but can destroy non-lifeforms far faster
+
zombies now take less stamina damage
+
beepsky can now wear hats
+
+
zeroisthebiggay updated:
+
+
rad and kravglove sprites
+
+
+
23 July 2020
+
DeltaFire15 updated:
+
+
Traits are no longer fucked
+
+
Putnam3145 updated:
+
+
Slight optimization in chat code.
+
+
kappa-sama updated:
+
+
tendril chests being empty
+
+
zeroisthebiggay updated:
+
+
fetish content
+
+
+
22 July 2020
+
Ludox updated:
+
+
You can no longer be brainwashed into giving birth to a fake baby
+
+
kappa-sama updated:
+
+
brainwashing disk has lost its cost buffs (3->5) and is role restricted once more (medical doctor/roboticist)
+
+
21 July 2020
Arturlang updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 9c53b8387d..55bb782766 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -26461,3 +26461,360 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: new fried component used for frying objects
- bugfix: various frying bugs fixed such as being able to unfry items and frying
turfs with cold cooking oil
+2020-07-22:
+ Ludox:
+ - rscdel: You can no longer be brainwashed into giving birth to a fake baby
+ kappa-sama:
+ - balance: brainwashing disk has lost its cost buffs (3->5) and is role restricted
+ once more (medical doctor/roboticist)
+2020-07-23:
+ DeltaFire15:
+ - bugfix: Traits are no longer fucked
+ Putnam3145:
+ - tweak: Slight optimization in chat code.
+ kappa-sama:
+ - bugfix: tendril chests being empty
+ zeroisthebiggay:
+ - rscadd: fetish content
+2020-07-24:
+ EmeraldSundisk:
+ - rscadd: Adds a CMO office, along with Virology and Genetics labs to Omega Station
+ - rscadd: Adds a second chemistry station to the chemistry lab
+ - tweak: Adjusts the locations of some objects in medical to accommodate these new
+ additions
+ - tweak: Relocates the morgue
+ - tweak: Relocates items in impacted areas of maintenance as well as the library
+ - bugfix: Fixes an air line Bartholomew somehow knocked out
+ Linzolle:
+ - bugfix: wounds now have a description on examine
+ Owai-Seek:
+ - rscadd: Meatball Sub, Meatloaf + Meatloaf Slices, Bear Chili, Mashed Potatoes
+ - rscadd: Buttered Potatoes, Fancy Cracker Pack, Spiral Soup, Sweet and Sour Chicken
+ - tweak: Organised the Food DMI a bit.
+ - tweak: Deleted some stray pixels on some sprites.
+ - tweak: Nuggie boxes are now centered correctly.
+ - imageadd: Icons for the the food items in this PR.
+ Sneakyrat6:
+ - bugfix: Fixes dressers not giving you undies
+ - bugfix: Fixes Snaxi not loading properly because of typos
+ - rscadd: You can now burn photos
+ Zandario:
+ - spellcheck: Murdered **tipes** and gave birth to **is**.
+ silicons:
+ - tweak: sanitization now doesn't cut off 15.7 or something million possible colors
+ from character preferences (instead of only allowing 16 values for R G and B,
+ it now allows 256 each)
+ - balance: projectiles are by default 17.5 tiles per second instead of 12.5
+ timothyteakettle:
+ - rscadd: due to recent innovative research in the medical field, you now have bones
+ - tweak: zombie claws are now sharp and do less damage, but can destroy non-lifeforms
+ far faster
+ - tweak: zombies now take less stamina damage
+ - rscadd: beepsky can now wear hats
+ zeroisthebiggay:
+ - imageadd: rad and kravglove sprites
+2020-07-25:
+ CameronWoof:
+ - bugfix: Aloe now has an icon.
+ timothyteakettle:
+ - bugfix: beepsky replaces the word THREAT_LEVEL with the actual threat level
+2020-07-26:
+ DeltaFire15:
+ - bugfix: Organs now decay again.
+ Iatots:
+ - tweak: Licking wounds now may cause you to spit out a hairball once in a while!
+ - rscadd: You can now craft a catgirl plushie with 3 of a new ingredient occasionally
+ found in medbay!
+ dapnee:
+ - tweak: removed legacy public mining shuttle area and remade lounge
+2020-07-27:
+ Hatterhat:
+ - rscadd: Training bokkens! Make 'em from wood, use 'em in-hand to toggle between
+ harmful and not-so-harmful, practice your parrying with them!
+ - bugfix: Marker beacons should have a sprite again.
+ silicons:
+ - rscadd: clownops and clown mobs now share the same faction. HONK!
+ timothyteakettle:
+ - bugfix: modern pickle technology now allows people who have been turned into pickles,
+ to be retrieved through the medical course of dying
+2020-07-28:
+ Cacogen:
+ - rscadd: OSHA has more pull than anyone could have expected. All armor provided
+ by Nanotrasen and the syndicate now have tags that accurately lists defenses
+ and resistances of a piece of clothing.
+ CameronWoof:
+ - tweak: Exotic seed crates now contain a spaceman's trumpet seed packet.
+ EmeraldSundisk:
+ - rscadd: Renovates Snow Taxi's northeast bathroom to have multiple non-urinal toilets
+ and showers
+ - rscadd: Adds signage/labeling to improve map readability
+ - rscadd: Adds a bathroom to the northwest station
+ - rscadd: Adds a filing cabinet to the cargo department
+ - tweak: Area designation adjustments to account for the above changes
+ - bugfix: Adds a missing airlock cyclelink near medical
+ Ludox235:
+ - tweak: Makes the flavour text that appears when you become a zombie tell you to
+ act like one.
+ MrJWhit:
+ - tweak: Decluttered toxins and hid the yellow mix line in atmos, for metastation
+ SiliconMain:
+ - tweak: Paramedic heirloom is now a zippo
+ - tweak: Durathread belts now protect their contents from radiation, and can hold
+ full sized extinguishers
+ Sishen1542:
+ - rscdel: removed zoomba
+ dapnee:
+ - tweak: added a fan to the listening outpost
+ - bugfix: added two missing r-walls near the SM, removed random light and wire node
+ below the engine, and fixed the missing cable in the courtroom on Kilo
+ kappa-sama:
+ - balance: Stimpaks cost 5tc once more, up from 3tc.
+ silicons:
+ - rscadd: polychromatic cloaks to loadout
+ - rscdel: no more self healing with medibeam guns
+ - balance: oh no, taser buff. alt fire delay dropped to 0.4 seconds.
+ - rscadd: you can now shoot yourself by disarm-intenting yourself with a gun.
+ timothyteakettle:
+ - tweak: species code is now slightly less messy
+ - bugfix: slight tweak to how material crafting works
+ - bugfix: changed up pet carriers / bluespace jars a bit so you can't fit certain
+ things inside them and also the text shown for resist times is accurate
+ zeroisthebiggay:
+ - rscadd: Black Box theft objective
+2020-07-29:
+ DeltaFire15:
+ - bugfix: The 'Naked' outfit is no longer broken.
+ Ghommie:
+ - bugfix: fixed cremator trays, paleness examination strings, chat message for stamping
+ paper, looping sounds, load away missions/VR admin verb, access requirements
+ for using the sechuds.
+ - tweak: Alt-Clicking a cigarette packet should pull the lighter out first if present,
+ then cigarettes.
+ Hatterhat:
+ - bugfix: Directional windows can now be rotated counterclockwise properly again.
+ NecromancerAnne, Sirich96:
+ - rscadd: Stunbaton sprites by Sirich96.
+ - rscadd: New sprites for the stunsword.
+ necromanceranne:
+ - rscadd: Adds some in-hands for the rapier sheath.
+ timothyteakettle:
+ - bugfix: tail wagging should work in all cases now
+ - bugfix: bluespace jars work as intended now
+ - bugfix: aliens can remove embeds now
+ - bugfix: bloodsuckers are not affected by bloodloss
+ zeroisthebiggay:
+ - rscadd: Flannel jackets and bartender winter coat
+2020-07-30:
+ Adelphon:
+ - rscadd: Created a Cosmetic version of the camo.
+ Arturlang:
+ - code_imp: Bloodsucker LifeTick runs from BiologicalLife now
+ Ryll-Ryll ported by silicons:
+ - rscadd: Shoelaces are now a thing. You can untie them by laying down next to someone.
+ - tweak: shoes now have lace delays and some can't be laced at all
+ - refactor: do after now tracks who's interacting with who, meaning some actions
+ now break when the target moves away.
+ SiliconMain:
+ - rscadd: Ported the long range atmos analyzer from sk*rat, credit to NotRanged
+ silicons:
+ - rscadd: energy sword perfect parries now reflect projectiles back at their shooters.
+ - balance: any mob can now parry if they have the right item
+ - rscadd: beam rifles now go into emitters properly
+ - refactor: clickdelay has been refactored into an experimental hybrid system. Check
+ code/modules/mob/clickdelay.dm for more information.
+ - balance: Resisting no longer checks clickdelay, but is standardized to a 2 second
+ per resist system for most forms of resisting. It still sets clickdelay, though.
+ - rscadd: 'Meters have been added for estimating time until next attack/resist.
+ Won''t be that useful due to our clickdelay currently being very short, though.
+ They''re visible from your hand and resist HUD elements. experimental: Most
+ attacks and forms of attacking (minus unarmed because it''s too much of a pain
+ to refactor how hugs/gloves of the north star works) now check for time-since-last-attack
+ rather than making it so you can''t attack for said time. This means you can
+ very quickly switch to a gun from a melee weapon, whereas in the old system
+ a melee weapon would put you on lockout for 0.8 seconds, in the new system all
+ the gun cares about is that you did not attack for at least 0.4 seconds.'
+ - code_imp: All clickdelay setting/reading are now procs, so it should be trivial
+ to implement another system where drawing/switching to a weapon requires you
+ to have it out for x seconds before using it. I am not personally doing it at
+ this point in time though because it will likely just annoy everyone with no
+ real gain unless we do something like putting a 0.8 second switch-to cooldown
+ for guns (which I did not, yet)
+ - refactor: 'attack_hand has been refactored to on_attack_hand remove: sexchems
+ no longer impact click delay'
+ - rscadd: turrets now automatically stagger their shots. Happy parrying/blocking.
+ - bugfix: turrets now speed_process, they were shooting slower than they should
+ be
+ - balance: anything can now block with the right items
+ timothyteakettle:
+ - bugfix: some crafted crates won't contain items now, and thus have stopped breaking
+ the laws of physics
+ - tweak: beepskys hats now follow the laws of gravity and move up/down when he bobs
+ up and down
+2020-08-01:
+ dapnee:
+ - tweak: added cake hat to bar, adds another atmostech spawn
+ - bugfix: sinks point in the right direction, APC won't spawn off the wall in circuits
+ - bugfix: changes commissary APC so it actually powers the room, adds a missing
+ AIR alarm, arrivals no longer has active atmos tiles.
+ silicons:
+ - tweak: toy shotguns no longer need 2 hands to fire
+ - bugfix: being on fire works again.
+ timothyteakettle:
+ - bugfix: monkeys no longer continuously bleed everywhere
+2020-08-02:
+ Auris456852:
+ - rscadd: Added B.O.O.P. Remote Control cartridges to the PTech.
+ Hatterhat:
+ - rscadd: Durathread reinforcement kits! Sprites by Toriate, sets jumpsuit armor
+ to durathread levels, craft in the crafting menu.
+ KeRSedChaplain:
+ - rscadd: The belligerent scripture and a brass multitool, and a new marauder variant
+ which act similar to holoparasites/guardian spirits.
+ - rscdel: Removed the abductor teleport consoles they get, removes abscond for the
+ time being as I've not seen much use for it other than just spamming it and
+ hoping you end up in the armory.
+ - tweak: moved around scriptures to make the cult work better as being based around
+ the station, makes the Ark scream more often and work as a summonable object,
+ clockwork armor now has a flat 0 defense up to 10 instead of negatives against
+ laser damage. Makes the Ark work better in a station based setting, as well
+ as the Heralds beacon in case It works for the mode.
+ - soundadd: added powerloaderstep.ogg for Neovgre
+ - tweak: changes 'Dread_Ipad.dmi' to 'clockwork_slab.dmi'
+ MrJWhit:
+ - tweak: Adjusts abductor spawntext
+ Seris02:
+ - bugfix: fixed replica pods
+ dapnee:
+ - bugfix: fixed active turfs on wizard ruin and space hermit, fixed missing APC's
+ and added a light on Delta
+ ike709 and bobbahbrown:
+ - rscadd: Admins can now see your bans on (some) other servers.
+ kappa-sama:
+ - bugfix: chaplain cultists being able to convert people to full clockwork cult
+ status
+ timothyteakettle:
+ - tweak: combat mode now has weaker buffs in terms of damage dealt and took for
+ being or not being in the mode
+ - tweak: damage debuff for laying down has been decreased from 0.5x to 0.7x
+2020-08-03:
+ KeRSedChaplain:
+ - bugfix: fixed clockwork guardians being able to reflect ranged weapons
+ Linzolle:
+ - bugfix: uv penlight no longer invisible
+ dapnee:
+ - bugfix: active turfs on box and xenohive, maintenance bar APC not being stringed
+ correctly, turned a monitor to face a direction that makes sense, changed tag
+ of camera in gravgen being misnamed
+ silicons:
+ - rscadd: shoves have been buffed to apply a status effect rather than a 0.85 movespeed
+ modifier, meaning repeatedly shoving someone now renews the debuff
+ - balance: shoves now stagger for 3.5 seconds.
+ - tweak: war operatives now actually time 20 minutes since roundstart to depart
+ instead of 15.
+ - balance: explosive stand bombs can now be examined from any distance
+ - code_imp: explosive stand bombs are now a component.
+2020-08-04:
+ Seris02:
+ - bugfix: lizard spines
+ timothyteakettle:
+ - rscadd: due to further advancements in medical technology, you can now have holes
+ poked into your body for fun and enjoyment
+ zeroisthebiggay:
+ - rscadd: prefs for headpat wagging
+2020-08-06:
+ Auris456852:
+ - rscadd: Added B.O.O.P. Remote Control cartridges to the PTech.
+ Hatterhat:
+ - rscadd: Proto-kinetic glaives! Essentially a proto-kinetic crusher with a different
+ blade, handguard, and goliath hide grip. Expensive, but elegant.
+ - balance: Door charges no longer knock people out.
+ Ludox235:
+ - rscadd: You can now buy damaged AI upload modules in the traitor's uplink.
+ Seris02:
+ - bugfix: fixed ghost chilis
+ Trilbyspaceclone:
+ - rscadd: 4 New blends of tea have been shipped to the station, and how to make
+ them has been leaked!
+ b1tt3r1n0:
+ - rscadd: Added the warp implant
+ dapnee:
+ - tweak: added a hallway to telecoms for engineers to get there on meta
+ kappa-sama:
+ - rscdel: dildo circuit assemblies
+ lolman360:
+ - bugfix: The Tendril-Mother on Lavaland has remembered how to make ashwalkers who
+ know how to speak Draconic again.
+ timothyteakettle:
+ - tweak: nanotrasen has decided to fire all disabled members of the security division
+ and confiscate certain sentimental items from doctors
+ - tweak: the custom tongue preference now passes through cloning so you spawn with
+ your selected tongue
+ - tweak: several changes to travelling traders so they look better and spawn slightly
+ less often
+ zeroisthebiggay:
+ - rscadd: nukies can buy holoparasites
+2020-08-07:
+ dapnee:
+ - bugfix: fixed active tufs on some space ruins, murderdome VR, and a few on pubby,
+ changed cargo autolathe to techfab, messed with pipe room leading to monastery.
+ lolman360:
+ - bugfix: vendors are now unanchored when tipped. it just fell over it's not bolted
+ to the ground anymore.
+ - bugfix: podpeople no fat when sunbathing.
+ silicons:
+ - balance: explosions only recurse one level into storage before dropping 1 level
+ per storage layer.
+ - tweak: volumetric storage is now minimum 16 pixels per item because 8 was ridiculous
+ - spellcheck: shieldbash balanace --> balance
+ - rscadd: attempting to send too long of an emote will now reflect it back to you
+ instead of cutting it off and discarding the overflow.
+ - rscadd: holoparasites can now play music
+ - balance: lethal blood now causes damaging bleeding instead of outright gibbing
+2020-08-08:
+ DeltaFire15:
+ - balance: Roundstart cultists now start with a replica fabricator - no brass though,
+ make your own.
+ - balance: 'Kindle cast time: 10 > 15, mute after stun end: 2 > 5, slur after mute
+ end: 3 > 5'
+ - bugfix: The ratvarian spear no longer adds negative vitality under very specific
+ circumstances.
+ - balance: The Ratvarian Spear can parry now! Short parries with low leeway, but
+ low cooldown.
+ - rscadd: The brass claw, a implant-based weapon which gains combo on consecutive
+ hits against the same target.
+ - rscadd: The sigil of rites, a sigil used to perform various rites with a cost
+ of power and materials
+ - rscadd: 'The Rite of Advancement: Used to add a organ or cyberimplant to a clockie
+ without need for surgery.'
+ - rscadd: 'The Rite of Woundmending: Used to heal all wounds on another cultist,
+ causing toxins damage in return.'
+ - rscadd: 'The Rite of the Claw: Used to summon a brass claw implant. Maximum of
+ 4 uses per round.'
+ Hatterhat:
+ - rscadd: You can now buy a toolbox's worth of Mosin-Nagant ammo for a fairly discounted
+ price.
+ - rscadd: Revolvers from the dedicated kit now have reskinning capabilities.
+ - bugfix: You can now actually buy the riflery primer, which lets you pump shotguns
+ and work the Mosin's bolt faster.
+ - imageadd: Bulldog slug magazines now have a unique sprite.
+ Ludox235:
+ - rscdel: Removed an abductee objective that told you to remove all oxygen.
+ - rscadd: Added a new abductee objective to replace the removed one.
+ Sishen1542:
+ - tweak: "\U0001F171\uFE0Foneless"
+ - rscadd: squishy slime emotes
+ timothyteakettle:
+ - tweak: heparin makes you bleed half as much now
+ - tweak: cuts make you bleed 25% less now
+ - rscadd: more items in the loadout and loadout has subcategories now for easier
+ searching
+2020-08-09:
+ Hatterhat:
+ - rscadd: Proto-kinetic glaives (not crushers) can parry now.
+ MrJWhit:
+ - rscadd: Adds a second shutter on the top of the hop line
+ silicons:
+ - bugfix: immovable rods no longer drop down chasms
+ - rscdel: 'fun removal: squeaking objects now have an 1 second cooldown between
+ squeaks, and will have a 33% chance of interrupting any other squeaking object
+ when Cross()ing, meaning no more ear-fuck conveyor belts.'
diff --git a/html/changelogs/AutoChangeLog-pr-12824.yml b/html/changelogs/AutoChangeLog-pr-12824.yml
deleted file mode 100644
index 5723117238..0000000000
--- a/html/changelogs/AutoChangeLog-pr-12824.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "kappa-sama"
-delete-after: True
-changes:
- - balance: "brainwashing disk has lost its cost buffs (3->5) and is role restricted once more (medical doctor/roboticist)"
diff --git a/html/changelogs/AutoChangeLog-pr-12852.yml b/html/changelogs/AutoChangeLog-pr-12852.yml
deleted file mode 100644
index 889a42f0bb..0000000000
--- a/html/changelogs/AutoChangeLog-pr-12852.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ludox"
-delete-after: True
-changes:
- - rscdel: "You can no longer be brainwashed into giving birth to a fake baby"
diff --git a/html/changelogs/AutoChangeLog-pr-12853.yml b/html/changelogs/AutoChangeLog-pr-12853.yml
new file mode 100644
index 0000000000..deea36f640
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12853.yml
@@ -0,0 +1,5 @@
+author: "LetterN"
+delete-after: True
+changes:
+ - tweak: "clocktheme color"
+ - code_imp: "Ports TGUI-4"
diff --git a/html/changelogs/AutoChangeLog-pr-13040.yml b/html/changelogs/AutoChangeLog-pr-13040.yml
new file mode 100644
index 0000000000..4fb40fbc5a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13040.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - balance: "gave chairs active block/parry in exchange for removal of block_chance"
diff --git a/html/changelogs/AutoChangeLog-pr-13047.yml b/html/changelogs/AutoChangeLog-pr-13047.yml
new file mode 100644
index 0000000000..94d54c3597
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13047.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - tweak: "replaces box whiteship tbaton with truncheon"
diff --git a/html/changelogs/AutoChangeLog-pr-13051.yml b/html/changelogs/AutoChangeLog-pr-13051.yml
new file mode 100644
index 0000000000..a3063edbbd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13051.yml
@@ -0,0 +1,4 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - rscadd: "MODS I SPILLED MU JUICE HEJPPHRLP HELPJ JLEP HELP"
diff --git a/html/changelogs/AutoChangeLog-pr-13053.yml b/html/changelogs/AutoChangeLog-pr-13053.yml
new file mode 100644
index 0000000000..163e08dd36
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13053.yml
@@ -0,0 +1,4 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - balance: "made the Dirty Magazines crate cost 4000 instead of 12000 credits"
diff --git a/html/changelogs/AutoChangeLog-pr-13054.yml b/html/changelogs/AutoChangeLog-pr-13054.yml
new file mode 100644
index 0000000000..969b4b34c7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13054.yml
@@ -0,0 +1,5 @@
+author: "KeRSedChaplain"
+delete-after: True
+changes:
+ - rscadd: "Added a guide for romerol usage"
+ - balance: "made infectious zombies not enter softcrit and take no stamina damage"
diff --git a/html/changelogs/AutoChangeLog-pr-13060.yml b/html/changelogs/AutoChangeLog-pr-13060.yml
new file mode 100644
index 0000000000..69ac724104
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13060.yml
@@ -0,0 +1,5 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - rscadd: "New item: Temporal Katana. 2 points for wizards, timestops upon successful parry, bokken quickparry stats (100 force on melee counter!)."
+ - rscadd: "Also you can *smirk. This has no mechanical effect, other than being smug."
diff --git a/html/changelogs/AutoChangeLog-pr-13066.yml b/html/changelogs/AutoChangeLog-pr-13066.yml
new file mode 100644
index 0000000000..43e7831700
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13066.yml
@@ -0,0 +1,4 @@
+author: "timothyteakettle"
+delete-after: True
+changes:
+ - tweak: "speech verbs copy through dna copying now"
diff --git a/html/changelogs/AutoChangeLog-pr-13068.yml b/html/changelogs/AutoChangeLog-pr-13068.yml
new file mode 100644
index 0000000000..5ae41fe394
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13068.yml
@@ -0,0 +1,6 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - balance: "Sterilized gauze is now better at stopping bleeding, and applies slightly faster. Very slightly faster."
+ - balance: "Ointment and sutures now hold more in a stack (12 and 15, respectively)."
+ - tweak: "Sterilized gauze can now be made by just pouring 10u sterilizine onto standard medical gauze, instead of having to craft it. Why you had to craft it, I will honestly never know."
diff --git a/html/changelogs/AutoChangeLog-pr-13069.yml b/html/changelogs/AutoChangeLog-pr-13069.yml
new file mode 100644
index 0000000000..77ca95e410
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13069.yml
@@ -0,0 +1,4 @@
+author: "Lynxless"
+delete-after: True
+changes:
+ - rscadd: "Ports TG #51879"
diff --git a/html/changelogs/AutoChangeLog-pr-13078.yml b/html/changelogs/AutoChangeLog-pr-13078.yml
new file mode 100644
index 0000000000..f9bcb9f35b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13078.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - tweak: "Rerolling your traitor goals will ONLY give you \"proper\" objectives."
diff --git a/html/changelogs/AutoChangeLog-pr-13079.yml b/html/changelogs/AutoChangeLog-pr-13079.yml
new file mode 100644
index 0000000000..d6951b3f75
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13079.yml
@@ -0,0 +1,4 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - bugfix: "Parry counterattack text now shows up."
diff --git a/html/changelogs/AutoChangeLog-pr-13081.yml b/html/changelogs/AutoChangeLog-pr-13081.yml
new file mode 100644
index 0000000000..7fdc1662f3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13081.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - rscadd: "Ethereals"
diff --git a/html/changelogs/AutoChangeLog-pr-13082.yml b/html/changelogs/AutoChangeLog-pr-13082.yml
new file mode 100644
index 0000000000..6d29840a38
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13082.yml
@@ -0,0 +1,5 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - rscdel: "(Hexa)crocin"
+ - rscdel: "(Hexa)camphor"
diff --git a/html/changelogs/AutoChangeLog-pr-13084.yml b/html/changelogs/AutoChangeLog-pr-13084.yml
new file mode 100644
index 0000000000..0ca0b2d111
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13084.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - tweak: "Tweaked wording for marking tickets IC issue."
diff --git a/html/changelogs/AutoChangeLog-pr-13085.yml b/html/changelogs/AutoChangeLog-pr-13085.yml
new file mode 100644
index 0000000000..4f88c783de
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13085.yml
@@ -0,0 +1,4 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - balance: "Proto-kinetic glaives are more expensive, stagger/cooldown on failed parries increased slightly, perfect parries required for counterattack."
diff --git a/icons/effects/supplypod_down_target.dmi b/icons/effects/mouse_pointers/supplypod_down_target.dmi
similarity index 100%
rename from icons/effects/supplypod_down_target.dmi
rename to icons/effects/mouse_pointers/supplypod_down_target.dmi
diff --git a/icons/effects/mouse_pointers/supplypod_pickturf.dmi b/icons/effects/mouse_pointers/supplypod_pickturf.dmi
new file mode 100644
index 0000000000..3ca1131e1a
Binary files /dev/null and b/icons/effects/mouse_pointers/supplypod_pickturf.dmi differ
diff --git a/icons/effects/mouse_pointers/supplypod_pickturf_down.dmi b/icons/effects/mouse_pointers/supplypod_pickturf_down.dmi
new file mode 100644
index 0000000000..113fe47540
Binary files /dev/null and b/icons/effects/mouse_pointers/supplypod_pickturf_down.dmi differ
diff --git a/icons/effects/supplypod_target.dmi b/icons/effects/mouse_pointers/supplypod_target.dmi
similarity index 100%
rename from icons/effects/supplypod_target.dmi
rename to icons/effects/mouse_pointers/supplypod_target.dmi
diff --git a/icons/misc/language.dmi b/icons/misc/language.dmi
index 155dbab98d..9501dc9216 100644
Binary files a/icons/misc/language.dmi and b/icons/misc/language.dmi differ
diff --git a/icons/mob/clockwork_mobs.dmi b/icons/mob/clockwork_mobs.dmi
index 5985adf12d..54690f6cac 100644
Binary files a/icons/mob/clockwork_mobs.dmi and b/icons/mob/clockwork_mobs.dmi differ
diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi
index 00cffd9006..9490595484 100644
Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ
diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi
index fd3016ac89..52ef75020c 100644
Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ
diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi
index 856fe2149a..755280b332 100644
Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ
diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi
index 167332b630..0ad9452994 100644
Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ
diff --git a/icons/mob/clothing/head_muzzled.dmi b/icons/mob/clothing/head_muzzled.dmi
index 16cc63a13e..62c1ebea0a 100644
Binary files a/icons/mob/clothing/head_muzzled.dmi and b/icons/mob/clothing/head_muzzled.dmi differ
diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi
index c361563da3..ecc6e2dd2c 100644
Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ
diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi
index 1c06c203e1..c94e8a46d3 100644
Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ
diff --git a/icons/mob/clothing/suit_digi.dmi b/icons/mob/clothing/suit_digi.dmi
index ca2a088551..dd00713770 100644
Binary files a/icons/mob/clothing/suit_digi.dmi and b/icons/mob/clothing/suit_digi.dmi differ
diff --git a/icons/mob/clothing/taur_canine.dmi b/icons/mob/clothing/taur_canine.dmi
index 26e4d488cd..24cf51d2e5 100644
Binary files a/icons/mob/clothing/taur_canine.dmi and b/icons/mob/clothing/taur_canine.dmi differ
diff --git a/icons/mob/clothing/taur_hooved.dmi b/icons/mob/clothing/taur_hooved.dmi
index 993e9c2550..03fd8c8a30 100644
Binary files a/icons/mob/clothing/taur_hooved.dmi and b/icons/mob/clothing/taur_hooved.dmi differ
diff --git a/icons/mob/clothing/taur_naga.dmi b/icons/mob/clothing/taur_naga.dmi
index a4c3644003..d178ba4a1c 100644
Binary files a/icons/mob/clothing/taur_naga.dmi and b/icons/mob/clothing/taur_naga.dmi differ
diff --git a/icons/mob/clothing/uniform.dmi b/icons/mob/clothing/uniform.dmi
index fa376635f9..3d24a9addd 100644
Binary files a/icons/mob/clothing/uniform.dmi and b/icons/mob/clothing/uniform.dmi differ
diff --git a/icons/mob/clothing/uniform_digi.dmi b/icons/mob/clothing/uniform_digi.dmi
index af72ac0e7b..bcb894033e 100644
Binary files a/icons/mob/clothing/uniform_digi.dmi and b/icons/mob/clothing/uniform_digi.dmi differ
diff --git a/icons/mob/inhands/antag/clockwork_lefthand.dmi b/icons/mob/inhands/antag/clockwork_lefthand.dmi
index 88bd8ab710..080d7fdc83 100644
Binary files a/icons/mob/inhands/antag/clockwork_lefthand.dmi and b/icons/mob/inhands/antag/clockwork_lefthand.dmi differ
diff --git a/icons/mob/inhands/antag/clockwork_righthand.dmi b/icons/mob/inhands/antag/clockwork_righthand.dmi
index 20190e4add..42715d6e92 100644
Binary files a/icons/mob/inhands/antag/clockwork_righthand.dmi and b/icons/mob/inhands/antag/clockwork_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/belt_lefthand.dmi b/icons/mob/inhands/equipment/belt_lefthand.dmi
index beac56725a..81b12c60f9 100644
Binary files a/icons/mob/inhands/equipment/belt_lefthand.dmi and b/icons/mob/inhands/equipment/belt_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/belt_righthand.dmi b/icons/mob/inhands/equipment/belt_righthand.dmi
index da31cc9710..42ed3a30c6 100644
Binary files a/icons/mob/inhands/equipment/belt_righthand.dmi and b/icons/mob/inhands/equipment/belt_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/hammers_lefthand.dmi b/icons/mob/inhands/weapons/hammers_lefthand.dmi
index 306fd0db8a..b753a1f181 100644
Binary files a/icons/mob/inhands/weapons/hammers_lefthand.dmi and b/icons/mob/inhands/weapons/hammers_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/hammers_righthand.dmi b/icons/mob/inhands/weapons/hammers_righthand.dmi
index 674e4d510b..7650f6c760 100644
Binary files a/icons/mob/inhands/weapons/hammers_righthand.dmi and b/icons/mob/inhands/weapons/hammers_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi
index 1e48d57ac7..0ca36ad43d 100644
Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi
index 5a5ee6f3db..59d7bbce69 100644
Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ
diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi
index 2bb8af7c61..082bfb3c3e 100644
Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
index 60fe2f9839..30c23601a5 100644
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/icons/mob/secbot_accessories.dmi b/icons/mob/secbot_accessories.dmi
new file mode 100644
index 0000000000..944aac44f3
Binary files /dev/null and b/icons/mob/secbot_accessories.dmi differ
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index bebb625440..e1caad8279 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/icons/obj/clockwork_objects.dmi b/icons/obj/clockwork_objects.dmi
index 1948bb605c..156d4fa0c6 100644
Binary files a/icons/obj/clockwork_objects.dmi and b/icons/obj/clockwork_objects.dmi differ
diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi
index 7e09d425fb..1c22a0ad1b 100644
Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ
diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi
index 535ae0d241..874f0d3660 100644
Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index b349161f8e..60304999fa 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/reinf_kits.dmi b/icons/obj/clothing/reinf_kits.dmi
new file mode 100644
index 0000000000..3b23d53342
Binary files /dev/null and b/icons/obj/clothing/reinf_kits.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 68210dc01f..e8a360bc87 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index 57424c7b99..76f5722c8b 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 193d4bc4da..5a9e1e54b6 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi
index ceda2fc9eb..5e1332ffd9 100644
Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index e87a37d069..078cadfd60 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/food/soupsalad.dmi b/icons/obj/food/soupsalad.dmi
index 378927e8f9..ca9c150480 100644
Binary files a/icons/obj/food/soupsalad.dmi and b/icons/obj/food/soupsalad.dmi differ
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index 33872719fe..7e7e4a644b 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index 8c50e7da27..9c6df36f49 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi
index c93865ca77..5415f47528 100644
Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ
diff --git a/icons/obj/implants.dmi b/icons/obj/implants.dmi
index a6d4697673..b7cb90e9f4 100644
Binary files a/icons/obj/implants.dmi and b/icons/obj/implants.dmi differ
diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi
index cf7a87d28b..57105cc089 100644
Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ
diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi
index 1f520a42bd..b240391328 100644
Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ
diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi
index 675005da91..0e262895fd 100644
Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ
diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi
index 43bc9c48aa..e7063b71db 100644
Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ
diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi
index cdcf6f1bd5..5d3cd0312c 100644
Binary files a/icons/obj/modular_console.dmi and b/icons/obj/modular_console.dmi differ
diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi
index 7cf5a77621..fd24d27a97 100644
Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ
diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi
index 2f9a0559ae..32edb57475 100644
Binary files a/icons/obj/modular_tablet.dmi and b/icons/obj/modular_tablet.dmi differ
diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi
index 3abb25d8b2..11d02a46cc 100644
Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ
diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi
index 67c1a59c51..16efcf262e 100644
Binary files a/icons/obj/stationobjs.dmi and b/icons/obj/stationobjs.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 3996f0ead2..8db1156dea 100755
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi
index f1a8cf3c02..0a457777c2 100644
Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index 9f3d8911ec..9c35ddb75f 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -66,7 +66,9 @@ h1.alert, h2.alert {color: #000000;}
.passive {color: #660000;}
.userdanger {color: #ff0000; font-weight: bold; font-size: 3;}
-.danger {color: #ff0000;}
+.danger {color: #ff0000; font-weight: bold;}
+.tinydanger {color: #ff0000; font-size: 85%;}
+.smalldanger {color: #ff0000; font-size: 90%;}
.warning {color: #ff0000; font-style: italic;}
.boldwarning {color: #ff0000; font-style: italic; font-weight: bold}
.announce {color: #228b22; font-weight: bold;}
@@ -75,6 +77,9 @@ h1.alert, h2.alert {color: #000000;}
.rose {color: #ff5050;}
.info {color: #0000CC;}
.notice {color: #000099;}
+.tinynotice {color: #000099; font-size: 85%;}
+.smallnotice {color: #000099; font-size: 90%;}
+.smallnoticeital {color: #000099; font-style: italic; font-size: 90%;}
.boldnotice {color: #000099; font-weight: bold;}
.adminnotice {color: #0000ff;}
.adminhelp {color: #ff0000; font-weight: bold;}
diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm
index 47eef6a820..0e971d4ced 100644
--- a/modular_citadel/code/datums/status_effects/chems.dm
+++ b/modular_citadel/code/datums/status_effects/chems.dm
@@ -53,7 +53,6 @@
if(last_checked_size != B.cached_size)
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/breast_hypertrophy, multiplicative_slowdown = moveCalc)
- sizeMoveMod(moveCalc)
if (B.size == "huge")
if(prob(1))
@@ -70,16 +69,8 @@
log_reagent("FERMICHEM: [owner]'s breasts has reduced to an acceptable size. ID: [owner.key]")
to_chat(owner, "Your expansive chest has become a more managable size, liberating your movements.")
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/breast_hypertrophy)
- sizeMoveMod(1)
return ..()
-/datum/status_effect/chem/breast_enlarger/proc/sizeMoveMod(var/value)
- if(cachedmoveCalc == value)
- return
- owner.next_move_modifier /= cachedmoveCalc
- owner.next_move_modifier *= value
- cachedmoveCalc = value
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/status_effect/chem/penis_enlarger
@@ -230,7 +221,7 @@
var/mob/living/carbon/M = owner
//chem calculations
- if(!owner.reagents.has_reagent(/datum/chemical_reaction/fermi/enthrall))
+ if(!owner.reagents.has_reagent(/datum/reagent/fermi/enthrall))
if (phase < 3 && phase != 0)
deltaResist += 3//If you've no chem, then you break out quickly
if(prob(5))
@@ -592,16 +583,6 @@
C.Stun(60)
to_chat(owner, "Your muscles seize up, then start spasming wildy!")
- //wah intensifies wah-rks
- else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- if (lewd)
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- H.mob_climax(forced_climax=TRUE)
- C.SetStun(10)//We got your stun effects in somewhere, Kev.
- else
- C.throw_at(get_step_towards(hearing_args[HEARING_SPEAKER],C), 3, 1) //cut this if it's too hard to get working
-
//kneel (knockdown)
else if (lowertext(customTriggers[trigger]) == "kneel")//as close to kneeling as you can get, I suppose.
to_chat(owner, "You drop to the ground unsurreptitiously.")
@@ -683,15 +664,6 @@
deltaResist *= 1.25
if (owner.reagents.has_reagent(/datum/reagent/medicine/neurine))
deltaResist *= 1.5
- if (!(owner.client?.prefs.cit_toggles & NO_APHRO) && lewd)
- if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiac))
- deltaResist *= 1.5
- if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiacplus))
- deltaResist *= 2
- if (owner.reagents.has_reagent(/datum/reagent/drug/aphrodisiac))
- deltaResist *= 0.75
- if (owner.reagents.has_reagent(/datum/reagent/drug/aphrodisiacplus))
- deltaResist *= 0.5
//Antag resistance
//cultists are already brainwashed by their god
if(iscultist(owner))
diff --git a/modular_citadel/code/game/objects/cit_screenshake.dm b/modular_citadel/code/game/objects/cit_screenshake.dm
index 188b8a48f9..222de37f82 100644
--- a/modular_citadel/code/game/objects/cit_screenshake.dm
+++ b/modular_citadel/code/game/objects/cit_screenshake.dm
@@ -45,18 +45,6 @@
. = ..()
shake_camera(user, (pressureSetting * 0.75 + 1), (pressureSetting * 0.75))
-/obj/item/attack(mob/living/M, mob/living/user)
- . = ..()
- if(force >= 15)
- shake_camera(user, ((force - 10) * 0.01 + 1), ((force - 10) * 0.01))
- if(M.client)
- switch (M.client.prefs.damagescreenshake)
- if (1)
- shake_camera(M, ((force - 10) * 0.015 + 1), ((force - 10) * 0.015))
- if (2)
- if(!CHECK_MOBILITY(M, MOBILITY_MOVE))
- shake_camera(M, ((force - 10) * 0.015 + 1), ((force - 10) * 0.015))
-
/obj/item/attack_obj(obj/O, mob/living/user)
. = ..()
if(force >= 20)
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index d428fc290a..378c70d187 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -1,496 +1,497 @@
//This is the file that handles donator loadout items.
-/datum/gear/pingcoderfailsafe
+/datum/gear/donator
name = "IF YOU SEE THIS, PING A CODER RIGHT NOW!"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/bikehorn/golden
+ category = LOADOUT_CATEGORY_DONATOR
ckeywhitelist = list("This entry should never appear with this variable set.") //If it does, then that means somebody fucked up the whitelist system pretty hard
-/datum/gear/donortestingbikehorn
+/datum/gear/donator/donortestingbikehorn
name = "Donor item testing bikehorn"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/bikehorn
geargroupID = list("DONORTEST") //This is a list mainly for the sake of testing, but geargroupID works just fine with ordinary strings
-/datum/gear/kevhorn
+/datum/gear/donator/kevhorn
name = "Airhorn"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/bikehorn/airhorn
ckeywhitelist = list("kevinz000")
-/datum/gear/cebusoap
+/datum/gear/donator/cebusoap
name = "Cebutris' soap"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/custom/ceb_soap
ckeywhitelist = list("cebutris")
-/datum/gear/kiaracloak
+/datum/gear/donator/kiaracloak
name = "Kiara's cloak"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/cloak/inferno
ckeywhitelist = list("inferno707")
-/datum/gear/kiaracollar
+/datum/gear/donator/kiaracollar
name = "Kiara's collar"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/inferno
ckeywhitelist = list("inferno707")
-/datum/gear/kiaramedal
+/datum/gear/donator/kiaramedal
name = "Insignia of Steele"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/clothing/accessory/medal/steele
ckeywhitelist = list("inferno707")
-/datum/gear/hheart
+/datum/gear/donator/hheart
name = "The Hollow Heart"
- category = SLOT_WEAR_MASK
+ slot = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/hheart
ckeywhitelist = list("inferno707")
-/datum/gear/engravedzippo
+/datum/gear/donator/engravedzippo
name = "Engraved zippo"
- category = SLOT_HANDS
+ slot = SLOT_HANDS
path = /obj/item/lighter/gold
ckeywhitelist = list("dirtyoldharry")
-/datum/gear/geisha
+/datum/gear/donator/geisha
name = "Geisha suit"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/geisha
ckeywhitelist = list("atiefling")
-/datum/gear/specialscarf
+/datum/gear/donator/specialscarf
name = "Special scarf"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/scarf/zomb
ckeywhitelist = list("zombierobin")
-/datum/gear/redmadcoat
+/datum/gear/donator/redmadcoat
name = "The Mad's labcoat"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/toggle/labcoat/mad/red
ckeywhitelist = list("zombierobin")
-/datum/gear/santahat
+/datum/gear/donator/santahat
name = "Santa hat"
- category = SLOT_HEAD
+ slot = SLOT_HEAD
path = /obj/item/clothing/head/santa/fluff
ckeywhitelist = list("illotafv")
-/datum/gear/reindeerhat
+/datum/gear/donator/reindeerhat
name = "Reindeer hat"
- category = SLOT_HEAD
+ slot = SLOT_HEAD
path = /obj/item/clothing/head/hardhat/reindeer/fluff
ckeywhitelist = list("illotafv")
-/datum/gear/treeplushie
+/datum/gear/donator/treeplushie
name = "Christmas tree plushie"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/tree
ckeywhitelist = list("illotafv")
-/datum/gear/santaoutfit
+/datum/gear/donator/santaoutfit
name = "Santa costume"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/space/santa/fluff
ckeywhitelist = list("illotafv")
-/datum/gear/treecloak
+/datum/gear/donator/treecloak
name = "Christmas tree cloak"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/cloak/festive
ckeywhitelist = list("illotafv")
-/datum/gear/carrotplush
+/datum/gear/donator/carrotplush
name = "Carrot plushie"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/carrot
ckeywhitelist = list("improvedname")
-/datum/gear/carrotcloak
+/datum/gear/donator/carrotcloak
name = "Carrot cloak"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/cloak/carrot
ckeywhitelist = list("improvedname")
-/datum/gear/albortorosamask
+/datum/gear/donator/albortorosamask
name = "Alborto Rosa mask"
- category = SLOT_WEAR_MASK
+ slot = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/luchador/zigfie
ckeywhitelist = list("zigfie")
-/datum/gear/mankini
+/datum/gear/donator/mankini
name = "Mankini"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/stripper/mankini
ckeywhitelist = list("zigfie")
-/datum/gear/pinkshoes
+/datum/gear/donator/pinkshoes
name = "Pink shoes"
- category = SLOT_SHOES
+ slot = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/pink
ckeywhitelist = list("zigfie")
-/datum/gear/reecesgreatcoat
+/datum/gear/donator/reecesgreatcoat
name = "Reece's Great Coat"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/trenchcoat/green
ckeywhitelist = list("geemiesif")
-/datum/gear/russianflask
+/datum/gear/donator/russianflask
name = "Russian flask"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/reagent_containers/food/drinks/flask/russian
cost = 2
ckeywhitelist = list("slomka")
-/datum/gear/stalkermask
+/datum/gear/donator/stalkermask
name = "S.T.A.L.K.E.R. mask"
- category = SLOT_WEAR_MASK
+ slot = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/gas/stalker
ckeywhitelist = list("slomka")
-/datum/gear/stripedcollar
+/datum/gear/donator/stripedcollar
name = "Striped collar"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/stripe
ckeywhitelist = list("jademanique")
-/datum/gear/performersoutfit
+/datum/gear/donator/performersoutfit
name = "Bluish performer's outfit"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/singer/yellow/custom
ckeywhitelist = list("killer402402")
-/datum/gear/vermillion
+/datum/gear/donator/vermillion
name = "Vermillion clothing"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/suit/vermillion
ckeywhitelist = list("fractious")
-/datum/gear/AM4B
+/datum/gear/donator/AM4B
name = "Foam Force AM4-B"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/gun/ballistic/automatic/AM4B
ckeywhitelist = list("zeronetalpha")
-/datum/gear/carrotsatchel
+/datum/gear/donator/carrotsatchel
name = "Carrot Satchel"
- category = SLOT_HANDS
+ slot = SLOT_HANDS
path = /obj/item/storage/backpack/satchel/carrot
ckeywhitelist = list("improvedname")
-/datum/gear/naomisweater
+/datum/gear/donator/naomisweater
name = "worn black sweater"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater/black/naomi
ckeywhitelist = list("technicalmagi")
-/datum/gear/naomicollar
+/datum/gear/donator/naomicollar
name = "worn pet collar"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/naomi
ckeywhitelist = list("technicalmagi")
-/datum/gear/gladiator
+/datum/gear/donator/gladiator
name = "Gladiator Armor"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/under/costume/gladiator
ckeywhitelist = list("aroche")
-/datum/gear/bloodredtie
+/datum/gear/donator/bloodredtie
name = "Blood Red Tie"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/tie/bloodred
ckeywhitelist = list("kyutness")
-/datum/gear/puffydress
+/datum/gear/donator/puffydress
name = "Puffy Dress"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/puffydress
ckeywhitelist = list("stallingratt")
-/datum/gear/labredblack
+/datum/gear/donator/labredblack
name = "Black and Red Coat"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/toggle/labcoat/labredblack
ckeywhitelist = list("blakeryan", "durandalphor")
-/datum/gear/torisword
+/datum/gear/donator/torisword
name = "Rainbow Zweihander"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/dualsaber/hypereutactic/toy/rainbow
ckeywhitelist = list("annoymous35")
-/datum/gear/darksabre
+/datum/gear/donator/darksabre
name = "Dark Sabre"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/darksabre
ckeywhitelist = list("inferno707")
-datum/gear/darksabresheath
+/datum/gear/donator/darksabresheath
name = "Dark Sabre Sheath"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/storage/belt/sabre/darksabre
ckeywhitelist = list("inferno707")
-/datum/gear/toriball
+/datum/gear/donator/toriball
name = "Rainbow Tennis Ball"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/rainbow
ckeywhitelist = list("annoymous35")
-/datum/gear/izzyball
+/datum/gear/donator/izzyball
name = "Katlin's Ball"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/rainbow/izzy
ckeywhitelist = list("izzyinbox")
-/datum/gear/cloak
+/datum/gear/donator/cloak
name = "Green Cloak"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/cloak/green
ckeywhitelist = list("killer402402")
-/datum/gear/steelflask
+/datum/gear/donator/steelflask
name = "Steel Flask"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/reagent_containers/food/drinks/flask/steel
cost = 2
ckeywhitelist = list("nik707")
-/datum/gear/paperhat
+/datum/gear/donator/paperhat
name = "Paper Hat"
- category = SLOT_HEAD
+ slot = SLOT_HEAD
path = /obj/item/clothing/head/paperhat
ckeywhitelist = list("kered2")
-/datum/gear/cloakce
+/datum/gear/donator/cloakce
name = "Polychromic CE Cloak"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/clothing/neck/cloak/polychromic/polyce
ckeywhitelist = list("worksbythesea", "blakeryan")
-/datum/gear/ssk
+/datum/gear/donator/ssk
name = "Stun Sword Kit"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/ssword_kit
ckeywhitelist = list("phillip458")
-/datum/gear/techcoat
+/datum/gear/donator/techcoat
name = "Techomancers Labcoat"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/clothing/suit/toggle/labcoat/mad/techcoat
ckeywhitelist = list("wilchen")
-/datum/gear/leechjar
+/datum/gear/donator/leechjar
name = "Jar of Leeches"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/custom/leechjar
ckeywhitelist = list("sgtryder")
-/datum/gear/darkarmor
+/datum/gear/donator/darkarmor
name = "Dark Armor"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/clothing/suit/armor/vest/darkcarapace
ckeywhitelist = list("inferno707")
-/datum/gear/devilwings
+/datum/gear/donator/devilwings
name = "Strange Wings"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/devilwings
ckeywhitelist = list("kitsun")
-/datum/gear/flagcape
+/datum/gear/donator/flagcape
name = "US Flag Cape"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/clothing/neck/flagcape
ckeywhitelist = list("darnchacha")
-/datum/gear/luckyjack
+/datum/gear/donator/luckyjack
name = "Lucky Jackboots"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/clothing/shoes/lucky
ckeywhitelist = list("donaldtrumpthecommunist")
-/datum/gear/raiqbawks
+/datum/gear/donator/raiqbawks
name = "Miami Boombox"
- category = SLOT_HANDS
+ slot = SLOT_HANDS
cost = 2
path = /obj/item/boombox/raiq
ckeywhitelist = list("chefferz")
-/datum/gear/m41
+/datum/gear/donator/m41
name = "Toy M41"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/gun/m41
ckeywhitelist = list("thalverscholen")
-/datum/gear/Divine_robes
+/datum/gear/donator/Divine_robes
name = "Divine robes"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/custom/lunasune
ckeywhitelist = list("invader4352")
-/datum/gear/gothcoat
+/datum/gear/donator/gothcoat
name = "Goth Coat"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/gothcoat
ckeywhitelist = list("norko")
-/datum/gear/corgisuit
+/datum/gear/donator/corgisuit
name = "Corgi Suit"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/ian_costume
ckeywhitelist = list("cathodetherobot")
-/datum/gear/sharkcloth
+/datum/gear/donator/sharkcloth
name = "Leon's Skimpy Outfit"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/under/custom/leoskimpy
ckeywhitelist = list("spectrosis")
-/datum/gear/mimemask
+/datum/gear/donator/mimemask
name = "Mime Mask"
- category = SLOT_WEAR_MASK
+ slot = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/gas/mime
ckeywhitelist = list("pireamaineach")
-/datum/gear/mimeoveralls
+/datum/gear/donator/mimeoveralls
name = "Mime's Overalls"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/under/custom/mimeoveralls
ckeywhitelist = list("pireamaineach")
-/datum/gear/soulneck
+/datum/gear/donator/soulneck
name = "Soul Necklace"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/undertale
ckeywhitelist = list("twilightic")
-/datum/gear/frenchberet
+/datum/gear/donator/frenchberet
name = "French Beret"
- category = SLOT_HEAD
+ slot = SLOT_HEAD
path = /obj/item/clothing/head/frenchberet
ckeywhitelist = list("notazoltan")
-/datum/gear/zuliecloak
+/datum/gear/donator/zuliecloak
name = "Project: Zul-E"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/cloak/zuliecloak
ckeywhitelist = list("asky")
-/datum/gear/blackredgold
+/datum/gear/donator/blackredgold
name = "Black, Red, and Gold Coat"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/blackredgold
ckeywhitelist = list("ttbnc")
-/datum/gear/fritzplush
+/datum/gear/donator/fritzplush
name = "Fritz Plushie"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/mammal/dog/fritz
ckeywhitelist = list("analwerewolf")
-/datum/gear/kimono
+/datum/gear/donator/kimono
name = "Kimono"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/kimono
ckeywhitelist = list("sfox63")
-/datum/gear/commjacket
+/datum/gear/donator/commjacket
name = "Dusty Commisar's Cloak"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/commjacket
ckeywhitelist = list("sadisticbatter")
-/datum/gear/mw2_russian_para
+/datum/gear/donator/mw2_russian_para
name = "Russian Paratrooper Jumper"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/custom/mw2_russian_para
ckeywhitelist = list("investigator77")
-/datum/gear/longblackgloves
+/datum/gear/donator/longblackgloves
name = "Luna's Gauntlets"
- category = SLOT_GLOVES
+ slot = SLOT_GLOVES
path = /obj/item/clothing/gloves/longblackgloves
ckeywhitelist = list("bigmanclancy")
-/datum/gear/trendy_fit
+/datum/gear/donator/trendy_fit
name = "Trendy Fit"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/custom/trendy_fit
ckeywhitelist = list("midgetdragon")
-/datum/gear/singery
+/datum/gear/donator/singery
name = "Yellow Performer Outfit"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/singer/yellow
ckeywhitelist = list("maxlynchy")
-/datum/gear/csheet
+/datum/gear/donator/csheet
name = "NT Bedsheet"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/bedsheet/captain
ckeywhitelist = list("tikibomb")
-/datum/gear/borgplush
+/datum/gear/donator/borgplush
name = "Robot Plush"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/borgplushie
ckeywhitelist = list("nicholaiavenicci")
-/datum/gear/donorberet
+/datum/gear/donator/donorberet
name = "Atmos Beret"
- category = SLOT_HEAD
+ slot = SLOT_HEAD
path = /obj/item/clothing/head/blueberet
ckeywhitelist = list("foxystalin")
-/datum/gear/donorgoggles
+/datum/gear/donator/donorgoggles
name = "Flight Goggles"
- category = SLOT_HEAD
+ slot = SLOT_HEAD
path = /obj/item/clothing/head/flight
ckeywhitelist = list("maxlynchy")
-/datum/gear/onionneck
+/datum/gear/donator/onionneck
name = "Onion Necklace"
- category = SLOT_NECK
+ slot = SLOT_NECK
path = /obj/item/clothing/neck/necklace/onion
ckeywhitelist = list("cdrcross")
-/datum/gear/mikubikini
+/datum/gear/donator/mikubikini
name = "starlight singer bikini"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/under/custom/mikubikini
ckeywhitelist = list("grandvegeta")
-/datum/gear/mikujacket
+/datum/gear/donator/mikujacket
name = "starlight singer jacket"
- category = SLOT_WEAR_SUIT
+ slot = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/mikujacket
ckeywhitelist = list("grandvegeta")
-/datum/gear/mikuhair
+/datum/gear/donator/mikuhair
name = "starlight singer hair"
- category = SLOT_W_UNIFORM
+ slot = SLOT_W_UNIFORM
path = /obj/item/clothing/head/mikuhair
ckeywhitelist = list("grandvegeta")
-/datum/gear/mikugloves
+/datum/gear/donator/mikugloves
name = "starlight singer gloves"
- category = SLOT_GLOVES
+ slot = SLOT_GLOVES
path = /obj/item/clothing/gloves/mikugloves
ckeywhitelist = list("grandvegeta")
-/datum/gear/mikuleggings
+/datum/gear/donator/mikuleggings
name = "starlight singer leggings"
- category = SLOT_SHOES
+ slot = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/mikuleggings
ckeywhitelist = list("grandvegeta")
-/datum/gear/cosmos
+/datum/gear/donator/cosmos
name = "cosmic space bedsheet"
- category = SLOT_IN_BACKPACK
+ slot = SLOT_IN_BACKPACK
path = /obj/item/bedsheet/cosmos
ckeywhitelist = list("grunnyyy")
diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm
index 51256f8cde..0ebfa060f2 100644
--- a/modular_citadel/code/modules/client/loadout/_loadout.dm
+++ b/modular_citadel/code/modules/client/loadout/_loadout.dm
@@ -27,8 +27,13 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids)
/proc/initialize_global_loadout_items()
load_loadout_config()
for(var/item in subtypesof(/datum/gear))
- var/datum/gear/I = new item
- LAZYSET(GLOB.loadout_items[slot_to_string(I.category)], I.name, I)
+ var/datum/gear/I = item
+ if(!initial(I.name))
+ continue
+ I = new item
+ LAZYINITLIST(GLOB.loadout_items[I.category])
+ LAZYINITLIST(GLOB.loadout_items[I.category][I.subcategory])
+ GLOB.loadout_items[I.category][I.subcategory][I.name] = I
if(islist(I.geargroupID))
var/list/ggidlist = I.geargroupID
I.ckeywhitelist = list()
@@ -41,7 +46,9 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids)
/datum/gear
var/name
- var/category
+ var/category = LOADOUT_CATEGORY_NONE
+ var/subcategory = LOADOUT_SUBCATEGORY_NONE
+ var/slot
var/description
var/path //item-to-spawn path
var/cost = 1 //normally, each loadout costs a single point.
diff --git a/modular_citadel/code/modules/client/loadout/_medical.dm b/modular_citadel/code/modules/client/loadout/_medical.dm
index 604a0f96ae..e371db94fc 100644
--- a/modular_citadel/code/modules/client/loadout/_medical.dm
+++ b/modular_citadel/code/modules/client/loadout/_medical.dm
@@ -1,47 +1,45 @@
-/datum/gear/medicbriefcase
+/datum/gear/hands/medicbriefcase
name = "Medical Briefcase"
- category = SLOT_HANDS
path = /obj/item/storage/briefcase/medical
restricted_roles = list("Medical Doctor", "Chief Medical Officer")
restricted_desc = "MD, CMO"
-/datum/gear/stethoscope
+/datum/gear/neck/stethoscope
name = "Stethoscope"
- category = SLOT_NECK
path = /obj/item/clothing/neck/stethoscope
restricted_roles = list("Medical Doctor", "Chief Medical Officer")
-/datum/gear/bluescrubs
+/datum/gear/uniform/bluescrubs
name = "Blue Scrubs"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/medical/doctor/blue
restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist")
restricted_desc = "Medical"
-
-/datum/gear/greenscrubs
+
+/datum/gear/uniform/greenscrubs
name = "Green Scrubs"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/medical/doctor/green
restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist")
restricted_desc = "Medical"
-/datum/gear/purplescrubs
+/datum/gear/uniform/purplescrubs
name = "Purple Scrubs"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/medical/doctor/purple
restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist")
restricted_desc = "Medical"
-/datum/gear/nursehat
+/datum/gear/head/nursehat
name = "Nurse Hat"
- category = SLOT_HEAD
path = /obj/item/clothing/head/nursehat
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist")
restricted_desc = "Medical"
-/datum/gear/nursesuit
+/datum/gear/uniform/nursesuit
name = "Nurse Suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/rank/medical/doctor/nurse
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Medical Doctor", "Chief Medical Officer", "Geneticist", "Chemist", "Virologist")
- restricted_desc = "Medical"
\ No newline at end of file
+ restricted_desc = "Medical"
diff --git a/modular_citadel/code/modules/client/loadout/_security.dm b/modular_citadel/code/modules/client/loadout/_security.dm
index 72a6aab394..ab316d577b 100644
--- a/modular_citadel/code/modules/client/loadout/_security.dm
+++ b/modular_citadel/code/modules/client/loadout/_security.dm
@@ -1,71 +1,70 @@
-/datum/gear/navyblueuniformhos
+/datum/gear/uniform/navyblueuniformhos
name = "Head of Security navyblue uniform"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/security/head_of_security/formal
restricted_roles = list("Head of Security")
-/datum/gear/navybluehosberet
+/datum/gear/head/navybluehosberet
name = "Head of security's navyblue beret"
- category = SLOT_HEAD
path = /obj/item/clothing/head/beret/sec/navyhos
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Head of Security")
-/datum/gear/navybluejackethos
+/datum/gear/suit/navybluejackethos
name = "head of security's navyblue jacket"
- category = SLOT_WEAR_SUIT
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
path = /obj/item/clothing/suit/armor/hos/navyblue
restricted_roles = list("Head of Security")
-/datum/gear/navybluejacketofficer
+/datum/gear/suit/navybluejacketofficer
name = "security officer's navyblue jacket"
- category = SLOT_WEAR_SUIT
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
path = /obj/item/clothing/suit/armor/navyblue
restricted_roles = list("Security Officer")
-/datum/gear/navyblueofficerberet
+/datum/gear/head/navyblueofficerberet
name = "Security officer's Navyblue beret"
- category = SLOT_HEAD
path = /obj/item/clothing/head/beret/sec/navyofficer
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Security Officer")
-/datum/gear/navyblueuniformofficer
+/datum/gear/uniform/navyblueuniformofficer
name = "Security officer navyblue uniform"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/security/officer/formal
restricted_roles = list("Security Officer")
-/datum/gear/navybluejacketwarden
+/datum/gear/suit/navybluejacketwarden
name = "warden navyblue jacket"
- category = SLOT_WEAR_SUIT
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
path = /obj/item/clothing/suit/armor/vest/warden/navyblue
restricted_roles = list("Warden")
-/datum/gear/navybluewardenberet
+/datum/gear/head/navybluewardenberet
name = "Warden's navyblue beret"
- category = SLOT_HEAD
path = /obj/item/clothing/head/beret/sec/navywarden
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Warden")
-/datum/gear/navyblueuniformwarden
+/datum/gear/uniform/navyblueuniformwarden
name = "Warden navyblue uniform"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/security/warden/formal
restricted_roles = list("Warden")
-/datum/gear/secskirt
+/datum/gear/uniform/secskirt
name = "Security skirt"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/security/officer/skirt
restricted_roles = list("Security Officer", "Warden", "Head of Security")
-/datum/gear/hosskirt
+/datum/gear/uniform/hosskirt
name = "Head of security's skirt"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/rank/security/head_of_security/skirt
restricted_roles = list("Head of Security")
-/datum/gear/sechud
+/datum/gear/glasses/sechud
name = "Security Hud"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/hud/security
- restricted_roles = list("Security Officer", "Warden", "Head of Security")
\ No newline at end of file
+ restricted_roles = list("Security Officer", "Warden", "Head of Security")
diff --git a/modular_citadel/code/modules/client/loadout/_service.dm b/modular_citadel/code/modules/client/loadout/_service.dm
index ab3daa5f3c..848ad6233c 100644
--- a/modular_citadel/code/modules/client/loadout/_service.dm
+++ b/modular_citadel/code/modules/client/loadout/_service.dm
@@ -1,33 +1,33 @@
-/datum/gear/greytidestationwide
+/datum/gear/uniform/greytidestationwide
name = "Staff Assistant's jumpsuit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/staffassistant
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Assistant")
-/datum/gear/neetsuit
+/datum/gear/suit/neetsuit
name = "D.A.B. suit"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/assu_suit
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Assistant")
cost = 2
-/datum/gear/neethelm
+/datum/gear/head/neethelm
name = "D.A.B. helmet"
- category = SLOT_HEAD
path = /obj/item/clothing/head/assu_helmet
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Assistant")
cost = 2
-/datum/gear/plushvar
+/datum/gear/backpack/plushvar
name = "Ratvar Plushie"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/plushvar
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
cost = 5
restricted_roles = list("Chaplain")
-/datum/gear/narplush
+/datum/gear/backpack/narplush
name = "Narsie Plushie"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/narplush
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
cost = 5
restricted_roles = list("Chaplain")
diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm
index 690e012840..fbc498df64 100644
--- a/modular_citadel/code/modules/client/loadout/backpack.dm
+++ b/modular_citadel/code/modules/client/loadout/backpack.dm
@@ -1,112 +1,100 @@
-/datum/gear/plushbox
+/datum/gear/backpack
+ category = LOADOUT_CATEGORY_BACKPACK
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_GENERAL
+ slot = SLOT_IN_BACKPACK
+
+/datum/gear/backpack/plushbox
name = "Plushie Choice Box"
- category = SLOT_IN_BACKPACK
path = /obj/item/choice_beacon/box/plushie
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
-/datum/gear/tennis
+/datum/gear/backpack/tennis
name = "Classic Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
-/datum/gear/tennisred
+/datum/gear/backpack/tennis/red
name = "Red Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/red
-/datum/gear/tennisyellow
+/datum/gear/backpack/tennis/yellow
name = "Yellow Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/yellow
-/datum/gear/tennisgreen
+/datum/gear/backpack/tennis/green
name = "Green Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/green
-/datum/gear/tenniscyan
+/datum/gear/backpack/tennis/cyan
name = "Cyan Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/cyan
-/datum/gear/tennisblue
+/datum/gear/backpack/tennis/blue
name = "Blue Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/blue
-/datum/gear/tennispurple
+/datum/gear/backpack/tennis/purple
name = "Purple Tennis Ball"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/purple
-/datum/gear/dildo
+/datum/gear/backpack/dildo
name = "Customizable dildo"
- category = SLOT_IN_BACKPACK
path = /obj/item/dildo/custom
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
-/datum/gear/toykatana
+/datum/gear/backpack/toykatana
name = "Toy Katana"
- category = SLOT_IN_BACKPACK
path = /obj/item/toy/katana
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
cost = 3
-/datum/gear/tapeplayer
+/datum/gear/backpack/tapeplayer
name = "Taperecorder"
- category = SLOT_IN_BACKPACK
path = /obj/item/taperecorder
-/datum/gear/tape
+/datum/gear/backpack/tape
name = "Spare cassette tape"
- category = SLOT_IN_BACKPACK
path = /obj/item/tape/random
-/datum/gear/newspaper
+/datum/gear/backpack/newspaper
name = "Newspaper"
- category = SLOT_IN_BACKPACK
path = /obj/item/newspaper
-/datum/gear/crayons
+/datum/gear/backpack/crayons
name = "Box of crayons"
- category = SLOT_IN_BACKPACK
path = /obj/item/storage/crayons
+ subcategory = LOADOUT_SUBCATEGORY_BACKPACK_TOYS
-/datum/gear/multipen
+/datum/gear/backpack/multipen
name = "A multicolored pen"
- category = SLOT_IN_BACKPACK
path = /obj/item/pen/fourcolor
-/datum/gear/fountainpen
+/datum/gear/backpack/fountainpen
name = "A fancy pen"
- category = SLOT_IN_BACKPACK
path = /obj/item/pen/fountain
cost = 2
-/datum/gear/modular_tablet
+/datum/gear/backpack/modular_tablet
name = "A modular tablet"
- category = SLOT_IN_BACKPACK
path = /obj/item/modular_computer/tablet/preset/cheap/
cost = 4
-/datum/gear/modular_laptop
+/datum/gear/backpack/modular_laptop
name = "A modular laptop"
- category = SLOT_IN_BACKPACK
path = /obj/item/modular_computer/laptop/preset/civilian
cost = 7
-/datum/gear/ringbox_gold
+/datum/gear/backpack/ringbox_gold
name = "A gold ring box"
- category = SLOT_IN_BACKPACK
path = /obj/item/storage/fancy/ringbox
cost = 3
-/datum/gear/ringbox_silver
+/datum/gear/backpack/ringbox_silver
name = "A silver ring box"
- category = SLOT_IN_BACKPACK
path = /obj/item/storage/fancy/ringbox/silver
cost = 3
-/datum/gear/ringbox_diamond
+/datum/gear/backpack/ringbox_diamond
name = "A diamond ring box"
- category = SLOT_IN_BACKPACK
path = /obj/item/storage/fancy/ringbox/diamond
cost = 5
-
diff --git a/modular_citadel/code/modules/client/loadout/glasses.dm b/modular_citadel/code/modules/client/loadout/glasses.dm
index 57270d8e57..b0eecbbf28 100644
--- a/modular_citadel/code/modules/client/loadout/glasses.dm
+++ b/modular_citadel/code/modules/client/loadout/glasses.dm
@@ -1,49 +1,43 @@
-/datum/gear/blindfold
+/datum/gear/glasses
+ category = LOADOUT_CATEGORY_GLASSES
+ slot = SLOT_GLASSES
+
+/datum/gear/glasses/blindfold
name = "Blindfold"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/sunglasses/blindfold
-/datum/gear/cold
+/datum/gear/glasses/cold
name = "Cold goggles"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/cold
-/datum/gear/eyepatch
+/datum/gear/glasses/eyepatch
name = "Eyepatch"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/eyepatch
-/datum/gear/heat
+/datum/gear/glasses/heat
name = "Heat goggles"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/heat
-/datum/gear/hipster
+/datum/gear/glasses/hipster
name = "Hipster glasses"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/regular/hipster
-/datum/gear/jamjar
+/datum/gear/glasses/jamjar
name = "Jamjar glasses"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/regular/jamjar
-/datum/gear/monocle
+/datum/gear/glasses/monocle
name = "Monocle"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/monocle
-/datum/gear/orange
+/datum/gear/glasses/orange
name = "Orange glasses"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/orange
-/datum/gear/red
+/datum/gear/glasses/red
name = "Red Glasses"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/red
-/datum/gear/prescription
+/datum/gear/glasses/prescription
name = "Prescription glasses"
- category = SLOT_GLASSES
path = /obj/item/clothing/glasses/regular
diff --git a/modular_citadel/code/modules/client/loadout/gloves.dm b/modular_citadel/code/modules/client/loadout/gloves.dm
index 72e6e91cfc..85be8bd487 100644
--- a/modular_citadel/code/modules/client/loadout/gloves.dm
+++ b/modular_citadel/code/modules/client/loadout/gloves.dm
@@ -1,23 +1,26 @@
-/datum/gear/fingerless
+/datum/gear/gloves
+ category = LOADOUT_CATEGORY_GLOVES
+ slot = SLOT_GLOVES
+
+/datum/gear/gloves/fingerless
name = "Fingerless Gloves"
- category = SLOT_GLOVES
path = /obj/item/clothing/gloves/fingerless
-/datum/gear/goldring
+/datum/gear/gloves/evening
+ name = "Evening gloves"
+ path = /obj/item/clothing/gloves/evening
+
+/datum/gear/gloves/goldring
name = "A gold ring"
- category = SLOT_GLOVES
path = /obj/item/clothing/gloves/ring
cost = 2
-/datum/gear/silverring
+/datum/gear/gloves/silverring
name = "A silver ring"
- category = SLOT_GLOVES
path = /obj/item/clothing/gloves/ring/silver
cost = 2
-/datum/gear/diamondring
+/datum/gear/gloves/diamondring
name = "A diamond ring"
- category = SLOT_GLOVES
path = /obj/item/clothing/gloves/ring/diamond
cost = 4
-
diff --git a/modular_citadel/code/modules/client/loadout/hands.dm b/modular_citadel/code/modules/client/loadout/hands.dm
index 2f03bd3b07..db57fb466b 100644
--- a/modular_citadel/code/modules/client/loadout/hands.dm
+++ b/modular_citadel/code/modules/client/loadout/hands.dm
@@ -1,67 +1,54 @@
-/datum/gear/cane
+/datum/gear/hands
+ category = LOADOUT_CATEGORY_HANDS
+ slot = SLOT_HANDS
+
+/datum/gear/hands/cane
name = "Cane"
- category = SLOT_HANDS
path = /obj/item/cane
-/datum/gear/cigarettes
+/datum/gear/hands/cigarettes
name = "Cigarette pack"
- category = SLOT_HANDS
path = /obj/item/storage/fancy/cigarettes
-/datum/gear/dice
+/datum/gear/hands/dice
name = "Dice bag"
- category = SLOT_HANDS
path = /obj/item/storage/box/dice
-/datum/gear/eightball
+/datum/gear/hands/eightball
name = "Magic eightball"
- category = SLOT_HANDS
path = /obj/item/toy/eightball
-/datum/gear/matches
+/datum/gear/hands/matches
name = "Matchbox"
- category = SLOT_HANDS
path = /obj/item/storage/box/matches
-/datum/gear/cheaplighter
+/datum/gear/hands/cheaplighter
name = "Cheap lighter"
- category = SLOT_HANDS
path = /obj/item/lighter/greyscale
-/datum/gear/cards
+/datum/gear/hands/cards
name = "Playing cards"
- category = SLOT_HANDS
path = /obj/item/toy/cards/deck
-/datum/gear/skub
+/datum/gear/hands/skub
name = "Skub"
- category = SLOT_HANDS
path = /obj/item/skub
-/datum/gear/carpplushie
- name = "Space carp plushie"
- category = SLOT_HANDS
- path = /obj/item/toy/plush/carpplushie
-
-/datum/gear/wallet
+/datum/gear/hands/wallet
name = "Wallet"
- category = SLOT_HANDS
path = /obj/item/storage/wallet
-/datum/gear/flask
+/datum/gear/hands/flask
name = "Flask"
- category = SLOT_HANDS
path = /obj/item/reagent_containers/food/drinks/flask
cost = 2
-/datum/gear/zippolighter
+/datum/gear/hands/zippolighter
name = "Zippo Lighter"
- category = SLOT_HANDS
path = /obj/item/lighter
cost = 2
-/datum/gear/cigar
+/datum/gear/hands/cigar
name = "Cigar"
- category = SLOT_HANDS
path = /obj/item/clothing/mask/cigarette/cigar
cost = 4 //smoking is bad mkay
diff --git a/modular_citadel/code/modules/client/loadout/head.dm b/modular_citadel/code/modules/client/loadout/head.dm
index a02c98a9f0..fd03e2279f 100644
--- a/modular_citadel/code/modules/client/loadout/head.dm
+++ b/modular_citadel/code/modules/client/loadout/head.dm
@@ -1,141 +1,136 @@
-/datum/gear/baseball
+/datum/gear/head
+ category = LOADOUT_CATEGORY_HEAD
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_GENERAL
+ slot = SLOT_HEAD
+
+/datum/gear/head/baseball
name = "Ballcap"
- category = SLOT_HEAD
path = /obj/item/clothing/head/soft/mime
-/datum/gear/beanie
+/datum/gear/head/beanie
name = "Beanie"
- category = SLOT_HEAD
path = /obj/item/clothing/head/beanie
-/datum/gear/beret
+/datum/gear/head/beret
name = "Black beret"
- category = SLOT_HEAD
path = /obj/item/clothing/head/beret/black
-/datum/gear/flatcap
+/datum/gear/head/flatcap
name = "Flat cap"
- category = SLOT_HEAD
path = /obj/item/clothing/head/flatcap
-/datum/gear/pirate
+/datum/gear/head/pirate
name = "Pirate hat"
- category = SLOT_HEAD
path = /obj/item/clothing/head/pirate
-/datum/gear/rice_hat
+/datum/gear/head/rice_hat
name = "Rice hat"
- category = SLOT_HEAD
path = /obj/item/clothing/head/rice_hat
-/datum/gear/ushanka
- name = "Ushanka"
- category = SLOT_HEAD
+/datum/gear/head/ushanka
path = /obj/item/clothing/head/ushanka
-/datum/gear/slime
+/datum/gear/head/slime
name = "Slime hat"
- category = SLOT_HEAD
path = /obj/item/clothing/head/collectable/slime
-/datum/gear/fedora
+/datum/gear/head/fedora
name = "Fedora"
- category = SLOT_HEAD
path = /obj/item/clothing/head/fedora
-/datum/gear/that
+/datum/gear/head/that
name = "Top Hat"
- category = SLOT_HEAD
path = /obj/item/clothing/head/that
-/datum/gear/flakhelm
+/datum/gear/head/maidband
+ name = "Maid headband"
+ path= /obj/item/clothing/head/maid
+
+/datum/gear/head/flakhelm
name = "Flak Helmet"
- category = SLOT_HEAD
path = /obj/item/clothing/head/flakhelm
cost = 2
-/datum/gear/bunnyears
+/datum/gear/head/bunnyears
name = "Bunny Ears"
- category = SLOT_HEAD
path = /obj/item/clothing/head/rabbitears
-/datum/gear/mailmanhat
+/datum/gear/head/mailmanhat
name = "Mailman's Hat"
- category = SLOT_HEAD
path = /obj/item/clothing/head/mailman
//trek fancy Hats!
-/datum/gear/trekcap
+/datum/gear/head/trekcap
name = "Federation Officer's Cap (White)"
- category = SLOT_HEAD
path = /obj/item/clothing/head/caphat/formal/fedcover
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Captain","Head of Personnel")
-/datum/gear/trekcapcap
+/datum/gear/head/trekcapcap
name = "Federation Officer's Cap (Black)"
- category = SLOT_HEAD
path = /obj/item/clothing/head/caphat/formal/fedcover/black
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Captain","Head of Personnel")
-/datum/gear/trekcapmedisci
+/datum/gear/head/trekcapmedisci
name = "Federation Officer's Cap (Blue)"
- category = SLOT_HEAD
path = /obj/item/clothing/head/caphat/formal/fedcover/medsci
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekcapeng
+/datum/gear/head/trekcapeng
name = "Federation Officer's Cap (Yellow)"
- category = SLOT_HEAD
path = /obj/item/clothing/head/caphat/formal/fedcover/eng
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
-/datum/gear/trekcapsec
+/datum/gear/head/trekcapsec
name = "Federation Officer's Cap (Red)"
- category = SLOT_HEAD
path = /obj/item/clothing/head/caphat/formal/fedcover/sec
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
// orvilike "original" kepi
-/datum/gear/orvkepicom
+/datum/gear/head/orvkepicom
name = "Federation Kepi, command"
description = "A visored cap. Intended to be used with ORV uniform."
- category = SLOT_HEAD
path = /obj/item/clothing/head/kepi/orvi/command
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Research Director", "Chief Medical Officer", "Quartermaster")
-/datum/gear/orvkepiops
+/datum/gear/head/orvkepiops
name = "Federation Kepi, ops/sec"
description = "A visored cap. Intended to be used with ORV uniform."
- category = SLOT_HEAD
path = /obj/item/clothing/head/kepi/orvi/engsec
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Engineering, Security and Cargo"
restricted_roles = list("Chief Engineer", "Atmospheric Technician", "Station Engineer", "Warden", "Detective", "Security Officer", "Head of Security", "Cargo Technician", "Shaft Miner", "Quartermaster")
-/datum/gear/orvkepimedsci
+/datum/gear/head/orvkepimedsci
name = "Federation Kepi, medsci"
description = "A visored cap. Intended to be used with ORV uniform."
- category = SLOT_HEAD
path = /obj/item/clothing/head/kepi/orvi/medsci
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Paramedic", "Geneticist", "Research Director", "Scientist", "Roboticist")
-/datum/gear/orvkepisrv
+/datum/gear/head/orvkepisrv
name = "Federation Kepi, service"
description = "A visored cap. Intended to be used with ORV uniform."
- category = SLOT_HEAD
path = /obj/item/clothing/head/kepi/orvi/service
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Service and Civilian, barring Clown, Mime and Lawyer"
restricted_roles = list("Assistant", "Bartender", "Botanist", "Cook", "Curator", "Janitor", "Chaplain")
-/datum/gear/orvkepiass
+/datum/gear/head/orvkepiass
name = "Federation Kepi, assistant"
description = "A visored cap. Intended to be used with ORV uniform."
- category = SLOT_HEAD
path = /obj/item/clothing/head/kepi/orvi
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_roles = list("Assistant")
/*Commenting out Until next Christmas or made automatic
@@ -151,35 +146,37 @@
*/
//Cowboy Stuff
-/datum/gear/cowboyhat
+/datum/gear/head/cowboyhat
name = "Cowboy Hat, Brown"
- category = SLOT_HEAD
path = /obj/item/clothing/head/cowboyhat
-/datum/gear/cowboyhat/black
+/datum/gear/head/cowboyhat/black
name = "Cowboy Hat, Black"
- category = SLOT_HEAD
path = /obj/item/clothing/head/cowboyhat/black
-/datum/gear/cowboyhat/white
+/datum/gear/head/cowboyhat/white
name = "Cowboy Hat, White"
- category = SLOT_HEAD
path = /obj/item/clothing/head/cowboyhat/white
-/datum/gear/cowboyhat/pink
+/datum/gear/head/cowboyhat/pink
name = "Cowboy Hat, Pink"
- category = SLOT_HEAD
path = /obj/item/clothing/head/cowboyhat/pink
-/datum/gear/cowboyhat/sec
+/datum/gear/head/cowboyhat/sec
name = "Cowboy Hat, Security"
- category = SLOT_HEAD
path = /obj/item/clothing/head/cowboyhat/sec
+ subcategory = LOADOUT_SUBCATEGORY_HEAD_JOBS
restricted_desc = "Security"
restricted_roles = list("Warden","Detective","Security Officer","Head of Security")
-// Misc
-/datum/gear/wkepi
+/datum/gear/head/wkepi
name = "white kepi"
- category = SLOT_HEAD
path = /obj/item/clothing/head/kepi
+
+/datum/gear/head/widered
+ name = "Wide red hat"
+ path = /obj/item/clothing/head/widered
+
+/datum/gear/head/kabuto
+ name = "Kabuto helmet"
+ path = /obj/item/clothing/head/kabuto
diff --git a/modular_citadel/code/modules/client/loadout/mask.dm b/modular_citadel/code/modules/client/loadout/mask.dm
index eeba06cad4..0d7e32552e 100644
--- a/modular_citadel/code/modules/client/loadout/mask.dm
+++ b/modular_citadel/code/modules/client/loadout/mask.dm
@@ -1,16 +1,16 @@
-/datum/gear/balaclava
+/datum/gear/mask
+ category = LOADOUT_CATEGORY_MASK
+ slot = SLOT_WEAR_MASK
+
+/datum/gear/mask/balaclava
name = "Balaclava"
- category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/balaclava
-/datum/gear/moustache
+/datum/gear/mask/moustache
name = "Fake moustache"
- category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/fakemoustache
-/datum/gear/joy
+/datum/gear/mask/joy
name = "Joy mask"
- category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/joy
cost = 3
-
diff --git a/modular_citadel/code/modules/client/loadout/neck.dm b/modular_citadel/code/modules/client/loadout/neck.dm
index 320a83b87d..19311f703a 100644
--- a/modular_citadel/code/modules/client/loadout/neck.dm
+++ b/modular_citadel/code/modules/client/loadout/neck.dm
@@ -1,94 +1,88 @@
-/datum/gear/bluetie
+/datum/gear/neck
+ category = LOADOUT_CATEGORY_NECK
+ subcategory = LOADOUT_SUBCATEGORY_NECK_GENERAL
+ slot = SLOT_NECK
+
+/datum/gear/neck/bluetie
name = "Blue tie"
- category = SLOT_NECK
+ subcategory = LOADOUT_SUBCATEGORY_NECK_TIE
path = /obj/item/clothing/neck/tie/blue
-/datum/gear/redtie
+/datum/gear/neck/redtie
name = "Red tie"
- category = SLOT_NECK
+ subcategory = LOADOUT_SUBCATEGORY_NECK_TIE
path = /obj/item/clothing/neck/tie/red
-/datum/gear/blacktie
+/datum/gear/neck/blacktie
name = "Black tie"
- category = SLOT_NECK
+ subcategory = LOADOUT_SUBCATEGORY_NECK_TIE
path = /obj/item/clothing/neck/tie/black
-/datum/gear/collar
+/datum/gear/neck/collar
name = "Collar"
- category = SLOT_NECK
path = /obj/item/clothing/neck/petcollar
-/datum/gear/leathercollar
+/datum/gear/neck/leathercollar
name = "Leather collar"
- category = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/leather
-/datum/gear/choker
+/datum/gear/neck/choker
name = "Choker"
- category = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/choker
-/datum/gear/scarf
+/datum/gear/neck/scarf
name = "White scarf"
- category = SLOT_NECK
+ subcategory = LOADOUT_SUBCATEGORY_NECK_SCARVES
path = /obj/item/clothing/neck/scarf
-/datum/gear/blackscarf
+/datum/gear/neck/scarf/black
name = "Black scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/black
-/datum/gear/redscarf
+/datum/gear/neck/scarf/red
name = "Red scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/red
-/datum/gear/greenscarf
+/datum/gear/neck/scarf/green
name = "Green scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/green
-/datum/gear/darkbluescarf
+/datum/gear/neck/scarf/darkblue
name = "Dark blue scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/darkblue
-/datum/gear/purplescarf
+/datum/gear/neck/scarf/purple
name = "Purple scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/purple
-/datum/gear/yellowscarf
+/datum/gear/neck/scarf/yellow
name = "Yellow scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/yellow
-/datum/gear/orangescarf
+/datum/gear/neck/scarf/orange
name = "Orange scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/orange
-/datum/gear/cyanscarf
+/datum/gear/neck/scarf/cyan
name = "Cyan scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/cyan
-/datum/gear/stripedredscarf
+/datum/gear/neck/scarf/stripedred
name = "Striped red scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/stripedredscarf
-/datum/gear/stripedbluescarf
+/datum/gear/neck/scarf/stripedblue
name = "Striped blue scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/stripedbluescarf
-/datum/gear/stripedgreenscarf
+/datum/gear/neck/scarf/stripedgreen
name = "Striped green scarf"
- category = SLOT_NECK
path = /obj/item/clothing/neck/stripedgreenscarf
-/datum/gear/headphones
+/datum/gear/neck/headphones
name = "Headphones"
- category = SLOT_NECK
path = /obj/item/clothing/ears/headphones
+
+/datum/gear/neck/polycloak
+ name = "Polychromatic Cloak"
+ path = /obj/item/clothing/neck/cloak/polychromic
diff --git a/modular_citadel/code/modules/client/loadout/shoes.dm b/modular_citadel/code/modules/client/loadout/shoes.dm
index 3531e69cfd..76d7305971 100644
--- a/modular_citadel/code/modules/client/loadout/shoes.dm
+++ b/modular_citadel/code/modules/client/loadout/shoes.dm
@@ -1,84 +1,71 @@
-/datum/gear/laceup
+/datum/gear/shoes
+ category = LOADOUT_CATEGORY_SHOES
+ slot = SLOT_SHOES
+
+/datum/gear/shoes/laceup
name = "Laceup shoes"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/laceup
-/datum/gear/workboots
+/datum/gear/shoes/workboots
name = "Work boots"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/workboots
-/datum/gear/jackboots
+/datum/gear/shoes/jackboots
name = "Jackboots"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/jackboots
-/datum/gear/winterboots
+/datum/gear/shoes/winterboots
name = "Winter boots"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/winterboots
-/datum/gear/sandals
+/datum/gear/shoes/sandals
name = "Sandals"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/sandal
-/datum/gear/blackshoes
+/datum/gear/shoes/blackshoes
name = "Black shoes"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/black
-/datum/gear/brownshoes
+/datum/gear/shoes/brownshoes
name = "Brown shoes"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/brown
-/datum/gear/whiteshoes
+/datum/gear/shoes/whiteshoes
name = "White shoes"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/white
-/datum/gear/gildedcuffs
+/datum/gear/shoes/gildedcuffs
name = "Gilded leg wraps"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps
-/datum/gear/silvercuffs
+/datum/gear/shoes/silvercuffs
name = "Silver leg wraps"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps/silver
-/datum/gear/redcuffs
+/datum/gear/shoes/redcuffs
name = "Red leg wraps"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps/red
-/datum/gear/bluecuffs
+/datum/gear/shoes/bluecuffs
name = "Blue leg wraps"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps/blue
-/datum/gear/christmasbootsr
+/datum/gear/shoes/christmasbootsr
name = "Red Christmas Boots"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/winterboots/christmasbootsr
-/datum/gear/christmasbootsg
+/datum/gear/shoes/christmasbootsg
name = "Green Christmas Boots"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/winterboots/christmasbootsg
-/datum/gear/santaboots
+/datum/gear/shoes/santaboots
name = "Santa Boots"
- category = SLOT_SHOES
path= /obj/item/clothing/shoes/winterboots/santaboots
-/datum/gear/cowboyboots
+/datum/gear/shoes/cowboyboots
name = "Cowboy Boots, Brown"
- category = SLOT_SHOES
path = /obj/item/clothing/shoes/cowboyboots
-/datum/gear/cowboyboots/black
+/datum/gear/shoes/cowboyboots/black
name = "Cowboy Boots, Black"
- category = SLOT_SHOES
- path = /obj/item/clothing/shoes/cowboyboots/black
\ No newline at end of file
+ path = /obj/item/clothing/shoes/cowboyboots/black
diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm
index fecf2a4dce..d0be26a8a4 100644
--- a/modular_citadel/code/modules/client/loadout/suit.dm
+++ b/modular_citadel/code/modules/client/loadout/suit.dm
@@ -1,235 +1,250 @@
-/datum/gear/poncho
+/datum/gear/suit
+ category = LOADOUT_CATEGORY_SUIT
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_GENERAL
+ slot = SLOT_WEAR_SUIT
+
+/datum/gear/suit/poncho
name = "Poncho"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/poncho
-/datum/gear/ponchogreen
+/datum/gear/suit/ponchogreen
name = "Green poncho"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/poncho/green
-/datum/gear/ponchored
+/datum/gear/suit/ponchored
name = "Red poncho"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/poncho/red
-/datum/gear/redhood
+/datum/gear/suit/redhood
name = "Red cloak"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/cloak/david
cost = 3
-/datum/gear/jacketbomber
+/datum/gear/suit/jacketbomber
name = "Bomber jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/jacketleather
+/datum/gear/suit/jacketflannelblack // all of these are reskins of bomber jackets but with the vibe to make you look like a true lumberjack
+ name = "Black flannel jacket"
+ path = /obj/item/clothing/suit/jacket/flannel
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
+
+/datum/gear/suit/jacketflannelred
+ name = "Red flannel jacket"
+ path = /obj/item/clothing/suit/jacket/flannel/red
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
+
+/datum/gear/suit/jacketflannelaqua
+ name = "Aqua flannel jacket"
+ path = /obj/item/clothing/suit/jacket/flannel/aqua
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
+
+/datum/gear/suit/jacketflannelbrown
+ name = "Brown flannel jacket"
+ path = /obj/item/clothing/suit/jacket/flannel/brown
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
+
+/datum/gear/suit/jacketleather
name = "Leather jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/leather
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/overcoatleather
+/datum/gear/suit/overcoatleather
name = "Leather overcoat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/leather/overcoat
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/jacketpuffer
+/datum/gear/suit/jacketpuffer
name = "Puffer jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/puffer
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/vestpuffer
+/datum/gear/suit/vestpuffer
name = "Puffer vest"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/puffer/vest
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/jacketlettermanbrown
+/datum/gear/suit/jacketlettermanbrown
name = "Brown letterman jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/letterman
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/jacketlettermanred
+/datum/gear/suit/jacketlettermanred
name = "Red letterman jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/letterman_red
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/jacketlettermanNT
+/datum/gear/suit/jacketlettermanNT
name = "Nanotrasen letterman jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/letterman_nanotrasen
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/coat
+/datum/gear/suit/coat
name = "Winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS
-/datum/gear/coat/aformal
+/datum/gear/suit/coat/aformal
name = "Assistant's formal winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/aformal
-/datum/gear/coat/runed
+/datum/gear/suit/coat/runed
name = "Runed winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/narsie/fake
-/datum/gear/coat/brass
+/datum/gear/suit/coat/brass
name = "Brass winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/ratvar/fake
-/datum/gear/coat/polycoat
+/datum/gear/suit/coat/polycoat
name = "Polychromic winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/polychromic
cost = 4 //too many people with neon green coats is hard on the eyes
-/datum/gear/coat/med
+/datum/gear/suit/coat/med
name = "Medical winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/medical
restricted_roles = list("Chief Medical Officer", "Medical Doctor") // Reserve it to Medical Doctors and their boss, the Chief Medical Officer
-/datum/gear/coat/paramedic
+/datum/gear/suit/coat/paramedic
name = "Paramedic winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/paramedic
restricted_roles = list("Chief Medical Officer", "Paramedic") // Reserve it to Paramedics and their boss, the Chief Medical Officer
-/datum/gear/coat/robotics
+/datum/gear/suit/coat/robotics
name = "Robotics winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/robotics
restricted_roles = list("Research Director", "Roboticist")
-/datum/gear/coat/sci
+/datum/gear/suit/coat/sci
name = "Science winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/science
restricted_roles = list("Research Director", "Scientist", "Roboticist") // Reserve it to the Science Departement
-/datum/gear/coat/eng
+/datum/gear/suit/coat/eng
name = "Engineering winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/engineering
restricted_roles = list("Chief Engineer", "Station Engineer") // Reserve it to Station Engineers and their boss, the Chief Engineer
-/datum/gear/coat/eng/atmos
+/datum/gear/suit/coat/eng/atmos
name = "Atmospherics winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/engineering/atmos
restricted_roles = list("Chief Engineer", "Atmospheric Technician") // Reserve it to Atmos Techs and their boss, the Chief Engineer
-/datum/gear/coat/hydro
+/datum/gear/suit/coat/hydro
name = "Hydroponics winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/hydro
restricted_roles = list("Head of Personnel", "Botanist") // Reserve it to Botanists and their boss, the Head of Personnel
-/datum/gear/coat/cargo
+/datum/gear/suit/coat/bar
+ name = "Bar winter coat"
+ path = /obj/item/clothing/suit/hooded/wintercoat/bar
+ restricted_roles = list("Bartender") // Reserve it to Bartenders and not the Head of Personnel because he doesnt deserve to look as fancy as them
+
+/datum/gear/suit/coat/cargo
name = "Cargo winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/cargo
restricted_roles = list("Quartermaster", "Cargo Technician") // Reserve it to Cargo Techs and their boss, the Quartermaster
-/datum/gear/coat/miner
+/datum/gear/suit/coat/miner
name = "Mining winter coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/miner
restricted_roles = list("Quartermaster", "Shaft Miner") // Reserve it to Miners and their boss, the Quartermaster
-/datum/gear/militaryjacket
+/datum/gear/suit/militaryjacket
name = "Military Jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/miljacket
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
-/datum/gear/ianshirt
+/datum/gear/suit/ianshirt
name = "Ian Shirt"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/ianshirt
-/datum/gear/flakjack
+/datum/gear/suit/flakjack
name = "Flak Jacket"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/flakjack
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
cost = 2
-/datum/gear/trekds9_coat
+/datum/gear/suit/trekds9_coat
name = "DS9 Overcoat (use uniform)"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/trek/ds9
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "All, barring Service and Civilian"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster",
"Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Scientist", "Roboticist",
"Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer",
"Cargo Technician", "Shaft Miner") //everyone who actually deserves a job.
//Federation jackets from movies
-/datum/gear/trekcmdcap
+/datum/gear/suit/trekcmdcap
name = "Fed (movie) uniform, Black"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat/capt
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_roles = list("Captain","Head of Personnel")
-/datum/gear/trekcmdmov
+/datum/gear/suit/trekcmdmov
name = "Fed (movie) uniform, Red"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "Heads of Staff and Security"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster","Warden","Detective","Security Officer")
-/datum/gear/trekmedscimov
+/datum/gear/suit/trekmedscimov
name = "Fed (movie) uniform, Blue"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat/medsci
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengmov
+/datum/gear/suit/trekengmov
name = "Fed (movie) uniform, Yellow"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat/eng
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "Engineering and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Cargo Technician", "Shaft Miner", "Quartermaster")
-/datum/gear/trekcmdcapmod
+/datum/gear/suit/trekcmdcapmod
name = "Fed (Modern) uniform, White"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat
restricted_roles = list("Captain","Head of Personnel")
-/datum/gear/trekcmdmod
+/datum/gear/suit/trekcmdmod
name = "Fed (Modern) uniform, Red"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/sec
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "Heads of Staff and Security"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster","Warden","Detective","Security Officer")
-/datum/gear/trekmedscimod
+/datum/gear/suit/trekmedscimod
name = "Fed (Modern) uniform, Blue"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/medsci
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengmod
+/datum/gear/suit/trekengmod
name = "Fed (Modern) uniform, Yellow"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/eng
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_JOBS
restricted_desc = "Engineering and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Cargo Technician", "Shaft Miner", "Quartermaster")
-/datum/gear/christmascoatr
+/datum/gear/suit/christmascoatr
name = "Red Christmas Coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatr
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS
-/datum/gear/christmascoatg
+/datum/gear/suit/christmascoatg
name = "Green Christmas Coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatg
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS
-/datum/gear/christmascoatrg
+/datum/gear/suit/christmascoatrg
name = "Red and Green Christmas Coat"
- category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatrg
+ subcategory = LOADOUT_SUBCATEGORY_SUIT_COATS
+
+/datum/gear/suit/samurai
+ name = "Samurai outfit"
+ path = /obj/item/clothing/suit/samurai
diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm
index e667626968..5ce73d1cfd 100644
--- a/modular_citadel/code/modules/client/loadout/uniform.dm
+++ b/modular_citadel/code/modules/client/loadout/uniform.dm
@@ -1,562 +1,542 @@
-/datum/gear/suitblack
- name = "Black suit"
- category = SLOT_W_UNIFORM
- path = /obj/item/clothing/under/suit/black
+/datum/gear/uniform
+ category = LOADOUT_CATEGORY_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_GENERAL
+ slot = SLOT_W_UNIFORM
-/datum/gear/suitgreen
+/datum/gear/uniform/suit
+ name = "Black suit"
+ path = /obj/item/clothing/under/suit/black
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SUITS
+
+/datum/gear/uniform/suit/green
name = "Green suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/green
-/datum/gear/suitred
+/datum/gear/uniform/suit/red
name = "Red suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/red
-/datum/gear/suitcharcoal
+/datum/gear/uniform/suit/charcoal
name = "Charcoal suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/charcoal
-/datum/gear/suitnavy
+/datum/gear/uniform/suit/navy
name = "Navy suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/navy
-/datum/gear/suitburgundy
+/datum/gear/uniform/suit/burgundy
name = "Burgundy suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/burgundy
-/datum/gear/suittan
+/datum/gear/uniform/suit/tan
name = "Tan suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/tan
-/datum/gear/suitwhite
+/datum/gear/uniform/suit/white
name = "White suit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/suit/white
-/datum/gear/assistantformal
+/datum/gear/uniform/assistantformal
name = "Assistant's formal uniform"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/assistantformal
-/datum/gear/maidcostume
+/datum/gear/uniform/maidcostume
name = "Maid costume"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/maid
-/datum/gear/mailmanuniform
+/datum/gear/uniform/mailmanuniform
name = "Mailman's jumpsuit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/mailman
-/datum/gear/skirtblack
+/datum/gear/uniform/skirt
name = "Black skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS
-/datum/gear/skirtblue
+/datum/gear/uniform/skirt/blue
name = "Blue skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/blue
-/datum/gear/skirtred
+/datum/gear/uniform/skirt/red
name = "Red skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/red
-/datum/gear/skirtpurple
+/datum/gear/uniform/skirt/purple
name = "Purple skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/purple
-/datum/gear/skirtplaid
+/datum/gear/uniform/skirt/plaid
name = "Plaid skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/plaid
-/datum/gear/schoolgirlblue
+/datum/gear/uniform/schoolgirlblue
name = "Blue Schoolgirl Uniform"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/schoolgirl
-/datum/gear/schoolgirlred
+/datum/gear/uniform/schoolgirlred
name = "Red Schoolgirl Uniform"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/schoolgirl/red
-/datum/gear/schoolgirlgreen
+/datum/gear/uniform/schoolgirlgreen
name = "Green Schoolgirl Uniform"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/schoolgirl/green
-/datum/gear/schoolgirlorange
+/datum/gear/uniform/schoolgirlorange
name = "Orange Schoolgirl Uniform"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/schoolgirl/orange
-/datum/gear/stripeddress
+/datum/gear/uniform/dress
name = "Striped Dress"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/striped
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
-/datum/gear/sundresswhite
+/datum/gear/uniform/dress/sun/white
name = "White Sundress"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/sundress/white
-/datum/gear/sundress
+/datum/gear/uniform/dress/sun
name = "Sundress"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/sundress
-/datum/gear/greendress
+/datum/gear/uniform/dress/green
name = "Green Dress"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/green
-/datum/gear/pinkdress
+/datum/gear/uniform/dress/pink
name = "Pink Dress"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/pink
-/datum/gear/flowerdress
+
+/datum/gear/uniform/dress/orange
name = "Flower Dress"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/flower
-/datum/gear/sweptskirt
+/datum/gear/uniform/skirt/swept
name = "Swept skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/swept
-/datum/gear/croptop
+/datum/gear/uniform/croptop
name = "Croptop"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/croptop
-/datum/gear/yoga
+/datum/gear/uniform/pants
name = "Yoga Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/yoga
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_PANTS
-/datum/gear/kilt
+/datum/gear/uniform/kilt
name = "Kilt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/kilt
-/datum/gear/camoshorts
+/datum/gear/uniform/pants/camo
name = "Camo Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/camo
-/datum/gear/athleticshorts
+/datum/gear/uniform/shorts
name = "Athletic Shorts"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/shorts/red
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SHORTS
-/datum/gear/bjeans
+/datum/gear/uniform/pants/bjeans
name = "Black Jeans"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/blackjeans
-/datum/gear/cjeans
+/datum/gear/uniform/pants/cjeans
name = "Classic Jeans"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/classicjeans
-/datum/gear/khaki
+/datum/gear/uniform/pants/khaki
name = "Khaki Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/khaki
-/datum/gear/wpants
+/datum/gear/uniform/pants/white
name = "White Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/white
-/datum/gear/rpants
+/datum/gear/uniform/pants/red
name = "Red Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/red
-/datum/gear/tpants
+/datum/gear/uniform/pants/tan
name = "Tan Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/tan
-/datum/gear/trpants
+/datum/gear/uniform/pants/track
name = "Track Pants"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/track
-/datum/gear/rippedjeans
+/datum/gear/uniform/pants/ripped
name = "Ripped Jeans"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/jeanripped
-/datum/gear/jeanshort
+/datum/gear/uniform/shorts/jean
name = "Jean Shorts"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/jeanshort
-/datum/gear/denimskirt
+/datum/gear/uniform/skirt/denim
name = "Denim Skirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/denimskirt
-/datum/gear/yoga
- name = "Yoga Pants"
- category = SLOT_W_UNIFORM
- path = /obj/item/clothing/under/pants/yoga
-
// Pantsless Sweaters
-/datum/gear/turtleneck
+/datum/gear/uniform/turtleneck
name = "Tactitool Turtleneck"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/syndicate/cosmetic
-/datum/gear/creamsweater
+/datum/gear/uniform/sweater
name = "Cream Commando Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS
-/datum/gear/blacksweater
+/datum/gear/uniform/sweater/black
name = "Black Commando Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater/black
-/datum/gear/purpsweater
+/datum/gear/uniform/sweater/purple
name = "Purple Commando Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater/purple
-/datum/gear/greensweater
+/datum/gear/uniform/sweater/green
name = "Green Commando Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater/green
-/datum/gear/redsweater
+/datum/gear/uniform/sweater/red
name = "Red Commando Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater/red
-/datum/gear/bluesweater
+/datum/gear/uniform/sweater/blue
name = "Navy Commando Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/sweater/blue
-/datum/gear/keyholesweater
+/datum/gear/uniform/sweater/keyhole
name = "Keyhole Sweater"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/keyholesweater
-/datum/gear/polyjump
+/datum/gear/uniform/polyjump
name = "Polychromic Jumpsuit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/polyjumpsuit
cost = 2
-
-/datum/gear/polyskirt
+
+/datum/gear/uniform/skirt/poly
name = "Polychromic Jumpskirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/polychromic
cost = 2
-/datum/gear/polysuit
+/datum/gear/uniform/suit/poly
name = "Polychromic Button-up Shirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/poly_shirt
cost = 3
-
-/datum/gear/polypleated
+
+/datum/gear/uniform/skirt/poly/pleated
name = "Polychromic Pleated Sweaterskirt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/dress/skirt/polychromic/pleated
cost = 3
-/datum/gear/polykilt
+/datum/gear/uniform/polykilt
name = "Polychromic Kilt"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/kilt/polychromic
cost = 3
-/datum/gear/polyshorts
+/datum/gear/uniform/shorts/poly
name = "Polychromic Shorts"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/polyshorts
cost = 3
-/datum/gear/polyshortpants
+/datum/gear/uniform/shorts/poly/athletic
name = "Polychromic Athletic Shorts"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/shorts/polychromic
cost = 2
// Trekie things
//TOS
-/datum/gear/trekcmdtos
+/datum/gear/uniform/trekcmdtos
name = "TOS uniform, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster")
-/datum/gear/trekmedscitos
+/datum/gear/uniform/trekmedscitos
name = "TOS uniform, med/sci"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/medsci
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengtos
+/datum/gear/uniform/trekengtos
name = "TOS uniform, ops/sec"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/engsec
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
//TNG
-/datum/gear/trekcmdtng
+/datum/gear/uniform/trekcmdtng
name = "TNG uniform, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/next
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster")
-/datum/gear/trekmedscitng
+/datum/gear/uniform/trekmedscitng
name = "TNG uniform, med/sci"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/medsci/next
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengtng
+/datum/gear/uniform/trekengtng
name = "TNG uniform, ops/sec"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/engsec/next
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
//VOY
-/datum/gear/trekcmdvoy
+/datum/gear/uniform/trekcmdvoy
name = "VOY uniform, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/voy
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster")
-/datum/gear/trekmedscivoy
+/datum/gear/uniform/trekmedscivoy
name = "VOY uniform, med/sci"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/medsci/voy
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengvoy
+/datum/gear/uniform/trekengvoy
name = "VOY uniform, ops/sec"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/engsec/voy
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
//DS9
-/datum/gear/trekcmdds9
+/datum/gear/uniform/trekcmdds9
name = "DS9 uniform, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/ds9
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster")
-/datum/gear/trekmedscids9
+/datum/gear/uniform/trekmedscids9
name = "DS9 uniform, med/sci"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/medsci/ds9
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengds9
+/datum/gear/uniform/trekengds9
name = "DS9 uniform, ops/sec"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/engsec/ds9
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
//ENT
-/datum/gear/trekcmdent
+/datum/gear/uniform/trekcmdent
name = "ENT uniform, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/ent
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster")
-/datum/gear/trekmedscient
+/datum/gear/uniform/trekmedscient
name = "ENT uniform, med/sci"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/medsci/ent
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Research Director","Scientist", "Roboticist")
-/datum/gear/trekengent
+/datum/gear/uniform/trekengent
name = "ENT uniform, ops/sec"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/engsec/ent
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
//TheMotionPicture
-/datum/gear/trekfedutil
+/datum/gear/uniform/trekfedutil
name = "TMP uniform"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/fedutil
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "All, barring Service and Civilian"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster",
"Medical Doctor","Chemist","Virologist","Paramedic","Geneticist","Scientist", "Roboticist",
"Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer",
"Cargo Technician", "Shaft Miner")
-/datum/gear/trekfedtrainee
+/datum/gear/uniform/trekfedtrainee
name = "TMP uniform, trainee"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/fedutil/trainee
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Assistant", "Janitor", "Cargo Technician")
-/datum/gear/trekfedservice
+/datum/gear/uniform/trekfedservice
name = "TMP uniform, service"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/fedutil/service
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Service and Civilian, barring Clown, Mime and Lawyer"
restricted_roles = list("Assistant", "Bartender", "Botanist", "Cook", "Curator", "Janitor", "Chaplain")
//Orvilike
-/datum/gear/orvcmd
+/datum/gear/uniform/orvcmd
name = "ORV uniform, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/orv
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Heads of Staff"
restricted_roles = list("Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Research Director", "Chief Medical Officer", "Quartermaster")
-/datum/gear/orvcmd_capt
+/datum/gear/uniform/orvcmd_capt
name = "ORV uniform, capt"
- category = SLOT_W_UNIFORM
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
path = /obj/item/clothing/under/trek/command/orv/captain
restricted_roles = list("Captain")
-/datum/gear/orvmedsci
+/datum/gear/uniform/orvmedsci
name = "ORV uniform, med/sci"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/medsci/orv
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Paramedic", "Geneticist", "Research Director", "Scientist", "Roboticist")
-/datum/gear/orvcmd_medsci
+/datum/gear/uniform/orvcmd_medsci
name = "ORV uniform, med/sci, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/orv/medsci
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Chief Medical Officer", "Research Director")
-/datum/gear/orvops
+/datum/gear/uniform/orvops
name = "ORV uniform, ops/sec"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/engsec/orv
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_desc = "Engineering, Security and Cargo"
restricted_roles = list("Chief Engineer", "Atmospheric Technician", "Station Engineer", "Warden", "Detective", "Security Officer", "Head of Security", "Cargo Technician", "Shaft Miner", "Quartermaster")
-/datum/gear/orvcmd_ops
+/datum/gear/uniform/orvcmd_ops
name = "ORV uniform, ops/sec, cmd"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/command/orv/engsec
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Chief Engineer", "Head of Security")
-/datum/gear/orvass
+/datum/gear/uniform/orvass
name = "ORV uniform, assistant"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/orv
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Assistant")
-/datum/gear/orvsrv
+/datum/gear/uniform/orvsrv
name = "ORV uniform, service"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trek/orv/service
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_JOBS
restricted_roles = list("Assistant", "Bartender", "Botanist", "Cook", "Curator", "Janitor", "Chaplain")
restricted_desc = "Service and Civilian, barring Clown, Mime and Lawyer"
//Memes
-/datum/gear/gear_harnesses
+/datum/gear/uniform/gear_harnesses
name = "Gear Harness"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/gear_harness
//Christmas
/*Commenting out Until next Christmas or made automatic
-/datum/gear/christmasmaler
+/datum/gear/uniform/christmasmaler
name = "Red Masculine Christmas Suit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/christmas
-/datum/gear/christmasmaleg
+/datum/gear/uniform/christmasmaleg
name = "Green Masculine Christmas Suit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/christmas/green
-/datum/gear/christmasfemaler
+/datum/gear/uniform/christmasfemaler
name = "Red Feminine Christmas Suit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/christmas/croptop
-/datum/gear/christmasfemaleg
+/datum/gear/uniform/christmasfemaleg
name = "Green Feminine Christmas Suit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/christmas/croptop/green
-/datum/gear/pinkstripper
+/datum/gear/uniform/pinkstripper
name = "Pink stripper outfit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/stripper
cost = 3
*/
-/datum/gear/greenstripper
+/datum/gear/uniform/greenstripper
name = "Green stripper outfit"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/misc/stripper/green
cost = 3
-/datum/gear/qipao
+/datum/gear/uniform/qipao
name = "Qipao, Black"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/qipao
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
cost = 3
-/datum/gear/qipao/white
+/datum/gear/uniform/qipao/white
name = "Qipao, White"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/qipao/white
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
cost = 3
-/datum/gear/qipao/red
+/datum/gear/uniform/qipao/red
name = "Qipao, Red"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/qipao/red
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
cost = 3
-/datum/gear/cheongsam
+/datum/gear/uniform/cheongsam
name = "Cheongsam, Black"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/cheongsam
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
cost = 3
-/datum/gear/cheongsam/white
+/datum/gear/uniform/cheongsam/white
name = "Cheongsam, White"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/cheongsam/white
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
cost = 3
-/datum/gear/cheongsam/red
+/datum/gear/uniform/cheongsam/red
name = "Cheongsam, Red"
- category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/costume/cheongsam/red
+ subcategory = LOADOUT_SUBCATEGORY_UNIFORM_DRESSES
cost = 3
+
+/datum/gear/uniform/dress/black
+ name = "Black dress"
+ path = /obj/item/clothing/under/misc/black_dress
+
+/datum/gear/uniform/skirt/pinktutu
+ name = "Pink tutu"
+ path = /obj/item/clothing/under/misc/pinktutu
+
+/datum/gear/uniform/bathrobe
+ name = "Bathrobe"
+ path = /obj/item/clothing/under/misc/bathrobe
+
+/datum/gear/uniform/kimono
+ name = "Kimono"
+ path = /obj/item/clothing/under/costume/kimono
+
+/datum/gear/uniform/kimono/black
+ name = "Black kimono"
+ path = /obj/item/clothing/under/costume/kimono/black
+
+/datum/gear/uniform/kimono/kamishimo
+ name = "Kamishimo"
+ path = /obj/item/clothing/under/costume/kimono/kamishimo
+
+/datum/gear/uniform/kimono/fancy
+ name = "Fancy kimono"
+ path = /obj/item/clothing/under/costume/kimono/fancy
+
+/datum/gear/uniform/kimono/sakura
+ name = "Sakura kimono"
+ path = /obj/item/clothing/under/costume/kimono/sakura
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index c747c4cf32..bbd71d22e3 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -7,12 +7,12 @@
features["ipc_antenna"] = sanitize_inlist(features["ipc_antenna"], GLOB.ipc_antennas_list)
//Citadel
features["flavor_text"] = sanitize_text(features["flavor_text"], initial(features["flavor_text"]))
- if(!features["mcolor2"] || features["mcolor"] == "#000")
+ if(!features["mcolor2"] || features["mcolor"] == "#000000")
features["mcolor2"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
- if(!features["mcolor3"] || features["mcolor"] == "#000")
+ if(!features["mcolor3"] || features["mcolor"] == "#000000")
features["mcolor3"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
- features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0)
- features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0)
+ features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 6, FALSE)
+ features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 6, FALSE)
/datum/preferences/proc/cit_character_pref_save(savefile/S)
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
index 8ef302e904..f3059a480a 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
@@ -112,7 +112,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
M.visible_message("[M] suddenly shudders, and splits into two identical twins!")
SM.copy_languages(M, LANGUAGE_MIND)
playerClone = TRUE
- M.next_move_modifier = 1
+ M.action_cooldown_mod = 1
M.adjust_nutrition(-500)
//Damage the clone
@@ -154,7 +154,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
M.adjust_nutrition(M.nutrition/5)
if(50)
to_chat(M, "The synthetic cells begin to merge with your body, it feels like your body is made of a viscous water, making your movements difficult.")
- M.next_move_modifier += 4//If this makes you fast then please fix it, it should make you slow!!
+ M.action_cooldown_mod += 4//If this makes you fast then please fix it, it should make you slow!!
//candidates = pollGhostCandidates("Do you want to play as a clone of [M.name] and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 300) // see poll_ignore.dm, should allow admins to ban greifers or bullies
if(51 to 79)
M.adjust_nutrition(M.nutrition/2)
@@ -164,7 +164,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
M.set_nutrition(20000) //https://www.youtube.com/watch?v=Bj_YLenOlZI
if(86)//Upon splitting, you get really hungry and are capable again. Deletes the chem after you're done.
M.set_nutrition(15)//YOU BEST BE EATTING AFTER THIS YOU CUTIE
- M.next_move_modifier -= 4
+ M.action_cooldown_mod -= 4
to_chat(M, "Your body splits away from the cell clone of yourself, leaving you with a drained and hollow feeling inside.")
//clone
@@ -195,14 +195,14 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
if (playerClone == TRUE)//If the player made a clone with it, then thats all they get.
playerClone = FALSE
return
- if (M.next_move_modifier == 4 && !M.has_status_effect(/datum/status_effect/chem/SGDF))//checks if they're ingested over 20u of the stuff, but fell short of the required 30u to make a clone.
+ if (M.action_cooldown_mod == 4 && !M.has_status_effect(/datum/status_effect/chem/SGDF))//checks if they're ingested over 20u of the stuff, but fell short of the required 30u to make a clone.
to_chat(M, "You feel the cells begin to merge with your body, unable to reach nucleation, they instead merge with your body, healing any wounds.")
M.adjustCloneLoss(-10, 0) //I don't want to make Rezadone obsolete.
M.adjustBruteLoss(-25, 0)// Note that this takes a long time to apply and makes you fat and useless when it's in you, I don't think this small burst of healing will be useful considering how long it takes to get there.
M.adjustFireLoss(-25, 0)
M.blood_volume += 250
M.heal_bodypart_damage(1,1)
- M.next_move_modifier = 1
+ M.action_cooldown_mod = 1
if (M.nutrition < 1500)
M.adjust_nutrition(250)
else if (unitCheck == TRUE && !M.has_status_effect(/datum/status_effect/chem/SGDF))// If they're ingested a little bit (10u minimum), then give them a little healing.
@@ -211,7 +211,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
M.adjustBruteLoss(-10, 0)
M.adjustFireLoss(-10, 0)
M.blood_volume += 100
- M.next_move_modifier = 1
+ M.action_cooldown_mod = 1
if (M.nutrition < 1500)
M.adjust_nutrition(500)
@@ -325,7 +325,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
M.adjust_nutrition(M.nutrition/5)
if(50)
to_chat(M, "The synethic cells begin to merge with your body, it feels like your body is made of a viscous water, making your movements difficult.")
- M.next_move_modifier = 4//If this makes you fast then please fix it, it should make you slow!!
+ M.action_cooldown_mod = 4//If this makes you fast then please fix it, it should make you slow!!
if(51 to 73)
M.adjust_nutrition(M.nutrition/2)
if(74)
@@ -339,7 +339,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
if (!M.reagents.has_reagent(/datum/reagent/medicine/pen_acid))//Counterplay is pent.)
message_admins("(non-infectious) SDZF: Zombie spawned at [M] [COORD(M)]!")
M.set_nutrition(startHunger - 500) //YOU BEST BE RUNNING AWAY AFTER THIS YOU BADDIE
- M.next_move_modifier = 1
+ M.action_cooldown_mod = 1
to_chat(M, "Your body splits away from the cell clone of yourself, your attempted clone birthing itself violently from you as it begins to shamble around, a terrifying abomination of science.")
M.visible_message("[M] suddenly shudders, and splits into a funky smelling copy of themselves!")
M.emote("scream")
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
index a24a5beaad..39ba69bd61 100644
--- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -178,7 +178,7 @@
name = "Sucubus milk"
id = /datum/reagent/fermi/breast_enlarger
results = list(/datum/reagent/fermi/breast_enlarger = 8)
- required_reagents = list(/datum/reagent/medicine/salglu_solution = 1, /datum/reagent/consumable/milk = 1, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/silicon = 3, /datum/reagent/drug/aphrodisiac = 3)
+ required_reagents = list(/datum/reagent/medicine/salglu_solution = 2, /datum/reagent/consumable/milk = 1, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/silicon = 5)
mix_message = "the reaction gives off a mist of milk."
//FermiChem vars:
OptimalTempMin = 200
@@ -218,7 +218,7 @@
name = "Incubus draft"
id = /datum/reagent/fermi/penis_enlarger
results = list(/datum/reagent/fermi/penis_enlarger = 8)
- required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/carbon = 2, /datum/reagent/drug/aphrodisiac = 2, /datum/reagent/medicine/salglu_solution = 1)
+ required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/synthflesh = 2, /datum/reagent/carbon = 5, /datum/reagent/medicine/salglu_solution = 2)
mix_message = "the reaction gives off a spicy mist."
//FermiChem vars:
OptimalTempMin = 200
@@ -384,7 +384,7 @@
name = "Furranium"
id = /datum/reagent/fermi/furranium
results = list(/datum/reagent/fermi/furranium = 5)
- required_reagents = list(/datum/reagent/drug/aphrodisiac = 1, /datum/reagent/moonsugar = 1, /datum/reagent/silver = 2, /datum/reagent/medicine/salglu_solution = 1)
+ required_reagents = list(/datum/reagent/pax/catnip = 1, /datum/reagent/silver = 2, /datum/reagent/medicine/salglu_solution = 2)
mix_message = "You think you can hear a howl come from the beaker."
//FermiChem vars:
OptimalTempMin = 350
@@ -402,10 +402,6 @@
FermiChem = TRUE
PurityMin = 0.3
-/datum/chemical_reaction/fermi/furranium/organic
- id = "furranium_organic"
- required_reagents = list(/datum/reagent/drug/aphrodisiac = 1, /datum/reagent/pax/catnip = 1, /datum/reagent/silver = 2, /datum/reagent/medicine/salglu_solution = 1)
-
//FOR INSTANT REACTIONS - DO NOT MULTIPLY LIMIT BY 10.
//There's a weird rounding error or something ugh.
@@ -607,4 +603,4 @@
ThermicConstant = 0
HIonRelease = 0.01
RateUpLim = 15
- FermiChem = TRUE
\ No newline at end of file
+ FermiChem = TRUE
diff --git a/modular_citadel/code/modules/reagents/objects/clothes.dm b/modular_citadel/code/modules/reagents/objects/clothes.dm
index d3c566ce70..ab4d49c56f 100644
--- a/modular_citadel/code/modules/reagents/objects/clothes.dm
+++ b/modular_citadel/code/modules/reagents/objects/clothes.dm
@@ -9,7 +9,7 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
//item_flags = NODROP //Tips their hat!
-/obj/item/clothing/head/hattip/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/clothing/head/hattip/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(iscarbon(user))
var/mob/living/carbon/C = user
if(is_ninja(C))
diff --git a/modular_citadel/code/modules/reagents/objects/items.dm b/modular_citadel/code/modules/reagents/objects/items.dm
index 27b8961835..f4316b3c58 100644
--- a/modular_citadel/code/modules/reagents/objects/items.dm
+++ b/modular_citadel/code/modules/reagents/objects/items.dm
@@ -9,7 +9,7 @@
w_class = WEIGHT_CLASS_TINY
//A little janky with pockets
-/obj/item/fermichem/pHbooklet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/item/fermichem/pHbooklet/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user.get_held_index_of_item(src))//Does this check pockets too..?
if(numberOfPages == 50)
icon_state = "pHbookletOpen"
diff --git a/sound/effects/butcher.ogg b/sound/effects/butcher.ogg
new file mode 100644
index 0000000000..2e4a0d2ddc
Binary files /dev/null and b/sound/effects/butcher.ogg differ
diff --git a/sound/effects/dismember.ogg b/sound/effects/dismember.ogg
new file mode 100644
index 0000000000..f5015ad961
Binary files /dev/null and b/sound/effects/dismember.ogg differ
diff --git a/sound/effects/wounds/blood1.ogg b/sound/effects/wounds/blood1.ogg
new file mode 100644
index 0000000000..88c76eb9e3
Binary files /dev/null and b/sound/effects/wounds/blood1.ogg differ
diff --git a/sound/effects/wounds/blood2.ogg b/sound/effects/wounds/blood2.ogg
new file mode 100644
index 0000000000..0fb165108a
Binary files /dev/null and b/sound/effects/wounds/blood2.ogg differ
diff --git a/sound/effects/wounds/blood3.ogg b/sound/effects/wounds/blood3.ogg
new file mode 100644
index 0000000000..f6024a5ff6
Binary files /dev/null and b/sound/effects/wounds/blood3.ogg differ
diff --git a/sound/effects/wounds/crack1.ogg b/sound/effects/wounds/crack1.ogg
new file mode 100644
index 0000000000..aa3bf0ab01
Binary files /dev/null and b/sound/effects/wounds/crack1.ogg differ
diff --git a/sound/effects/wounds/crack2.ogg b/sound/effects/wounds/crack2.ogg
new file mode 100644
index 0000000000..cef226c98b
Binary files /dev/null and b/sound/effects/wounds/crack2.ogg differ
diff --git a/sound/effects/wounds/crackandbleed.ogg b/sound/effects/wounds/crackandbleed.ogg
new file mode 100644
index 0000000000..ea07f13d48
Binary files /dev/null and b/sound/effects/wounds/crackandbleed.ogg differ
diff --git a/sound/effects/wounds/pierce1.ogg b/sound/effects/wounds/pierce1.ogg
new file mode 100644
index 0000000000..cd7b7c3961
Binary files /dev/null and b/sound/effects/wounds/pierce1.ogg differ
diff --git a/sound/effects/wounds/pierce2.ogg b/sound/effects/wounds/pierce2.ogg
new file mode 100644
index 0000000000..4977cab299
Binary files /dev/null and b/sound/effects/wounds/pierce2.ogg differ
diff --git a/sound/effects/wounds/pierce3.ogg b/sound/effects/wounds/pierce3.ogg
new file mode 100644
index 0000000000..e81700b134
Binary files /dev/null and b/sound/effects/wounds/pierce3.ogg differ
diff --git a/sound/effects/wounds/sizzle1.ogg b/sound/effects/wounds/sizzle1.ogg
new file mode 100644
index 0000000000..4a3d229018
Binary files /dev/null and b/sound/effects/wounds/sizzle1.ogg differ
diff --git a/sound/effects/wounds/sizzle2.ogg b/sound/effects/wounds/sizzle2.ogg
new file mode 100644
index 0000000000..409206e58a
Binary files /dev/null and b/sound/effects/wounds/sizzle2.ogg differ
diff --git a/sound/machines/clockcult/ratvar_scream.ogg b/sound/machines/clockcult/ratvar_scream.ogg
new file mode 100644
index 0000000000..5c0c0a0d63
Binary files /dev/null and b/sound/machines/clockcult/ratvar_scream.ogg differ
diff --git a/sound/magic/abomscream.ogg b/sound/magic/abomscream.ogg
new file mode 100644
index 0000000000..4f450e05f7
Binary files /dev/null and b/sound/magic/abomscream.ogg differ
diff --git a/sound/mecha/neostep1.ogg b/sound/mecha/neostep1.ogg
new file mode 100644
index 0000000000..ce7f51ad23
Binary files /dev/null and b/sound/mecha/neostep1.ogg differ
diff --git a/sound/mecha/neostep2.ogg b/sound/mecha/neostep2.ogg
new file mode 100644
index 0000000000..e828d9eadd
Binary files /dev/null and b/sound/mecha/neostep2.ogg differ
diff --git a/sound/mecha/powerloader_step.ogg b/sound/mecha/powerloader_step.ogg
new file mode 100644
index 0000000000..af427df865
Binary files /dev/null and b/sound/mecha/powerloader_step.ogg differ
diff --git a/sound/roundend/CitadelStationHasSeenBetterDays.ogg b/sound/roundend/CitadelStationHasSeenBetterDays.ogg
new file mode 100644
index 0000000000..2fa0c5b33c
Binary files /dev/null and b/sound/roundend/CitadelStationHasSeenBetterDays.ogg differ
diff --git a/sound/voice/catpeople/distressed.ogg b/sound/voice/catpeople/distressed.ogg
new file mode 100644
index 0000000000..cebe73dffc
Binary files /dev/null and b/sound/voice/catpeople/distressed.ogg differ
diff --git a/sound/voice/catpeople/license.txt b/sound/voice/catpeople/license.txt
new file mode 100644
index 0000000000..7218480ddb
--- /dev/null
+++ b/sound/voice/catpeople/license.txt
@@ -0,0 +1,2 @@
+distressed_cat.ogg from Cat annoyed meow / wail by jbierfeldt at https://freesound.org/people/jbierfeldt/sounds/440735/, chopped up and ogged
+cat_puking.ogg from catpuking mp3 by NoiseCollector and Mocha the cat at https://freesound.org/people/NoiseCollector/sounds/80778/, chopped up, volume altered and ogged
\ No newline at end of file
diff --git a/sound/voice/catpeople/puking.ogg b/sound/voice/catpeople/puking.ogg
new file mode 100644
index 0000000000..e19c10858f
Binary files /dev/null and b/sound/voice/catpeople/puking.ogg differ
diff --git a/sound/weapons/etherealhit.ogg b/sound/weapons/etherealhit.ogg
new file mode 100644
index 0000000000..19da870961
Binary files /dev/null and b/sound/weapons/etherealhit.ogg differ
diff --git a/sound/weapons/etherealmiss.ogg b/sound/weapons/etherealmiss.ogg
new file mode 100644
index 0000000000..8feb7cdc91
Binary files /dev/null and b/sound/weapons/etherealmiss.ogg differ
diff --git a/sound/weapons/guillotine.ogg b/sound/weapons/guillotine.ogg
new file mode 100644
index 0000000000..f2647b43e3
Binary files /dev/null and b/sound/weapons/guillotine.ogg differ
diff --git a/sound/weapons/shot.ogg b/sound/weapons/shot.ogg
new file mode 100644
index 0000000000..6c57482973
Binary files /dev/null and b/sound/weapons/shot.ogg differ
diff --git a/strings/abductee_objectives.txt b/strings/abductee_objectives.txt
index 93fd946818..135bb7673b 100644
--- a/strings/abductee_objectives.txt
+++ b/strings/abductee_objectives.txt
@@ -31,7 +31,7 @@ Flood the station's powernet with as much electricity as you can.
Replace all the floor tiles with wood, carpeting, grass or bling.
You must escape the station! Get the shuttle called!
Don't allow anyone to be cloned.
-The oxygen is killing them all and they don't even know it. Make sure no oxygen is on the station.
+Their cold, mindless gaze pierce your soul. They see your every movements, it's merely a question of time before they try to control us further. Deactivate all cameras!
Your body must be improved. Ingest as many drugs as you can.
You are hungry. Eat as much food as you can find.
You see you see what they cannot you see the open door you seeE you SEeEe you SEe yOU seEee SHOW THEM ALL
diff --git a/strings/names/ethereal.txt b/strings/names/ethereal.txt
new file mode 100644
index 0000000000..d3e6a26e6e
--- /dev/null
+++ b/strings/names/ethereal.txt
@@ -0,0 +1,38 @@
+Aten
+Apollo
+Arche
+Atlas
+Eos
+Halo
+Kale
+Nysa
+Orion
+Pallas
+Rigel
+Themis
+Aurora
+Andromeda
+Lyra
+Saggitarius
+Crux
+Canis
+Cygnus
+Corvus
+Cepheus
+Auriga
+Corona
+Aquilla
+Serpens
+Cetus
+Puppis
+Ophiuchus
+Carina
+Cassiopeia
+Canes
+Fornax
+Berenices
+Coma
+Vela
+Triangulum
+Tau
+Ceti
\ No newline at end of file
diff --git a/strings/traumas.json b/strings/traumas.json
index f461c5f5fd..768b854fa5 100644
--- a/strings/traumas.json
+++ b/strings/traumas.json
@@ -131,7 +131,8 @@
"@pick(semicolon)*merp",
"@pick(semicolon)*weh",
"@pick(semicolon)My balls finally feel full, again.",
- "@pick(semicolon)Assaltign a sec osficer aren't crime if ur @pick(roles)"
+ "@pick(semicolon)Assaltign a sec osficer aren't crime if ur @pick(roles)",
+ ";SEC I SPILED MU JICE HELELPH HELPJ JLEP HELP"
],
"mutations": [
diff --git a/strings/wounds/bone_scar_desc.json b/strings/wounds/bone_scar_desc.json
new file mode 100644
index 0000000000..3540547c4a
--- /dev/null
+++ b/strings/wounds/bone_scar_desc.json
@@ -0,0 +1,26 @@
+{
+ "generic": ["general disfigurement"],
+
+ "bluntmoderate": [
+ "the bone equivalent of a faded bruise",
+ "a series of tiny chip marks"
+ ],
+
+ "bluntsevere": [
+ "a series of faded hairline cracks",
+ "a small bone dent"
+ ],
+
+ "bluntcritical": [
+ "large streaks of refilled cracks",
+ "a fractal of reformed stress marks",
+ "a cluster of calluses"
+ ],
+
+ "dismember": [
+ "is slightly misaligned",
+ "has clearly been dropped recently",
+ "has a damaged socket"
+ ]
+
+}
\ No newline at end of file
diff --git a/strings/wounds/flesh_scar_desc.json b/strings/wounds/flesh_scar_desc.json
new file mode 100644
index 0000000000..fb2b927a30
--- /dev/null
+++ b/strings/wounds/flesh_scar_desc.json
@@ -0,0 +1,86 @@
+{
+ "generic": ["general disfigurement"],
+
+ "bluntmoderate": [
+ "light discoloring",
+ "a slight blue tint"
+ ],
+
+ "bluntsevere": [
+ "a faded, fist-sized bruise",
+ "a vaguely triangular peel scar"
+ ],
+
+ "bluntcritical": [
+ "a section of janky skin lines and badly healed scars",
+ "a large patch of uneven skin tone",
+ "a cluster of calluses"
+ ],
+
+
+
+ "slashmoderate": [
+ "light, faded lines",
+ "minor cut marks",
+ "a small faded slit",
+ "a series of small scars"
+ ],
+
+ "slashsevere": [
+ "a twisted line of faded gashes",
+ "a gnarled sickle-shaped slice scar"
+ ],
+
+ "slashcritical": [
+ "a winding path of very badly healed scar tissue",
+ "a series of peaks and valleys along a gruesome line of cut scar tissue",
+ "a grotesque snake of indentations and stitching scars"
+ ],
+
+
+
+ "piercemoderate": [
+ "a small, faded bruise",
+ "a small twist of reformed skin",
+ "a thumb-sized puncture scar"
+ ],
+
+ "piercesevere": [
+ "an ink-splat shaped pocket of scar tissue",
+ "a long-faded puncture wound",
+ "a tumbling puncture hole with evidence of faded stitching"
+ ],
+
+ "piercecritical": [
+ "a rippling shockwave of scar tissue",
+ "a wide, scattered cloud of shrapnel marks",
+ "a gruesome multi-pronged puncture scar"
+ ],
+
+
+
+ "burnmoderate": [
+ "small amoeba-shaped skinmarks",
+ "a faded streak of depressed skin"
+ ],
+
+ "burnsevere": [
+ "a large, jagged patch of faded skin",
+ "random spots of shiny, smooth skin",
+ "spots of taut, leathery skin"
+ ],
+
+ "burncritical": [
+ "massive, disfiguring keloid scars",
+ "several long streaks of badly discolored and malformed skin",
+ "unmistakeable splotches of dead tissue from serious burns"
+ ],
+
+
+ "dismember": [
+ "is several skintone shades paler than the rest of the body",
+ "is a gruesome patchwork of artificial flesh",
+ "has a large series of attachment scars at the articulation points"
+ ]
+
+}
\ No newline at end of file
diff --git a/strings/wounds/scar_loc.json b/strings/wounds/scar_loc.json
new file mode 100644
index 0000000000..f721294925
--- /dev/null
+++ b/strings/wounds/scar_loc.json
@@ -0,0 +1,52 @@
+{
+ "": ["general area"],
+
+ "head": [
+ "left eyebrow",
+ "cheekbone",
+ "neck",
+ "throat",
+ "jawline",
+ "entire face"
+ ],
+
+ "chest": [
+ "upper chest",
+ "lower abdomen",
+ "midsection",
+ "collarbone",
+ "lower back"
+ ],
+
+ "l_arm": [
+ "outer left forearm",
+ "inner left wrist",
+ "left elbow",
+ "left bicep",
+ "left shoulder"
+ ],
+
+ "r_arm": [
+ "outer right forearm",
+ "inner right wrist",
+ "right elbow",
+ "right bicep",
+ "right shoulder"
+ ],
+
+ "l_leg": [
+ "inner left thigh",
+ "outer left calf",
+ "outer left hip",
+ "left kneecap",
+ "lower left shin"
+ ],
+
+ "r_leg": [
+ "inner right thigh",
+ "outer right calf",
+ "outer right hip",
+ "right kneecap",
+ "lower right shin"
+ ]
+}
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index 017ee5bec8..77c4dd3c7e 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -47,6 +47,7 @@
#include "code\__DEFINES\dynamic.dm"
#include "code\__DEFINES\economy.dm"
#include "code\__DEFINES\events.dm"
+#include "code\__DEFINES\exosuit_fabs.dm"
#include "code\__DEFINES\exports.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
#include "code\__DEFINES\food.dm"
@@ -61,6 +62,7 @@
#include "code\__DEFINES\language.dm"
#include "code\__DEFINES\layers_planes.dm"
#include "code\__DEFINES\lighting.dm"
+#include "code\__DEFINES\loadout.dm"
#include "code\__DEFINES\logging.dm"
#include "code\__DEFINES\machines.dm"
#include "code\__DEFINES\maps.dm"
@@ -120,10 +122,12 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wall_dents.dm"
#include "code\__DEFINES\wires.dm"
+#include "code\__DEFINES\wounds.dm"
#include "code\__DEFINES\_flags\_flags.dm"
#include "code\__DEFINES\_flags\do_after.dm"
#include "code\__DEFINES\_flags\item_flags.dm"
#include "code\__DEFINES\_flags\obj_flags.dm"
+#include "code\__DEFINES\_flags\return_values.dm"
#include "code\__DEFINES\_flags\shields.dm"
#include "code\__DEFINES\admin\keybindings.dm"
#include "code\__DEFINES\chemistry\reactions.dm"
@@ -135,7 +139,6 @@
#include "code\__DEFINES\dcs\signals.dm"
#include "code\__DEFINES\mapping\maploader.dm"
#include "code\__DEFINES\material\worth.dm"
-#include "code\__DEFINES\misc\return_values.dm"
#include "code\__DEFINES\mobs\slowdowns.dm"
#include "code\__DEFINES\research\stock_parts.dm"
#include "code\__DEFINES\skills\defines.dm"
@@ -200,6 +203,7 @@
#include "code\_globalvars\lists\client.dm"
#include "code\_globalvars\lists\flavor_misc.dm"
#include "code\_globalvars\lists\keybindings.dm"
+#include "code\_globalvars\lists\loadout_categories.dm"
#include "code\_globalvars\lists\maintenance_loot.dm"
#include "code\_globalvars\lists\mapping.dm"
#include "code\_globalvars\lists\medals.dm"
@@ -220,6 +224,9 @@
#include "code\_onclick\observer.dm"
#include "code\_onclick\other_mobs.dm"
#include "code\_onclick\overmind.dm"
+#include "code\_onclick\right_click.dm"
+#include "code\_onclick\right_item_attack.dm"
+#include "code\_onclick\right_other_mobs.dm"
#include "code\_onclick\telekinesis.dm"
#include "code\_onclick\hud\_defines.dm"
#include "code\_onclick\hud\action_button.dm"
@@ -229,6 +236,7 @@
#include "code\_onclick\hud\alien_larva.dm"
#include "code\_onclick\hud\blob_overmind.dm"
#include "code\_onclick\hud\blobbernauthud.dm"
+#include "code\_onclick\hud\clockwork_marauder.dm"
#include "code\_onclick\hud\constructs.dm"
#include "code\_onclick\hud\credits.dm"
#include "code\_onclick\hud\devil.dm"
@@ -252,7 +260,11 @@
#include "code\_onclick\hud\robot.dm"
#include "code\_onclick\hud\screen_objects.dm"
#include "code\_onclick\hud\swarmer.dm"
+#include "code\_onclick\hud\screen_objects\clickdelay.dm"
+#include "code\_onclick\hud\screen_objects\sprint.dm"
+#include "code\_onclick\hud\screen_objects\stamina.dm"
#include "code\_onclick\hud\screen_objects\storage.dm"
+#include "code\_onclick\hud\screen_objects\vore.dm"
#include "code\controllers\admin.dm"
#include "code\controllers\configuration_citadel.dm"
#include "code\controllers\controller.dm"
@@ -340,6 +352,7 @@
#include "code\controllers\subsystem\processing\circuit.dm"
#include "code\controllers\subsystem\processing\fastprocess.dm"
#include "code\controllers\subsystem\processing\fields.dm"
+#include "code\controllers\subsystem\processing\huds.dm"
#include "code\controllers\subsystem\processing\instruments.dm"
#include "code\controllers\subsystem\processing\nanites.dm"
#include "code\controllers\subsystem\processing\networks.dm"
@@ -354,6 +367,7 @@
#include "code\datums\ai_laws.dm"
#include "code\datums\armor.dm"
#include "code\datums\beam.dm"
+#include "code\datums\beepsky_fashion.dm"
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
#include "code\datums\chatmessage.dm"
@@ -370,6 +384,7 @@
#include "code\datums\explosion.dm"
#include "code\datums\forced_movement.dm"
#include "code\datums\holocall.dm"
+#include "code\datums\http.dm"
#include "code\datums\hud.dm"
#include "code\datums\mind.dm"
#include "code\datums\mutable_appearance.dm"
@@ -419,10 +434,12 @@
#include "code\datums\components\field_of_vision.dm"
#include "code\datums\components\footstep.dm"
#include "code\datums\components\fried.dm"
+#include "code\datums\components\gps.dm"
#include "code\datums\components\identification.dm"
#include "code\datums\components\igniter.dm"
#include "code\datums\components\infective.dm"
#include "code\datums\components\jousting.dm"
+#include "code\datums\components\killerqueen.dm"
#include "code\datums\components\knockback.dm"
#include "code\datums\components\knockoff.dm"
#include "code\datums\components\lifesteal.dm"
@@ -634,6 +651,7 @@
#include "code\datums\status_effects\gas.dm"
#include "code\datums\status_effects\neutral.dm"
#include "code\datums\status_effects\status_effect.dm"
+#include "code\datums\status_effects\wound_effects.dm"
#include "code\datums\traits\_quirk.dm"
#include "code\datums\traits\good.dm"
#include "code\datums\traits\negative.dm"
@@ -661,6 +679,13 @@
#include "code\datums\wires\syndicatebomb.dm"
#include "code\datums\wires\tesla_coil.dm"
#include "code\datums\wires\vending.dm"
+#include "code\datums\wounds\_scars.dm"
+#include "code\datums\wounds\_wounds.dm"
+#include "code\datums\wounds\bones.dm"
+#include "code\datums\wounds\burns.dm"
+#include "code\datums\wounds\loss.dm"
+#include "code\datums\wounds\pierce.dm"
+#include "code\datums\wounds\slash.dm"
#include "code\game\alternate_appearance.dm"
#include "code\game\atoms.dm"
#include "code\game\atoms_movable.dm"
@@ -962,6 +987,7 @@
#include "code\game\objects\items\AI_modules.dm"
#include "code\game\objects\items\airlock_painter.dm"
#include "code\game\objects\items\apc_frame.dm"
+#include "code\game\objects\items\armor_kits.dm"
#include "code\game\objects\items\balls.dm"
#include "code\game\objects\items\binoculars.dm"
#include "code\game\objects\items\blueprints.dm"
@@ -1392,6 +1418,7 @@
#include "code\modules\antagonists\abductor\equipment\abduction_outfits.dm"
#include "code\modules\antagonists\abductor\equipment\abduction_surgery.dm"
#include "code\modules\antagonists\abductor\equipment\gland.dm"
+#include "code\modules\antagonists\abductor\equipment\orderable_gear.dm"
#include "code\modules\antagonists\abductor\equipment\glands\access.dm"
#include "code\modules\antagonists\abductor\equipment\glands\blood.dm"
#include "code\modules\antagonists\abductor\equipment\glands\chem.dm"
@@ -1509,6 +1536,7 @@
#include "code\modules\antagonists\clockcult\clock_effects\servant_blocker.dm"
#include "code\modules\antagonists\clockcult\clock_effects\spatial_gateway.dm"
#include "code\modules\antagonists\clockcult\clock_helpers\clock_powerdrain.dm"
+#include "code\modules\antagonists\clockcult\clock_helpers\clock_rites.dm"
#include "code\modules\antagonists\clockcult\clock_helpers\component_helpers.dm"
#include "code\modules\antagonists\clockcult\clock_helpers\fabrication_helpers.dm"
#include "code\modules\antagonists\clockcult\clock_helpers\hierophant_network.dm"
@@ -1516,6 +1544,7 @@
#include "code\modules\antagonists\clockcult\clock_helpers\ratvarian_language.dm"
#include "code\modules\antagonists\clockcult\clock_helpers\scripture_checks.dm"
#include "code\modules\antagonists\clockcult\clock_helpers\slab_abilities.dm"
+#include "code\modules\antagonists\clockcult\clock_items\clock_augments.dm"
#include "code\modules\antagonists\clockcult\clock_items\clock_components.dm"
#include "code\modules\antagonists\clockcult\clock_items\clockwork_armor.dm"
#include "code\modules\antagonists\clockcult\clock_items\clockwork_slab.dm"
@@ -1527,6 +1556,7 @@
#include "code\modules\antagonists\clockcult\clock_items\soul_vessel.dm"
#include "code\modules\antagonists\clockcult\clock_items\wraith_spectacles.dm"
#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\_call_weapon.dm"
+#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\brass_claw.dm"
#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\ratvarian_shield.dm"
#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\ratvarian_spear.dm"
#include "code\modules\antagonists\clockcult\clock_mobs\_eminence.dm"
@@ -1534,6 +1564,7 @@
#include "code\modules\antagonists\clockcult\clock_scriptures\scripture_applications.dm"
#include "code\modules\antagonists\clockcult\clock_scriptures\scripture_cyborg.dm"
#include "code\modules\antagonists\clockcult\clock_scriptures\scripture_drivers.dm"
+#include "code\modules\antagonists\clockcult\clock_scriptures\scripture_judgement.dm"
#include "code\modules\antagonists\clockcult\clock_scriptures\scripture_scripts.dm"
#include "code\modules\antagonists\clockcult\clock_structures\_trap_object.dm"
#include "code\modules\antagonists\clockcult\clock_structures\ark_of_the_clockwork_justicar.dm"
@@ -1542,6 +1573,7 @@
#include "code\modules\antagonists\clockcult\clock_structures\heralds_beacon.dm"
#include "code\modules\antagonists\clockcult\clock_structures\mania_motor.dm"
#include "code\modules\antagonists\clockcult\clock_structures\ocular_warden.dm"
+#include "code\modules\antagonists\clockcult\clock_structures\prolonging_prism.dm"
#include "code\modules\antagonists\clockcult\clock_structures\ratvar_the_clockwork_justicar.dm"
#include "code\modules\antagonists\clockcult\clock_structures\reflector.dm"
#include "code\modules\antagonists\clockcult\clock_structures\stargazer.dm"
@@ -2251,6 +2283,7 @@
#include "code\modules\language\swarmer.dm"
#include "code\modules\language\sylvan.dm"
#include "code\modules\language\vampiric.dm"
+#include "code\modules\language\voltaic.dm"
#include "code\modules\language\xenocommon.dm"
#include "code\modules\library\lib_codex_gigas.dm"
#include "code\modules\library\lib_items.dm"
@@ -2319,6 +2352,7 @@
#include "code\modules\mining\lavaland\ash_flora.dm"
#include "code\modules\mining\lavaland\necropolis_chests.dm"
#include "code\modules\mining\lavaland\ruins\gym.dm"
+#include "code\modules\mob\clickdelay.dm"
#include "code\modules\mob\death.dm"
#include "code\modules\mob\emote.dm"
#include "code\modules\mob\inventory.dm"
@@ -2371,6 +2405,7 @@
#include "code\modules\mob\dead\observer\say.dm"
#include "code\modules\mob\living\blood.dm"
#include "code\modules\mob\living\bloodcrawl.dm"
+#include "code\modules\mob\living\clickdelay.dm"
#include "code\modules\mob\living\damage_procs.dm"
#include "code\modules\mob\living\death.dm"
#include "code\modules\mob\living\emote.dm"
@@ -2477,6 +2512,7 @@
#include "code\modules\mob\living\carbon\human\species_types\corporate.dm"
#include "code\modules\mob\living\carbon\human\species_types\dullahan.dm"
#include "code\modules\mob\living\carbon\human\species_types\dwarves.dm"
+#include "code\modules\mob\living\carbon\human\species_types\ethereal.dm"
#include "code\modules\mob\living\carbon\human\species_types\felinid.dm"
#include "code\modules\mob\living\carbon\human\species_types\flypeople.dm"
#include "code\modules\mob\living\carbon\human\species_types\furrypeople.dm"
@@ -2493,6 +2529,7 @@
#include "code\modules\mob\living\carbon\human\species_types\synthliz.dm"
#include "code\modules\mob\living\carbon\human\species_types\synths.dm"
#include "code\modules\mob\living\carbon\human\species_types\vampire.dm"
+#include "code\modules\mob\living\carbon\human\species_types\xeno.dm"
#include "code\modules\mob\living\carbon\human\species_types\zombies.dm"
#include "code\modules\mob\living\carbon\monkey\combat.dm"
#include "code\modules\mob\living\carbon\monkey\death.dm"
@@ -2696,6 +2733,7 @@
#include "code\modules\mob\living\simple_animal\slime\slime_mobility.dm"
#include "code\modules\mob\living\simple_animal\slime\subtypes.dm"
#include "code\modules\modular_computers\laptop_vendor.dm"
+#include "code\modules\modular_computers\computers\_modular_computer_shared.dm"
#include "code\modules\modular_computers\computers\item\computer.dm"
#include "code\modules\modular_computers\computers\item\computer_components.dm"
#include "code\modules\modular_computers\computers\item\computer_damage.dm"
@@ -2716,13 +2754,16 @@
#include "code\modules\modular_computers\file_system\programs\airestorer.dm"
#include "code\modules\modular_computers\file_system\programs\alarm.dm"
#include "code\modules\modular_computers\file_system\programs\arcade.dm"
+#include "code\modules\modular_computers\file_system\programs\atmosscan.dm"
#include "code\modules\modular_computers\file_system\programs\card.dm"
+#include "code\modules\modular_computers\file_system\programs\cargobounty.dm"
#include "code\modules\modular_computers\file_system\programs\configurator.dm"
+#include "code\modules\modular_computers\file_system\programs\crewmanifest.dm"
#include "code\modules\modular_computers\file_system\programs\file_browser.dm"
+#include "code\modules\modular_computers\file_system\programs\jobmanagement.dm"
#include "code\modules\modular_computers\file_system\programs\ntdownloader.dm"
#include "code\modules\modular_computers\file_system\programs\ntmonitor.dm"
#include "code\modules\modular_computers\file_system\programs\ntnrc_client.dm"
-#include "code\modules\modular_computers\file_system\programs\nttransfer.dm"
#include "code\modules\modular_computers\file_system\programs\powermonitor.dm"
#include "code\modules\modular_computers\file_system\programs\radar.dm"
#include "code\modules\modular_computers\file_system\programs\robocontrol.dm"
@@ -3069,6 +3110,7 @@
#include "code\modules\research\research_disk.dm"
#include "code\modules\research\server.dm"
#include "code\modules\research\stock_parts.dm"
+#include "code\modules\research\anomaly\anomaly_core.dm"
#include "code\modules\research\designs\AI_module_designs.dm"
#include "code\modules\research\designs\autobotter_designs.dm"
#include "code\modules\research\designs\autoylathe_designs.dm"
@@ -3281,7 +3323,9 @@
#include "code\modules\station_goals\shield.dm"
#include "code\modules\station_goals\station_goal.dm"
#include "code\modules\surgery\amputation.dm"
+#include "code\modules\surgery\bone_mending.dm"
#include "code\modules\surgery\brain_surgery.dm"
+#include "code\modules\surgery\burn_dressing.dm"
#include "code\modules\surgery\cavity_implant.dm"
#include "code\modules\surgery\core_removal.dm"
#include "code\modules\surgery\coronary_bypass.dm"
@@ -3304,6 +3348,7 @@
#include "code\modules\surgery\plastic_surgery.dm"
#include "code\modules\surgery\prosthetic_replacement.dm"
#include "code\modules\surgery\remove_embedded_object.dm"
+#include "code\modules\surgery\repair_puncture.dm"
#include "code\modules\surgery\surgery.dm"
#include "code\modules\surgery\surgery_step.dm"
#include "code\modules\surgery\tools.dm"
@@ -3322,10 +3367,11 @@
#include "code\modules\surgery\advanced\bioware\nerve_grounding.dm"
#include "code\modules\surgery\advanced\bioware\nerve_splicing.dm"
#include "code\modules\surgery\advanced\bioware\vein_threading.dm"
-#include "code\modules\surgery\bodyparts\bodyparts.dm"
+#include "code\modules\surgery\bodyparts\_bodyparts.dm"
#include "code\modules\surgery\bodyparts\dismemberment.dm"
#include "code\modules\surgery\bodyparts\head.dm"
#include "code\modules\surgery\bodyparts\helpers.dm"
+#include "code\modules\surgery\bodyparts\parts.dm"
#include "code\modules\surgery\bodyparts\robot_bodyparts.dm"
#include "code\modules\surgery\organs\appendix.dm"
#include "code\modules\surgery\organs\augments_arms.dm"
@@ -3347,15 +3393,14 @@
#include "code\modules\tgs\includes.dm"
#include "code\modules\tgui\external.dm"
#include "code\modules\tgui\states.dm"
-#include "code\modules\tgui\subsystem.dm"
#include "code\modules\tgui\tgui.dm"
+#include "code\modules\tgui\tgui_window.dm"
#include "code\modules\tgui\states\admin.dm"
#include "code\modules\tgui\states\always.dm"
#include "code\modules\tgui\states\conscious.dm"
#include "code\modules\tgui\states\contained.dm"
#include "code\modules\tgui\states\deep_inventory.dm"
#include "code\modules\tgui\states\default.dm"
-#include "code\modules\tgui\states\default_contained.dm"
#include "code\modules\tgui\states\hands.dm"
#include "code\modules\tgui\states\human_adjacent.dm"
#include "code\modules\tgui\states\inventory.dm"
@@ -3447,12 +3492,6 @@
#include "interface\menu.dm"
#include "interface\stylesheet.dm"
#include "interface\skin.dmf"
-#include "modular_citadel\code\_onclick\click.dm"
-#include "modular_citadel\code\_onclick\item_attack.dm"
-#include "modular_citadel\code\_onclick\other_mobs.dm"
-#include "modular_citadel\code\_onclick\hud\screen_objects.dm"
-#include "modular_citadel\code\_onclick\hud\sprint.dm"
-#include "modular_citadel\code\_onclick\hud\stamina.dm"
#include "modular_citadel\code\datums\components\souldeath.dm"
#include "modular_citadel\code\datums\status_effects\chems.dm"
#include "modular_citadel\code\game\objects\cit_screenshake.dm"
diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml
index 67e74085c7..9fd4db9fd2 100644
--- a/tgui/.eslintrc.yml
+++ b/tgui/.eslintrc.yml
@@ -8,6 +8,8 @@ env:
es6: true
browser: true
node: true
+globals:
+ Byond: readonly
plugins:
- react
settings:
@@ -388,7 +390,7 @@ rules:
## Enforce a particular style for multiline comments
# multiline-comment-style: error
## Enforce newlines between operands of ternary expressions
- multiline-ternary: [error, always-multiline]
+ # multiline-ternary: [error, always-multiline]
## Require constructor names to begin with a capital letter
# new-cap: error
## Enforce or disallow parentheses when invoking a constructor with no
diff --git a/tgui/.gitattributes b/tgui/.gitattributes
index 0016cc3bf6..9382416e69 100644
--- a/tgui/.gitattributes
+++ b/tgui/.gitattributes
@@ -2,9 +2,18 @@
## Enforce text mode and LF line breaks
*.js text eol=lf
+*.jsx text eol=lf
+*.ts text eol=lf
+*.tsx text eol=lf
*.css text eol=lf
+*.scss text eol=lf
*.html text eol=lf
*.json text eol=lf
+*.yml text eol=lf
+*.md text eol=lf
+*.bat text eol=lf
+yarn.lock text eol=lf
+bin/tgui text eol=lf
## Treat bundles as binary and ignore them during conflicts
*.bundle.* binary merge=tgui-merge-bundle
diff --git a/tgui/README.md b/tgui/README.md
index 5ddeb18fdd..9eab0196de 100644
--- a/tgui/README.md
+++ b/tgui/README.md
@@ -67,8 +67,9 @@ Run one of the following:
game as you code it. Very useful, highly recommended.
- In order to use it, you should start the game server first, connect to it
and wait until the world has been properly loaded and you are no longer
- in the lobby. Start tgui dev server. You'll know that it's hooked correctly
- if data gets dumped to the log when tgui windows are opened.
+ in the lobby. Start tgui dev server, and once it has finished building,
+ press F5 on any tgui window. You'll know that it's hooked correctly if
+ you see a green bug icon in titlebar and data gets dumped to the console.
- `bin/tgui --dev --reload` - reload byond cache once.
- `bin/tgui --dev --debug` - run server with debug logging enabled.
- `bin/tgui --dev --no-hot` - disable hot module replacement (helps when
@@ -134,11 +135,11 @@ logs and time spent on rendering. Use this information to optimize your
code, and try to keep re-renders below 16ms.
**Kitchen Sink.**
-Press `Ctrl+Alt+=` to open the KitchenSink interface. This interface is a
+Press `F12` to open the KitchenSink interface. This interface is a
playground to test various tgui components.
**Layout Debugger.**
-Press `Ctrl+Alt+-` to toggle the *layout debugger*. It will show outlines of
+Press `F11` to toggle the *layout debugger*. It will show outlines of
all tgui elements, which makes it easy to understand how everything comes
together, and can reveal certain layout bugs which are not normally visible.
@@ -180,8 +181,11 @@ See: [Component Reference](docs/component-reference.md).
## License
-All code is licensed with the parent license of *tgstation*, **AGPL-3.0**.
+Source code is covered by /tg/station's parent license - **AGPL-3.0**
+(see the main [README](../README.md)), unless otherwise indicated.
-See the main [README](../README.md) for more details.
+Some files are annotated with a copyright header, which explicitly states
+the copyright holder and license of the file. Most of the core tgui
+source code is available under the **MIT** license.
The Authors retain all copyright to their respective work here submitted.
diff --git a/tgui/bin/tgui b/tgui/bin/tgui
index eb1f200b31..97a86159e6 100755
--- a/tgui/bin/tgui
+++ b/tgui/bin/tgui
@@ -52,6 +52,7 @@ task-dev-server() {
task-eslint() {
cd "${base_dir}"
eslint ./packages "${@}"
+ echo "tgui: eslint check passed"
}
## Mr. Proper
@@ -153,6 +154,13 @@ if [[ ${1} == '--lint-harder' ]]; then
exit 0
fi
+if [[ ${1} == '--fix' ]]; then
+ shift 1
+ task-install
+ task-eslint --fix "${@}"
+ exit 0
+fi
+
## Analyze the bundle
if [[ ${1} == '--analyze' ]]; then
task-install
diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md
index a2a0066a70..ff1b4e7dfd 100644
--- a/tgui/docs/component-reference.md
+++ b/tgui/docs/component-reference.md
@@ -30,6 +30,8 @@ Make sure to add new items to this list if you document new components.
- [`Icon`](#icon)
- [`Input`](#input)
- [`Knob`](#knob)
+ - [`LabeledControls`](#labeledcontrols)
+ - [`LabeledControls.Item`](#labeledcontrolsitem)
- [`LabeledList`](#labeledlist)
- [`LabeledList.Item`](#labeledlistitem)
- [`LabeledList.Divider`](#labeledlistdivider)
@@ -239,7 +241,7 @@ A ghetto checkbox, made entirely using existing Button API.
### `Button.Confirm`
-A button with a an extra confirmation step, using native button component.
+A button with an extra confirmation step, using native button component.
**Props:**
@@ -273,11 +275,11 @@ interface.
Example (button):
-```
+```jsx
@@ -285,11 +287,10 @@ Example (button):
Example (map):
-```
+```jsx
```
@@ -584,6 +585,24 @@ the input, or successfully enter a number.
- `onDrag: (e, value) => void` - An event, which fires about every 500ms
when you drag the input up and down, on release and on manual editing.
+### `LabeledControls`
+
+LabeledControls is a horizontal grid, that is designed to hold various
+controls, like [Knobs](#knob) or small [Buttons](#button). Every item in
+this grid is labeled at the bottom.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `children: LabeledControls.Item` - Items to render.
+
+### `LabeledControls.Item`
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `label: string` - Item label.
+
### `LabeledList`
LabeledList is a continuous, vertical list of text and other content, where
@@ -962,6 +981,7 @@ Example:
- `className: string` - Applies a CSS class to the element.
- `theme: string` - A name of the theme.
- For a list of themes, see `packages/tgui/styles/themes`.
+- `title: string` - Window title.
- `resizable: boolean` - Controls resizability of the window.
- `children: any` - Child elements, which are rendered directly inside the
window. If you use a [Dimmer](#dimmer) or [Modal](#modal) in your UI,
diff --git a/tgui/docs/converting-old-tgui-interfaces.md b/tgui/docs/converting-old-tgui-interfaces.md
index a42724e05c..fe2feebfee 100644
--- a/tgui/docs/converting-old-tgui-interfaces.md
+++ b/tgui/docs/converting-old-tgui-interfaces.md
@@ -73,6 +73,7 @@ This might look a bit intimidating compared to the reactive part but it's not as
You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong.
Ractive conditionals can have an `else` as well
+
```ractive
{{#if data.condition}}
value
@@ -116,7 +117,7 @@ and you can mix string literals, values, and tags as well.
Ractive has loops for iterating over data and inserting something for each
member of an array or object
-```
+```ractive
{{#each data.list_of_foo}}
foo {{number}} is here.
{{/each}}
@@ -135,6 +136,7 @@ Objects are represented by `{}`, arrays by `[]`
`list("bla", "blo")` would become `["bla", "blo"]` and `list("foo" = 1, "bar" = 2)` would become `{"foo": 1, "bar": 2}`
First things first, above the `return` of the function you're making the interface in, you're going to want to add something like this
+
```jsx
const things = data.things || [];
```
@@ -142,6 +144,7 @@ const things = data.things || [];
This ensures that you'll never be reading a null entry by mistake. Substitute `{}` for objects as appropriate.
If it's an array, you'll want to do this in the template
+
```jsx
{things.map(thing => (
@@ -187,7 +190,7 @@ const fooArray = toArray(fooObject);
Also occasionally you'd see an else:
-```
+```ractive
{{#each data.potentially_empty_list}}
Thing "{{name}}" is in this list!
{{else}}
@@ -220,7 +223,7 @@ This will be a reference of tgui components and the tgui-next equivalent.
Equivalent of `` is ``
-```
+```ractive
Contents
@@ -236,7 +239,7 @@ becomes
A feature sometimes used is if `ui-display` has the `button` property, it will contain a `partial` command. This becomes the `buttons` property on `Section`:
-```
+```ractive
{{#partial button}}
// lots more button bullshit here
@@ -263,7 +266,7 @@ Very important to note `ui-section` is NOT the equivalent of `Section`
`` does not have a direct equivalent, but the closest equivalent is ``
-```
+```ractive
No Power
@@ -293,7 +296,7 @@ Also good to know that if you need the contents of a `LabeledList.Item` to be co
`` has a direct equivalent in ``
-```
+```ractive
Notice stuff!
@@ -311,7 +314,7 @@ becomes
The equivalent of `ui-button` is `Button` but it works quite a bit differently.
-```
+```ractive
{
@@ -294,10 +292,10 @@ here's what you need (note that you'll probably be forced to clean your shit up
upon code review):
```dm
-/obj/copypasta/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) // Remember to use the appropriate state.
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/copypasta/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "copypasta", name, 300, 300, master_ui, state)
+ ui = new(user, src, "copypasta")
ui.open()
/obj/copypasta/ui_data(mob/user)
@@ -345,7 +343,7 @@ export const SampleInterface = (props, context) => {
diff --git a/tgui/package.json b/tgui/package.json
index bfceeec49e..8dd15925b2 100644
--- a/tgui/package.json
+++ b/tgui/package.json
@@ -13,7 +13,7 @@
},
"dependencies": {
"babel-eslint": "^10.0.3",
- "eslint": "^6.7.2",
+ "eslint": "^7.4.0",
"eslint-plugin-react": "^7.17.0"
}
}
diff --git a/tgui/packages/common/collections.js b/tgui/packages/common/collections.js
index 1e5c978942..b542967d47 100644
--- a/tgui/packages/common/collections.js
+++ b/tgui/packages/common/collections.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
/**
* Converts a given collection to an array.
*
diff --git a/tgui/packages/common/fp.js b/tgui/packages/common/fp.js
index 4be45877e2..7aa00a00f3 100644
--- a/tgui/packages/common/fp.js
+++ b/tgui/packages/common/fp.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
/**
* Creates a function that returns the result of invoking the given
* functions, where each successive invocation is supplied the return
diff --git a/tgui/packages/common/logging.js b/tgui/packages/common/logging.js
index 4ae1855fda..0dc222ae3d 100644
--- a/tgui/packages/common/logging.js
+++ b/tgui/packages/common/logging.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
const inception = Date.now();
// Runtime detection
diff --git a/tgui/packages/common/math.js b/tgui/packages/common/math.js
index cc7a309563..c3013b5a32 100644
--- a/tgui/packages/common/math.js
+++ b/tgui/packages/common/math.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
/**
* Limits a number to the range between 'min' and 'max'.
*/
diff --git a/tgui/packages/common/perf.js b/tgui/packages/common/perf.js
new file mode 100644
index 0000000000..319b77cea3
--- /dev/null
+++ b/tgui/packages/common/perf.js
@@ -0,0 +1,44 @@
+/**
+ * Ghetto performance measurement tools.
+ *
+ * Uses NODE_ENV to redact itself from production bundles.
+ *
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
+let markersByLabel = {};
+
+/**
+ * Marks a certain spot in the code for later measurements.
+ */
+const mark = (label, timestamp) => {
+ if (process.env.NODE_ENV !== 'production') {
+ markersByLabel[label] = timestamp || Date.now();
+ }
+};
+
+/**
+ * Calculates and returns the difference between two markers as a string.
+ *
+ * Use logger.log() to print the measurement.
+ */
+const measure = (markerA, markerB) => {
+ if (process.env.NODE_ENV !== 'production') {
+ return timeDiff(
+ markersByLabel[markerA],
+ markersByLabel[markerB]);
+ }
+};
+
+const timeDiff = (startedAt, finishedAt) => {
+ const diff = Math.abs(finishedAt - startedAt);
+ const diffFrames = (diff / 16.6667).toFixed(2);
+ return `${diff}ms (${diffFrames} frames)`;
+};
+
+export const perf = {
+ mark,
+ measure,
+};
diff --git a/tgui/packages/common/react.js b/tgui/packages/common/react.js
index 0828bb8864..dba84b7b10 100644
--- a/tgui/packages/common/react.js
+++ b/tgui/packages/common/react.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
/**
* Helper for conditionally adding/removing classes in React
*
diff --git a/tgui/packages/common/redux.js b/tgui/packages/common/redux.js
index 257a9eebf5..dc486ff7b8 100644
--- a/tgui/packages/common/redux.js
+++ b/tgui/packages/common/redux.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import { compose } from './fp';
/**
@@ -63,3 +69,31 @@ export const applyMiddleware = (...middlewares) => {
};
};
};
+
+/**
+ * Combines reducers by running them in their own object namespaces as
+ * defined in reducersObj paramter.
+ *
+ * Main difference from redux/combineReducers is that it preserves keys
+ * in the state that are not present in the reducers object. This function
+ * is also more flexible than the redux counterpart.
+ */
+export const combineReducers = reducersObj => {
+ const keys = Object.keys(reducersObj);
+ let hasChanged = false;
+ return (prevState, action) => {
+ const nextState = { ...prevState };
+ for (let key of keys) {
+ const reducer = reducersObj[key];
+ const prevDomainState = prevState[key];
+ const nextDomainState = reducer(prevDomainState, action);
+ if (prevDomainState !== nextDomainState) {
+ hasChanged = true;
+ nextState[key] = nextDomainState;
+ }
+ }
+ return hasChanged
+ ? nextState
+ : prevState;
+ };
+};
diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.js
new file mode 100644
index 0000000000..8e1d2183e4
--- /dev/null
+++ b/tgui/packages/common/storage.js
@@ -0,0 +1,76 @@
+/**
+ * Browser-agnostic abstraction of key-value web storage.
+ *
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
+export const STORAGE_NONE = 0;
+export const STORAGE_LOCAL_STORAGE = 1;
+export const STORAGE_INDEXED_DB = 2;
+
+const createMock = () => {
+ let storage = {};
+ const get = key => storage[key];
+ const set = (key, value) => {
+ storage[key] = value;
+ };
+ const remove = key => {
+ storage[key] = undefined;
+ };
+ const clear = () => {
+ // NOTE: On IE8, this will probably leak memory if used often.
+ storage = {};
+ };
+ return {
+ get,
+ set,
+ remove,
+ clear,
+ engine: STORAGE_NONE,
+ };
+};
+
+const createLocalStorage = () => {
+ const get = key => {
+ const value = localStorage.getItem(key);
+ if (typeof value !== 'string') {
+ return;
+ }
+ return JSON.parse(value);
+ };
+ const set = (key, value) => {
+ localStorage.setItem(key, JSON.stringify(value));
+ };
+ const remove = key => {
+ localStorage.removeItem(key);
+ };
+ const clear = () => {
+ localStorage.clear();
+ };
+ return {
+ get,
+ set,
+ remove,
+ clear,
+ engine: STORAGE_LOCAL_STORAGE,
+ };
+};
+
+const testLocalStorage = () => {
+ // Localstorage can sometimes throw an error, even if DOM storage is not
+ // disabled in IE11 settings.
+ // See: https://superuser.com/questions/1080011
+ try {
+ return Boolean(window.localStorage && window.localStorage.getItem);
+ }
+ catch {
+ return false;
+ }
+};
+
+export const storage = (
+ testLocalStorage() && createLocalStorage()
+ || createMock()
+);
diff --git a/tgui/packages/common/string.babel-plugin.cjs b/tgui/packages/common/string.babel-plugin.cjs
index ba25e3f91d..68295aefcf 100644
--- a/tgui/packages/common/string.babel-plugin.cjs
+++ b/tgui/packages/common/string.babel-plugin.cjs
@@ -1,5 +1,7 @@
/**
- * @file
+ * This plugin saves overall about 10KB on the final bundle size, so it's
+ * sort of worth it.
+ *
* We are using a .cjs extension because:
*
* 1. Webpack CLI only supports CommonJS modules;
@@ -9,8 +11,9 @@
* We need to copy-paste the whole "multiline" function because we can't
* synchronously import an ES module from a CommonJS module.
*
- * This plugin saves overall about 10KB on the final bundle size, so it's
- * sort of worth it.
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
*/
/**
diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js
index d05dbfb6fc..16a0921a25 100644
--- a/tgui/packages/common/string.js
+++ b/tgui/packages/common/string.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
/**
* Removes excess whitespace and indentation from the string.
*/
diff --git a/tgui/packages/common/timer.js b/tgui/packages/common/timer.js
index e3feb69ca9..f4e26fa5aa 100644
--- a/tgui/packages/common/timer.js
+++ b/tgui/packages/common/timer.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
/**
* Returns a function, that, as long as it continues to be invoked, will
* not be triggered. The function will be called after it stops being
diff --git a/tgui/packages/common/vector.js b/tgui/packages/common/vector.js
index fa98597896..c3ac350a4e 100644
--- a/tgui/packages/common/vector.js
+++ b/tgui/packages/common/vector.js
@@ -1,14 +1,14 @@
-import { map, reduce, zipWith } from './collections';
-
/**
- * Creates a vector, with as many dimensions are there are arguments.
+ * N-dimensional vector manipulation functions.
+ *
+ * Vectors are plain number arrays, i.e. [x, y, z].
+ *
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
*/
-export const vecCreate = (...components) => {
- if (Array.isArray(components[0])) {
- return [...components[0]];
- }
- return components;
-};
+
+import { map, reduce, zipWith } from './collections';
const ADD = (a, b) => a + b;
const SUB = (a, b) => a - b;
diff --git a/tgui/packages/tgui-dev-server/index.js b/tgui/packages/tgui-dev-server/index.js
index 1e7683080c..f4e8155d29 100644
--- a/tgui/packages/tgui-dev-server/index.js
+++ b/tgui/packages/tgui-dev-server/index.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import { setupWebpack, getWebpackConfig } from './webpack.js';
import { reloadByondCache } from './reloader.js';
diff --git a/tgui/packages/tgui-dev-server/link/client.js b/tgui/packages/tgui-dev-server/link/client.js
index 774b7ed6db..4671b340c5 100644
--- a/tgui/packages/tgui-dev-server/link/client.js
+++ b/tgui/packages/tgui-dev-server/link/client.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
let socket;
const queue = [];
const subscribers = [];
@@ -92,8 +98,8 @@ const sendRawMessage = msg => {
socket.send(json);
}
else {
- // Keep only 10 latest messages in the queue
- if (queue.length > 10) {
+ // Keep only 100 latest messages in the queue
+ if (queue.length > 100) {
queue.shift();
}
queue.push(json);
diff --git a/tgui/packages/tgui-dev-server/link/retrace.js b/tgui/packages/tgui-dev-server/link/retrace.js
index 74c87e6a55..e0b17a01d6 100644
--- a/tgui/packages/tgui-dev-server/link/retrace.js
+++ b/tgui/packages/tgui-dev-server/link/retrace.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import { createLogger } from 'common/logging.js';
import fs from 'fs';
import { basename } from 'path';
diff --git a/tgui/packages/tgui-dev-server/link/server.js b/tgui/packages/tgui-dev-server/link/server.js
index 84f3700048..94a79c9ad5 100644
--- a/tgui/packages/tgui-dev-server/link/server.js
+++ b/tgui/packages/tgui-dev-server/link/server.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import { createLogger, directLog } from 'common/logging.js';
import http from 'http';
import { inspect } from 'util';
diff --git a/tgui/packages/tgui-dev-server/reloader.js b/tgui/packages/tgui-dev-server/reloader.js
index 394e55afdb..e33f7226b9 100644
--- a/tgui/packages/tgui-dev-server/reloader.js
+++ b/tgui/packages/tgui-dev-server/reloader.js
@@ -1,9 +1,16 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import { createLogger } from 'common/logging.js';
import fs from 'fs';
import os from 'os';
import { basename } from 'path';
import { promisify } from 'util';
import { resolveGlob, resolvePath } from './util.js';
+import { regQuery } from './winreg.js';
const logger = createLogger('reloader');
@@ -40,6 +47,21 @@ export const findCacheRoot = async () => {
return cacheRoot;
}
}
+ // Query the Windows Registry
+ if (process.platform === 'win32') {
+ logger.log('querying windows registry');
+ let userpath = await regQuery(
+ 'HKCU\\Software\\Dantom\\BYOND',
+ 'userpath');
+ if (userpath) {
+ cacheRoot = userpath
+ .replace(/\\$/, '')
+ .replace(/\\/g, '/')
+ + '/cache';
+ logger.log(`found cache at '${cacheRoot}'`);
+ return cacheRoot;
+ }
+ }
logger.log('found no cache directories');
};
diff --git a/tgui/packages/tgui-dev-server/util.js b/tgui/packages/tgui-dev-server/util.js
index db34626721..50c0baad5a 100644
--- a/tgui/packages/tgui-dev-server/util.js
+++ b/tgui/packages/tgui-dev-server/util.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import glob from 'glob';
import { resolve as resolvePath } from 'path';
import fs from 'fs';
diff --git a/tgui/packages/tgui-dev-server/webpack.js b/tgui/packages/tgui-dev-server/webpack.js
index 778469a15b..c625827409 100644
--- a/tgui/packages/tgui-dev-server/webpack.js
+++ b/tgui/packages/tgui-dev-server/webpack.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
import { createLogger } from 'common/logging.js';
import fs from 'fs';
import { createRequire } from 'module';
diff --git a/tgui/packages/tgui-dev-server/winreg.js b/tgui/packages/tgui-dev-server/winreg.js
new file mode 100644
index 0000000000..974135e76d
--- /dev/null
+++ b/tgui/packages/tgui-dev-server/winreg.js
@@ -0,0 +1,47 @@
+/**
+ * Tools for dealing with Windows Registry bullshit.
+ *
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
+import { exec } from 'child_process';
+import { createLogger } from 'common/logging.js';
+import { promisify } from 'util';
+
+const logger = createLogger('winreg');
+
+export const regQuery = async (path, key) => {
+ if (process.platform !== 'win32') {
+ return null;
+ }
+ try {
+ const command = `reg query "${path}" /v ${key}`;
+ const { stdout } = await promisify(exec)(command);
+ const keyPattern = ` ${key} `;
+ const indexOfKey = stdout.indexOf(keyPattern);
+ if (indexOfKey === -1) {
+ logger.error('could not find the registry key');
+ return null;
+ }
+ const indexOfEol = stdout.indexOf('\r\n', indexOfKey);
+ if (indexOfEol === -1) {
+ logger.error('could not find the end of the line');
+ return null;
+ }
+ const indexOfValue = stdout.indexOf(
+ ' ',
+ indexOfKey + keyPattern.length);
+ if (indexOfValue === -1) {
+ logger.error('could not find the start of the key value');
+ return null;
+ }
+ const value = stdout.substring(indexOfValue + 4, indexOfEol);
+ return value;
+ }
+ catch (err) {
+ logger.error(err);
+ return null;
+ }
+};
diff --git a/tgui/packages/tgui/assets.js b/tgui/packages/tgui/assets.js
new file mode 100644
index 0000000000..b0f71bb9ff
--- /dev/null
+++ b/tgui/packages/tgui/assets.js
@@ -0,0 +1,54 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
+import { loadCSS as fgLoadCSS } from 'fg-loadcss';
+import { createLogger } from './logging';
+
+const logger = createLogger('assets');
+
+const EXCLUDED_PATTERNS = [
+ /v4shim/i,
+];
+
+const loadedStyles = [];
+const loadedMappings = {};
+
+export const loadCSS = url => {
+ if (loadedStyles.includes(url)) {
+ return;
+ }
+ loadedStyles.push(url);
+ logger.log(`loading stylesheet '${url}'`);
+ fgLoadCSS(url);
+};
+
+export const resolveAsset = name => (
+ loadedMappings[name] || name
+);
+
+export const assetMiddleware = store => next => action => {
+ const { type, payload } = action;
+ if (type === 'asset/stylesheet') {
+ loadCSS(payload);
+ return;
+ }
+ if (type === 'asset/mappings') {
+ for (let name of Object.keys(payload)) {
+ // Skip anything that matches excluded patterns
+ if (EXCLUDED_PATTERNS.some(regex => regex.test(name))) {
+ continue;
+ }
+ const url = payload[name];
+ const ext = name.split('.').pop();
+ loadedMappings[name] = url;
+ if (ext === 'css') {
+ loadCSS(url);
+ }
+ }
+ return;
+ }
+ next(action);
+};
diff --git a/tgui/packages/tgui/backend.js b/tgui/packages/tgui/backend.js
index 0c35483487..dab86ee918 100644
--- a/tgui/packages/tgui/backend.js
+++ b/tgui/packages/tgui/backend.js
@@ -5,10 +5,18 @@
* Sometimes backend can response without a "data" field, but our final
* state will still contain previous "data" because we are merging
* the response with already existing state.
+ *
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
*/
+import { perf } from 'common/perf';
import { UI_DISABLED, UI_INTERACTIVE } from './constants';
-import { callByond } from './byond';
+import { releaseHeldKeys } from './hotkeys';
+import { createLogger } from './logging';
+
+const logger = createLogger('backend');
export const backendUpdate = state => ({
type: 'backend/update',
@@ -20,7 +28,23 @@ export const backendSetSharedState = (key, nextState) => ({
payload: { key, nextState },
});
-export const backendReducer = (state, action) => {
+export const backendSuspendStart = () => ({
+ type: 'backend/suspendStart',
+});
+
+export const backendSuspendSuccess = () => ({
+ type: 'backend/suspendSuccess',
+ payload: {
+ timestamp: Date.now(),
+ },
+});
+
+const initialState = {
+ config: {},
+ data: {},
+};
+
+export const backendReducer = (state = initialState, action) => {
const { type, payload } = action;
if (type === 'backend/update') {
@@ -59,6 +83,7 @@ export const backendReducer = (state, action) => {
shared,
visible,
interactive,
+ suspended: false,
};
}
@@ -73,30 +98,175 @@ export const backendReducer = (state, action) => {
};
}
+ if (type === 'backend/suspendStart') {
+ return {
+ ...state,
+ suspending: true,
+ };
+ }
+
+ if (type === 'backend/suspendSuccess') {
+ const { timestamp } = payload;
+ return {
+ ...state,
+ data: {},
+ shared: {},
+ config: {
+ ...state.config,
+ title: '',
+ status: 1,
+ },
+ suspending: false,
+ suspended: timestamp,
+ };
+ }
+
return state;
};
+export const backendMiddleware = store => {
+ let fancyState;
+ let suspendInterval;
+
+ return next => action => {
+ const { config, suspended } = selectBackend(store.getState());
+ const { type, payload } = action;
+
+ if (type === 'backend/suspendStart' && !suspendInterval) {
+ logger.log(`suspending (${window.__windowId__})`);
+ // Keep sending suspend messages until it succeeds.
+ // It may fail multiple times due to topic rate limiting.
+ const suspendFn = () => sendMessage({
+ type: 'suspend',
+ });
+ suspendFn();
+ suspendInterval = setInterval(suspendFn, 2000);
+ }
+
+ if (type === 'backend/suspendSuccess') {
+ clearInterval(suspendInterval);
+ suspendInterval = undefined;
+ releaseHeldKeys();
+ Byond.winset(window.__windowId__, {
+ 'is-visible': false,
+ });
+ }
+
+ if (type === 'backend/update') {
+ const fancy = payload.config?.window?.fancy;
+ // Initialize fancy state
+ if (fancyState === undefined) {
+ fancyState = fancy;
+ }
+ // React to changes in fancy
+ else if (fancyState !== fancy) {
+ logger.log('changing fancy mode to', fancy);
+ fancyState = fancy;
+ Byond.winset(window.__windowId__, {
+ titlebar: !fancy,
+ 'can-resize': !fancy,
+ });
+ }
+ }
+
+ if (type === 'backend/update' && suspended) {
+ // We schedule this for the next tick here because resizing and unhiding
+ // during the same tick will flash with a white background.
+ setImmediate(() => {
+ perf.mark('resume/start');
+ // Doublecheck if we are not re-suspended.
+ const { suspended } = selectBackend(store.getState());
+ if (suspended) {
+ return;
+ }
+ Byond.winset(window.__windowId__, {
+ 'is-visible': true,
+ });
+ perf.mark('resume/finish');
+ if (process.env.NODE_ENV !== 'production') {
+ logger.log('visible in',
+ perf.measure('render/finish', 'resume/finish'));
+ }
+ });
+ }
+
+ return next(action);
+ };
+};
+
+/**
+ * Sends a message to /datum/tgui_window.
+ */
+export const sendMessage = (message = {}) => {
+ const { payload, ...rest } = message;
+ const data = {
+ // Message identifying header
+ tgui: 1,
+ window_id: window.__windowId__,
+ // Message body
+ ...rest,
+ };
+ // JSON-encode the payload
+ if (payload !== null && payload !== undefined) {
+ data.payload = JSON.stringify(payload);
+ }
+ Byond.topic(data);
+};
+
+/**
+ * Sends an action to `ui_act` on `src_object` that this tgui window
+ * is associated with.
+ */
+export const sendAct = (action, payload = {}) => {
+ // Validate that payload is an object
+ const isObject = typeof payload === 'object'
+ && payload !== null
+ && !Array.isArray(payload);
+ if (!isObject) {
+ logger.error(`Payload for act() must be an object, got this:`, payload);
+ return;
+ }
+ sendMessage({
+ type: 'act/' + action,
+ payload,
+ });
+};
+
/**
* @typedef BackendState
* @type {{
* config: {
* title: string,
* status: number,
- * screen: string,
- * style: string,
* interface: string,
- * fancy: number,
- * locked: number,
- * observer: number,
- * window: string,
- * ref: string,
+ * user: {
+ * name: string,
+ * ckey: string,
+ * observer: number,
+ * },
+ * window: {
+ * key: string,
+ * size: [number, number],
+ * fancy: boolean,
+ * locked: boolean,
+ * },
* },
* data: any,
+ * shared: any,
* visible: boolean,
* interactive: boolean,
+ * suspending: boolean,
+ * suspended: boolean,
* }}
*/
+/**
+ * Selects a backend-related slice of Redux state
+ *
+ * @return {BackendState}
+ */
+export const selectBackend = state => state.backend || {};
+
/**
* A React hook (sort of) for getting tgui state and related functions.
*
@@ -104,21 +274,16 @@ export const backendReducer = (state, action) => {
* be used in functional components.
*
* @return {BackendState & {
- * act: (action: string, params?: object) => void,
+ * act: sendAct,
* }}
*/
export const useBackend = context => {
const { store } = context;
- const state = store.getState();
- const ref = state.config.ref;
- const act = (action, params = {}) => {
- callByond('', {
- src: ref,
- action,
- ...params,
- });
+ const state = selectBackend(store.getState());
+ return {
+ ...state,
+ act: sendAct,
};
- return { ...state, act };
};
/**
@@ -136,7 +301,7 @@ export const useBackend = context => {
*/
export const useLocalState = (context, key, initialState) => {
const { store } = context;
- const state = store.getState();
+ const state = selectBackend(store.getState());
const sharedStates = state.shared ?? {};
const sharedState = (key in sharedStates)
? sharedStates[key]
@@ -144,7 +309,11 @@ export const useLocalState = (context, key, initialState) => {
return [
sharedState,
nextState => {
- store.dispatch(backendSetSharedState(key, nextState));
+ store.dispatch(backendSetSharedState(key, (
+ typeof nextState === 'function'
+ ? nextState(sharedState)
+ : nextState
+ )));
},
];
};
@@ -165,8 +334,7 @@ export const useLocalState = (context, key, initialState) => {
*/
export const useSharedState = (context, key, initialState) => {
const { store } = context;
- const state = store.getState();
- const ref = state.config.ref;
+ const state = selectBackend(store.getState());
const sharedStates = state.shared ?? {};
const sharedState = (key in sharedStates)
? sharedStates[key]
@@ -174,11 +342,14 @@ export const useSharedState = (context, key, initialState) => {
return [
sharedState,
nextState => {
- callByond('', {
- src: ref,
- action: 'tgui:setSharedState',
+ sendMessage({
+ type: 'setSharedState',
key,
- value: JSON.stringify(nextState) || '',
+ value: JSON.stringify(
+ typeof nextState === 'function'
+ ? nextState(sharedState)
+ : nextState
+ ) || '',
});
},
];
diff --git a/tgui/packages/tgui/byond.js b/tgui/packages/tgui/byond.js
index bd70056613..fa2b03e715 100644
--- a/tgui/packages/tgui/byond.js
+++ b/tgui/packages/tgui/byond.js
@@ -1,3 +1,9 @@
+/**
+ * @file
+ * @copyright 2020 Aleksej Komarov
+ * @license MIT
+ */
+
// Reference a global Byond object
const { Byond } = window;
diff --git a/tgui/packages/tgui/components/Box.js b/tgui/packages/tgui/components/Box.js
index cb86890a97..a85c692e9a 100644
--- a/tgui/packages/tgui/components/Box.js
+++ b/tgui/packages/tgui/components/Box.js
@@ -9,17 +9,22 @@ import { createVNode } from 'inferno';
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
import { CSS_COLORS } from '../constants';
-const UNIT_PX = 12;
-
/**
* Coverts our rem-like spacing unit into a CSS unit.
*/
export const unit = value => {
if (typeof value === 'string') {
+ // Transparently convert pixels into rem units
+ if (value.endsWith('px') && !Byond.IS_LTE_IE8) {
+ return parseFloat(value) / 12 + 'rem';
+ }
return value;
}
if (typeof value === 'number') {
- return (value * UNIT_PX) + 'px';
+ if (Byond.IS_LTE_IE8) {
+ return value * 12 + 'px';
+ }
+ return value + 'rem';
}
};
@@ -28,10 +33,10 @@ export const unit = value => {
*/
export const halfUnit = value => {
if (typeof value === 'string') {
- return value;
+ return unit(value);
}
if (typeof value === 'number') {
- return (value * UNIT_PX * 0.5) + 'px';
+ return unit(value * 0.5);
}
};
@@ -90,7 +95,13 @@ const styleMapperByPropName = {
maxHeight: mapUnitPropTo('max-height', unit),
fontSize: mapUnitPropTo('font-size', unit),
fontFamily: mapRawPropTo('font-family'),
- lineHeight: mapRawPropTo('line-height'),
+ lineHeight: (style, value) => {
+ if (!isFalsy(value)) {
+ style['line-height'] = typeof value === 'number'
+ ? value
+ : unit(value);
+ }
+ },
opacity: mapRawPropTo('opacity'),
textAlign: mapRawPropTo('text-align'),
verticalAlign: mapRawPropTo('vertical-align'),
diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.js
index 52adf286ad..bb8b4bcbf0 100644
--- a/tgui/packages/tgui/components/Button.js
+++ b/tgui/packages/tgui/components/Button.js
@@ -6,7 +6,6 @@
import { classes, pureComponentHooks } from 'common/react';
import { Component, createRef } from 'inferno';
-import { IS_IE8 } from '../byond';
import { KEY_ENTER, KEY_ESCAPE, KEY_SPACE } from '../hotkeys';
import { refocusLayout } from '../layouts';
import { createLogger } from '../logging';
@@ -61,7 +60,7 @@ export const Button = props => {
className,
])}
tabIndex={!disabled && '0'}
- unselectable={IS_IE8}
+ unselectable={Byond.IS_LTE_IE8}
onclick={e => {
refocusLayout();
if (!disabled && onClick) {
@@ -87,7 +86,10 @@ export const Button = props => {
}}
{...rest}>
{icon && (
-
+
)}
{content}
{children}
diff --git a/tgui/packages/tgui/components/ByondUi.js b/tgui/packages/tgui/components/ByondUi.js
index db9c5822ba..2369cc7993 100644
--- a/tgui/packages/tgui/components/ByondUi.js
+++ b/tgui/packages/tgui/components/ByondUi.js
@@ -7,7 +7,6 @@
import { shallowDiffers } from 'common/react';
import { debounce } from 'common/timer';
import { Component, createRef } from 'inferno';
-import { callByond, IS_IE8 } from '../byond';
import { createLogger } from '../logging';
import { computeBoxProps } from './Box';
@@ -28,16 +27,12 @@ const createByondUiElement = elementId => {
render: params => {
logger.log(`rendering '${id}'`);
byondUiStack[index] = id;
- callByond('winset', {
- ...params,
- id,
- });
+ Byond.winset(id, params);
},
unmount: () => {
logger.log(`unmounting '${id}'`);
byondUiStack[index] = null;
- callByond('winset', {
- id,
+ Byond.winset(id, {
parent: '',
});
},
@@ -51,8 +46,7 @@ window.addEventListener('beforeunload', () => {
if (typeof id === 'string') {
logger.log(`unmounting '${id}' (beforeunload)`);
byondUiStack[index] = null;
- callByond('winset', {
- id,
+ Byond.winset(id, {
parent: '',
});
}
@@ -83,7 +77,7 @@ export class ByondUi extends Component {
this.byondUiElement = createByondUiElement(props.params?.id);
this.handleResize = debounce(() => {
this.forceUpdate();
- }, 500);
+ }, 100);
}
shouldComponentUpdate(nextProps) {
@@ -101,16 +95,17 @@ export class ByondUi extends Component {
componentDidMount() {
// IE8: It probably works, but fuck you anyway.
- if (IS_IE8) {
+ if (Byond.IS_LTE_IE10) {
return;
}
window.addEventListener('resize', this.handleResize);
- return this.componentDidUpdate();
+ this.componentDidUpdate();
+ this.handleResize();
}
componentDidUpdate() {
// IE8: It probably works, but fuck you anyway.
- if (IS_IE8) {
+ if (Byond.IS_LTE_IE10) {
return;
}
const {
@@ -119,6 +114,7 @@ export class ByondUi extends Component {
const box = getBoundingBox(this.containerRef.current);
logger.log('bounding box', box);
this.byondUiElement.render({
+ parent: window.__windowId__,
...params,
pos: box.pos[0] + ',' + box.pos[1],
size: box.size[0] + 'x' + box.size[1],
@@ -127,7 +123,7 @@ export class ByondUi extends Component {
componentWillUnmount() {
// IE8: It probably works, but fuck you anyway.
- if (IS_IE8) {
+ if (Byond.IS_LTE_IE10) {
return;
}
window.removeEventListener('resize', this.handleResize);
@@ -135,26 +131,16 @@ export class ByondUi extends Component {
}
render() {
- const {
- parent,
- params,
- ...rest
- } = this.props;
+ const { params, ...rest } = this.props;
const type = params?.type;
const boxProps = computeBoxProps(rest);
return (
- {type === 'button' && }
+ {/* Filler */}
+
);
}
}
-
-const ButtonMock = () => (
-
-);
diff --git a/tgui/packages/tgui/components/Chart.js b/tgui/packages/tgui/components/Chart.js
index 16ed82c355..77913779db 100644
--- a/tgui/packages/tgui/components/Chart.js
+++ b/tgui/packages/tgui/components/Chart.js
@@ -7,7 +7,6 @@
import { map, zipWith } from 'common/collections';
import { pureComponentHooks } from 'common/react';
import { Component, createRef } from 'inferno';
-import { IS_IE8 } from '../byond';
import { Box } from './Box';
const normalizeData = (data, scale, rangeX, rangeY) => {
@@ -123,5 +122,5 @@ const Stub = props => null;
// IE8: No inline svg support
export const Chart = {
- Line: IS_IE8 ? Stub : LineChart,
+ Line: Byond.IS_LTE_IE8 ? Stub : LineChart,
};
diff --git a/tgui/packages/tgui/components/Flex.js b/tgui/packages/tgui/components/Flex.js
index 4ee69a1902..02d2fac314 100644
--- a/tgui/packages/tgui/components/Flex.js
+++ b/tgui/packages/tgui/components/Flex.js
@@ -5,7 +5,6 @@
*/
import { classes, pureComponentHooks } from 'common/react';
-import { IS_IE8 } from '../byond';
import { Box, unit } from './Box';
export const computeFlexProps = props => {
@@ -22,10 +21,10 @@ export const computeFlexProps = props => {
return {
className: classes([
'Flex',
- IS_IE8 && (
+ Byond.IS_LTE_IE10 && (
direction === 'column'
- ? 'Flex--ie8--column'
- : 'Flex--ie8'
+ ? 'Flex--iefix--column'
+ : 'Flex--iefix'
),
inline && 'Flex--inline',
spacing > 0 && 'Flex--spacing--' + spacing,
@@ -63,7 +62,7 @@ export const computeFlexItemProps = props => {
return {
className: classes([
'Flex__item',
- IS_IE8 && 'Flex__item--ie8',
+ Byond.IS_LTE_IE10 && 'Flex__item--iefix',
className,
]),
style: {
diff --git a/tgui/packages/tgui/components/Knob.js b/tgui/packages/tgui/components/Knob.js
index e72b15f195..4861e71bf3 100644
--- a/tgui/packages/tgui/components/Knob.js
+++ b/tgui/packages/tgui/components/Knob.js
@@ -6,7 +6,6 @@
import { keyOfMatchingRange, scale } from 'common/math';
import { classes } from 'common/react';
-import { IS_IE8 } from '../byond';
import { computeBoxClassName, computeBoxProps } from './Box';
import { DraggableControl } from './DraggableControl';
import { NumberInput } from './NumberInput';
@@ -14,7 +13,7 @@ import { NumberInput } from './NumberInput';
export const Knob = props => {
// IE8: I don't want to support a yet another component on IE8.
// IE8: It also can't handle SVG.
- if (IS_IE8) {
+ if (Byond.IS_LTE_IE8) {
return (
);
diff --git a/tgui/packages/tgui/components/NumberInput.js b/tgui/packages/tgui/components/NumberInput.js
index 806c81d542..cba6f5025e 100644
--- a/tgui/packages/tgui/components/NumberInput.js
+++ b/tgui/packages/tgui/components/NumberInput.js
@@ -7,7 +7,6 @@
import { clamp } from 'common/math';
import { classes, pureComponentHooks } from 'common/react';
import { Component, createRef } from 'inferno';
-import { IS_IE8 } from '../byond';
import { AnimatedNumber } from './AnimatedNumber';
import { Box } from './Box';
@@ -168,7 +167,7 @@ export class NumberInput extends Component {
const renderContentElement = value => (