diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm
index 7d422677278e6..faa5cf18ae978 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm
@@ -54,6 +54,10 @@
/obj/structure/chair/comfy{
dir = 1
},
+/obj/effect/decal/remains/human/smokey{
+ pixel_x = -3;
+ pixel_y = 9
+ },
/turf/open/floor/carpet/blue,
/area/ruin/smoking_room/room)
"k" = (
@@ -245,11 +249,6 @@
/turf/open/misc/asteroid/snow/icemoon,
/area/icemoon/surface/outdoors/nospawn)
"R" = (
-/obj/effect/spawner/random/entertainment/cigarette_pack,
-/obj/effect/decal/cleanable/ash/large{
- pixel_x = -1;
- pixel_y = 5
- },
/obj/structure/showcase/machinery/tv/broken,
/turf/open/floor/carpet/blue,
/area/ruin/smoking_room/room)
@@ -279,17 +278,12 @@
/turf/open/floor/stone,
/area/ruin/smoking_room/house)
"W" = (
-/obj/effect/spawner/random/entertainment/cigarette_pack,
/obj/structure/chair/plastic{
dir = 8
},
/obj/effect/spawner/random/entertainment/cigarette_pack,
/obj/effect/decal/cleanable/ash/large,
/obj/structure/sign/calendar/directional/east,
-/obj/effect/decal/remains/human/smokey{
- pixel_x = -3;
- pixel_y = 9
- },
/turf/open/floor/carpet/blue,
/area/ruin/smoking_room/room)
"X" = (
diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm
index a636b7220cab5..33c5893bcee4c 100644
--- a/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm
+++ b/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm
@@ -78,7 +78,7 @@
/turf/open/floor/plating,
/area/ruin/space/has_grav/garbagetruck/toystore)
"hH" = (
-/obj/structure/spider/solid,
+/obj/structure/spider/stickyweb/sealed/tough,
/obj/item/book/manual/wiki/cytology,
/obj/effect/decal/cleanable/plastic,
/turf/open/floor/plating,
@@ -122,7 +122,7 @@
/area/ruin/space/has_grav/garbagetruck/toystore)
"lm" = (
/obj/structure/spider/stickyweb,
-/obj/structure/spider/sticky,
+/obj/structure/spider/stickyweb/very_sticky,
/turf/open/floor/plating,
/area/ruin/space/has_grav/garbagetruck/toystore)
"mf" = (
@@ -182,7 +182,7 @@
/turf/open/floor/plating,
/area/ruin/space/has_grav/garbagetruck/toystore)
"qX" = (
-/obj/structure/spider/sticky,
+/obj/structure/spider/stickyweb/very_sticky,
/obj/item/food/badrecipe/moldy,
/obj/structure/spider/stickyweb,
/obj/item/food/spidereggs{
@@ -255,7 +255,7 @@
/turf/open/floor/plating,
/area/ruin/space/has_grav/garbagetruck/toystore)
"ts" = (
-/obj/structure/spider/solid,
+/obj/structure/spider/stickyweb/sealed/tough,
/obj/structure/spider/stickyweb,
/obj/structure/closet/crate/trashcart/filled,
/turf/open/floor/plating,
@@ -841,7 +841,7 @@
/turf/open/floor/plating,
/area/ruin/space/has_grav/garbagetruck/toystore)
"XI" = (
-/obj/structure/spider/solid,
+/obj/structure/spider/stickyweb/sealed/tough,
/obj/item/food/badrecipe/moldy/bacteria,
/turf/open/floor/plating,
/area/ruin/space/has_grav/garbagetruck/toystore)
diff --git a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm
index 0c4e9cd740b37..3e4bece11e8e5 100644
--- a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm
+++ b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm
@@ -733,7 +733,7 @@
/turf/open/indestructible/white,
/area/ruin/space/has_grav/powered/biooutpost)
"oQ" = (
-/obj/machinery/puzzle_button/meatderelict{
+/obj/machinery/puzzle/button/meatderelict{
pixel_y = 32;
queue_size = 4
},
@@ -1669,7 +1669,7 @@
"FI" = (
/obj/item/instrument/piano_synth/headphones,
/obj/structure/table,
-/obj/machinery/puzzle_button/directional/north{
+/obj/machinery/puzzle/button/directional/north{
used = 1
},
/obj/effect/turf_decal/tile/neutral/opposingcorners,
@@ -1820,7 +1820,7 @@
/turf/open/floor/iron/dark/textured_large,
/area/ruin/space/has_grav/powered/biooutpost/vault)
"Jt" = (
-/obj/machinery/puzzle_button/directional/north{
+/obj/machinery/puzzle/button/directional/north{
id = "md_tosci";
name = "shield power panel"
},
@@ -1889,7 +1889,7 @@
/turf/open/indestructible/white,
/area/ruin/space/has_grav/powered/biooutpost)
"KC" = (
-/obj/machinery/puzzle_button/directional/north{
+/obj/machinery/puzzle/button/directional/north{
id = "md_toeng";
queue_size = 4
},
@@ -2138,7 +2138,7 @@
id = "md_armory"
},
/obj/effect/turf_decal/stripes/full,
-/obj/machinery/puzzle_keycardpad/directional/south{
+/obj/machinery/puzzle/keycardpad/directional/south{
id = "md_armory";
name = "armory authentication pad";
queue_size = 5
diff --git a/_maps/RandomZLevels/museum.dmm b/_maps/RandomZLevels/museum.dmm
index f40ecc09015c6..64fd580b80f78 100644
--- a/_maps/RandomZLevels/museum.dmm
+++ b/_maps/RandomZLevels/museum.dmm
@@ -9,11 +9,18 @@
/obj/machinery/computer/old{
name = "replica computer";
dir = 8;
- icon_keyboard = "rd_key";
- icon_screen = "rdcomp"
+ icon_screen = "rdcomp";
+ icon_keyboard = "rd_key"
},
/turf/open/floor/iron/smooth_large,
/area/awaymission/museum)
+"ac" = (
+/obj/structure/sign/poster/contraband/fake_bombable/directional/west,
+/obj/structure/closet/crate/bin,
+/obj/machinery/light/warm/directional/south,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"ai" = (
/obj/structure/railing{
dir = 8
@@ -59,6 +66,11 @@
},
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"ax" = (
+/obj/structure/sink/directional/north,
+/obj/structure/mirror/directional/south,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"az" = (
/obj/structure/table/reinforced,
/obj/effect/spawner/random/entertainment/musical_instrument,
@@ -76,6 +88,22 @@
/obj/structure/closet/crate/preopen,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"aO" = (
+/obj/machinery/button/door/directional/north{
+ name = "Lock Control";
+ id = "museum_toilet_wontwork"
+ },
+/obj/effect/mob_spawn/corpse/human/skeleton/museum_chef,
+/obj/structure/toilet/museum{
+ dir = 4
+ },
+/obj/item/keycard/cafeteria,
+/obj/item/paper/fluff/museum/chefs_ultimatum,
+/obj/machinery/light/small/dim/directional/west,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/cleanable/cobweb,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"aR" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -147,8 +175,8 @@
},
/turf/open/mirage{
dir = 8;
- target_turf_x = 11;
- range = 1
+ range = 1;
+ target_turf_x = 11
},
/area/awaymission/museum)
"bC" = (
@@ -177,8 +205,8 @@
/area/awaymission/museum)
"bJ" = (
/mob/living/basic/statue/mannequin{
- dir = 8;
- name = "Dale Knox"
+ name = "Dale Knox";
+ dir = 8
},
/obj/effect/turf_decal/tile/blue/opposingcorners,
/turf/open/floor/holofloor/white,
@@ -229,6 +257,14 @@
/obj/item/storage/box/stickers/googly,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"ci" = (
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"cm" = (
/obj/machinery/door/airlock/grunge,
/obj/structure/barricade/wooden/crude,
@@ -255,8 +291,8 @@
/turf/open/floor/iron/smooth_half,
/area/awaymission/museum)
"ct" = (
-/obj/structure/chair/comfy,
/mob/living/basic/mothroach,
+/obj/structure/chair/comfy,
/obj/effect/mapping_helpers/mob_buckler,
/obj/machinery/light/dim/directional/north,
/turf/open/floor/iron/dark/textured_large,
@@ -313,8 +349,8 @@
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/item/toy/balloon/corgi,
/obj/machinery/status_display/random_message{
- firstline_to_secondline = list("NO" = "LITTERING","YOU ARE" = "BEING WATCHED", "DO NOT TOUCH" = "THE EXHIBITS");
- pixel_x = 32
+ pixel_x = 32;
+ firstline_to_secondline = list(NO="LITTERING", "YOU ARE"="BEING WATCHED", "DO NOT TOUCH"="THE EXHIBITS")
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -328,9 +364,9 @@
"cS" = (
/obj/effect/step_trigger/thrower{
direction = 1;
- facedir = 1;
+ mobs_only = 1;
tiles = 10;
- mobs_only = 1
+ facedir = 1
},
/obj/machinery/light/floor,
/turf/open/floor/iron,
@@ -343,6 +379,14 @@
/obj/structure/plaque/static_plaque/golden/commission/dream,
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
+"cY" = (
+/obj/structure/fluff/fake_camera{
+ dir = 5
+ },
+/obj/machinery/light/warm/directional/east,
+/obj/structure/fluff/fake_scrubber,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"cZ" = (
/obj/structure/fluff/divine/nexus,
/turf/open/floor/cult,
@@ -398,9 +442,9 @@
/area/awaymission/museum)
"dK" = (
/turf/open/mirage{
+ dir = 1;
range = 2;
- target_turf_y = -4;
- dir = 1
+ target_turf_y = -4
},
/area/awaymission/museum)
"dL" = (
@@ -434,8 +478,8 @@
/area/awaymission/museum)
"dY" = (
/mob/living/basic/statue/mannequin{
- hat = /obj/item/clothing/head/helmet/space;
- dir = 1
+ dir = 1;
+ hat = /obj/item/clothing/head/helmet/space
},
/turf/open/floor/holofloor/hyperspace/ns,
/area/awaymission/museum)
@@ -462,7 +506,7 @@
/obj/machinery/door/poddoor/shutters/indestructible{
id = "museum_secret"
},
-/obj/machinery/puzzle_keycardpad/directional/east{
+/obj/machinery/puzzle/keycardpad/directional/east{
id = "museum_secret"
},
/turf/open/floor/iron/dark,
@@ -521,10 +565,10 @@
/turf/open/floor/grass,
/area/awaymission/museum)
"ex" = (
+/mob/living/basic/mothroach,
/obj/structure/chair/stool/bar/directional/west{
can_buckle = 1
},
-/mob/living/basic/mothroach,
/obj/effect/mapping_helpers/mob_buckler,
/turf/open/floor/wood/large,
/area/awaymission/museum)
@@ -596,6 +640,15 @@
/obj/structure/plaque/static_plaque/golden/commission/omega,
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
+"eW" = (
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/effect/turf_decal/siding/dark_blue,
+/obj/structure/fluff/wallsign/directional/north{
+ name = "Restrooms";
+ dir = 4
+ },
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"eX" = (
/obj/effect/turf_decal/siding/wideplating{
dir = 4
@@ -605,11 +658,11 @@
},
/area/awaymission/museum)
"fa" = (
-/obj/effect/turf_decal/sand/plating,
/mob/living/basic/statue/mannequin{
held_item = /obj/item/pickaxe;
hat = /obj/item/clothing/suit/hooded/explorer
},
+/obj/effect/turf_decal/sand/plating,
/obj/effect/turf_decal/mining,
/turf/open/indestructible/plating,
/area/awaymission/museum)
@@ -627,6 +680,13 @@
/obj/item/kitchen/fork,
/turf/open/floor/wood/tile,
/area/awaymission/museum)
+"fl" = (
+/obj/machinery/status_display/random_message{
+ pixel_x = -32;
+ firstline_to_secondline = list(CAFETERIA="YUMMY", CAFETERIA="HOTDOGS", ENJOY="YOUR MEAL")
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"fn" = (
/turf/open/floor/holofloor/hyperspace/ns,
/area/awaymission/museum)
@@ -706,6 +766,11 @@
},
/turf/open/floor/iron,
/area/awaymission/museum)
+"gg" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/machinery/shower/directional/east,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"gj" = (
/obj/machinery/door/poddoor/shutters/preopen{
dir = 8
@@ -751,6 +816,10 @@
/obj/machinery/light/small/dim/directional/south,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"gE" = (
+/obj/item/clothing/suit/caution,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"gG" = (
/obj/effect/turf_decal/siding/dark_blue/corner{
dir = 4
@@ -814,8 +883,8 @@
"hk" = (
/obj/effect/smooths_with_walls,
/turf/open/mirage{
- target_turf_y = -29;
- dir = 1
+ dir = 1;
+ target_turf_y = -29
},
/area/awaymission/museum)
"hl" = (
@@ -827,6 +896,12 @@
},
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"hm" = (
+/obj/structure/table,
+/obj/effect/spawner/random/food_or_drink/condiment,
+/obj/machinery/light/floor,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"hp" = (
/mob/living/basic/mothroach/bar,
/turf/open/floor/wood/tile,
@@ -874,10 +949,18 @@
"hM" = (
/turf/closed/wall/rock/porous,
/area/awaymission/museum)
+"hS" = (
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 5
+ },
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"hT" = (
/mob/living/basic/statue/mannequin{
- dir = 8;
name = "Dale Knox";
+ dir = 8;
held_item = /obj/item/circuitboard
},
/obj/structure/sign/flag/nanotrasen/directional/south,
@@ -892,8 +975,8 @@
/area/awaymission/museum)
"hX" = (
/obj/item/circuitboard{
- icon_state = "flopdrive";
- name = "microprocessor"
+ name = "microprocessor";
+ icon_state = "flopdrive"
},
/obj/structure/table/reinforced,
/turf/open/floor/circuit/green,
@@ -983,6 +1066,15 @@
/obj/machinery/light/floor,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"iJ" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/structure/toilet/museum{
+ dir = 1
+ },
+/obj/structure/curtain,
+/obj/structure/broken_flooring/plating,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"iK" = (
/obj/effect/turf_decal/sand/plating,
/obj/effect/turf_decal/siding{
@@ -1031,9 +1123,9 @@
},
/obj/effect/step_trigger/thrower{
direction = 1;
- facedir = 1;
+ mobs_only = 1;
tiles = 10;
- mobs_only = 1
+ facedir = 1
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -1067,10 +1159,20 @@
},
/turf/open/floor/cult,
/area/awaymission/museum)
+"ju" = (
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 6
+ },
+/obj/structure/fluff/wallsign/directional/north{
+ name = "Restrooms"
+ },
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"jy" = (
/mob/living/basic/statue/mannequin{
- dir = 8;
name = "Dale Knox";
+ dir = 8;
held_item = /obj/item/circuitboard
},
/obj/effect/turf_decal/stripes{
@@ -1082,6 +1184,14 @@
/obj/effect/spawner/structure/window,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"jC" = (
+/obj/effect/puzzle_poddoor_open{
+ icon = 'icons/effects/mapping_helpers.dmi';
+ id = "museum_right_wing";
+ queue_id = "museum_right_wing"
+ },
+/turf/closed/indestructible/reinforced,
+/area/awaymission/museum)
"jF" = (
/obj/machinery/suit_storage_unit/open,
/obj/effect/turf_decal/box,
@@ -1110,6 +1220,18 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"jO" = (
+/obj/structure/toilet/museum,
+/obj/structure/sign/poster/contraband/fake_bombable/directional/north,
+/obj/machinery/button/door/directional/east{
+ name = "Lock Control";
+ id = "museum_toilet6";
+ specialfunctions = 4;
+ normaldoorcontrol = 1
+ },
+/obj/machinery/light/small/dim/directional/north,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"jP" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue/corner{
@@ -1120,13 +1242,16 @@
dir = 9
},
/obj/item/reagent_containers/cup/glass/coffee,
+/obj/item/paper/fluff/scrambled_pass{
+ puzzle_id = "museum_r_wing_puzzle"
+ },
/turf/open/floor/iron/dark,
/area/awaymission/museum)
"jU" = (
/obj/effect/landmark/transport/nav_beacon/tram/platform{
+ name = "Exhibit Loading Bay";
specific_transport_id = "museum_cargo";
- platform_code = 2;
- name = "Exhibit Loading Bay"
+ platform_code = 2
},
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
@@ -1193,6 +1318,12 @@
},
/turf/open/floor/iron,
/area/awaymission/museum)
+"kx" = (
+/obj/machinery/door/airlock/public{
+ name = "Restrooms"
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum)
"kA" = (
/obj/machinery/conveyor{
dir = 1
@@ -1200,6 +1331,16 @@
/obj/item/vending_refill/wardrobe/coroner_wardrobe,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"kL" = (
+/obj/machinery/door/poddoor/shutters/window/indestructible{
+ dir = 8;
+ id = "museum_cafeteria"
+ },
+/obj/machinery/puzzle/keycardpad/directional/south{
+ id = "museum_cafeteria"
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum)
"kO" = (
/obj/structure/railing{
dir = 8
@@ -1227,6 +1368,19 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"kZ" = (
+/obj/structure/toilet/museum{
+ dir = 4
+ },
+/obj/machinery/button/door/directional/north{
+ name = "Lock Control";
+ id = "museum_toilet5";
+ specialfunctions = 4;
+ normaldoorcontrol = 1
+ },
+/obj/machinery/light/small/dim/directional/west,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"la" = (
/obj/effect/turf_decal/siding/wood{
dir = 4
@@ -1324,11 +1478,11 @@
/turf/open/floor/iron,
/area/awaymission/museum)
"lT" = (
-/obj/structure/chair/office{
- dir = 1
- },
/mob/living/basic/statue/mannequin{
- hat = /obj/item/clothing/suit/toggle/labcoat/science;
+ dir = 1;
+ hat = /obj/item/clothing/suit/toggle/labcoat/science
+ },
+/obj/structure/chair/office{
dir = 1
},
/obj/machinery/light/floor,
@@ -1345,9 +1499,9 @@
specific_transport_id = "museum_cargo"
},
/obj/effect/landmark/transport/nav_beacon/tram/platform{
+ name = "Internal Loading Bay";
specific_transport_id = "museum_cargo";
- platform_code = 1;
- name = "Internal Loading Bay"
+ platform_code = 1
},
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
@@ -1379,6 +1533,9 @@
},
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
+"ms" = (
+/turf/open/floor/iron,
+/area/awaymission/museum/cafeteria)
"mA" = (
/obj/structure/window/reinforced/spawner/directional/west,
/turf/open/floor/holofloor/beach/water,
@@ -1403,9 +1560,9 @@
/area/awaymission/museum)
"mS" = (
/mob/living/basic/statue/mannequin{
+ dir = 1;
held_item = /obj/item/wrench;
- hat = /obj/item/clothing/head/utility/hardhat;
- dir = 1
+ hat = /obj/item/clothing/head/utility/hardhat
},
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/blood/gibs,
@@ -1436,8 +1593,8 @@
/obj/structure/transport/linear/tram/slow,
/obj/structure/tram,
/obj/machinery/transport/tram_controller{
- configured_transport_id = "museum_cargo";
- cover_locked = 0
+ cover_locked = 0;
+ configured_transport_id = "museum_cargo"
},
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
@@ -1477,8 +1634,8 @@
/turf/open/floor/iron/white,
/area/awaymission/museum)
"nu" = (
-/obj/effect/decal/cleanable/glass/titanium,
/mob/living/basic/mouse/rat,
+/obj/effect/decal/cleanable/glass/titanium,
/turf/open/floor/iron/white,
/area/awaymission/museum)
"nv" = (
@@ -1510,9 +1667,9 @@
"nz" = (
/obj/structure/lattice/catwalk/mining,
/obj/structure/fluff{
+ name = "old plasma extractor";
icon = 'icons/mob/simple/hivebot.dmi';
- icon_state = "fab_robot";
- name = "old plasma extractor"
+ icon_state = "fab_robot"
},
/turf/open/lava/plasma/mafia,
/area/awaymission/museum)
@@ -1537,9 +1694,9 @@
},
/obj/effect/step_trigger/thrower{
direction = 1;
- facedir = 1;
+ mobs_only = 1;
tiles = 10;
- mobs_only = 1
+ facedir = 1
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -1588,6 +1745,16 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"nY" = (
+/obj/structure/sign/poster/official/no_erp/directional/north,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
+"nZ" = (
+/obj/structure/chair/sofa/bench/left{
+ dir = 1
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"od" = (
/obj/structure/fluff/fake_vent,
/turf/open/floor/iron,
@@ -1648,11 +1815,31 @@
/obj/structure/flora/coconuts,
/turf/open/misc/beach/sand,
/area/awaymission/museum/mothroachvoid)
+"oD" = (
+/obj/structure/toilet/museum{
+ dir = 4
+ },
+/obj/machinery/button/door/directional/north{
+ name = "Lock Control";
+ id = "museum_toilet4";
+ specialfunctions = 4;
+ normaldoorcontrol = 1
+ },
+/obj/machinery/light/small/dim/directional/west,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"oI" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/machinery/light/floor,
/turf/open/floor/iron,
/area/awaymission/museum)
+"oP" = (
+/obj/effect/puzzle_poddoor_open{
+ id = "museum_cafeteria";
+ queue_id = "museum_cafeteria"
+ },
+/turf/closed/indestructible/reinforced,
+/area/awaymission/museum)
"oQ" = (
/turf/open/floor/holofloor/beach/coast{
dir = 1
@@ -1694,8 +1881,8 @@
/area/awaymission/museum)
"pi" = (
/mob/living/basic/statue/mannequin{
- hat = /obj/item/clothing/head/costume/nursehat;
- held_item = /obj/item/clothing/neck/stethoscope
+ held_item = /obj/item/clothing/neck/stethoscope;
+ hat = /obj/item/clothing/head/costume/nursehat
},
/obj/effect/turf_decal/tile/blue/opposingcorners,
/turf/open/floor/holofloor/white,
@@ -1729,6 +1916,13 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/white,
/area/awaymission/museum)
+"pz" = (
+/obj/machinery/door/poddoor/shutters/window/indestructible{
+ dir = 8;
+ id = "museum_cafeteria"
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum)
"pD" = (
/obj/structure/broken_flooring/corner/always_floorplane/directional/west,
/obj/effect/decal/cleanable/dirt/dust,
@@ -1758,6 +1952,17 @@
},
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"pN" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 6
+ },
+/obj/structure/fluff/fake_camera{
+ dir = 4
+ },
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"pX" = (
/obj/structure/rack,
/obj/effect/spawner/random/maintenance/two,
@@ -1773,6 +1978,10 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron,
/area/awaymission/museum)
+"ql" = (
+/obj/structure/chair/sofa/bench,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"qo" = (
/obj/effect/oneway{
dir = 8
@@ -1784,15 +1993,15 @@
/area/awaymission/museum)
"qt" = (
/obj/effect/spawner/random/food_or_drink/booze{
- loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer = 10, /obj/item/reagent_containers/cup/glass/bottle/ale = 10, /obj/item/reagent_containers/cup/glass/bottle/beer/light = 5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor = 5, /obj/item/reagent_containers/cup/glass/bottle/whiskey = 5, /obj/item/reagent_containers/cup/glass/bottle/gin = 5, /obj/item/reagent_containers/cup/glass/bottle/vodka = 5, /obj/item/reagent_containers/cup/glass/bottle/tequila = 5, /obj/item/reagent_containers/cup/glass/bottle/rum = 5, /obj/item/reagent_containers/cup/glass/bottle/vermouth = 5, /obj/item/reagent_containers/cup/glass/bottle/cognac = 5, /obj/item/reagent_containers/cup/glass/bottle/wine = 5, /obj/item/reagent_containers/cup/glass/bottle/kahlua = 5, /obj/item/reagent_containers/cup/glass/bottle/amaretto = 5, /obj/item/reagent_containers/cup/glass/bottle/hcider = 5, /obj/item/reagent_containers/cup/glass/bottle/absinthe = 5, /obj/item/reagent_containers/cup/glass/bottle/sake = 5, /obj/item/reagent_containers/cup/glass/bottle/grappa = 5, /obj/item/reagent_containers/cup/glass/bottle/applejack = 5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic = 5, /obj/item/reagent_containers/cup/bottle/ethanol = 2, /obj/item/reagent_containers/cup/glass/bottle/fernet = 2, /obj/item/reagent_containers/cup/glass/bottle/champagne = 2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium = 2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager = 2, /obj/item/reagent_containers/cup/glass/bottle/patron = 1, /obj/item/reagent_containers/cup/glass/bottle/kong = 1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1, /obj/item/reagent_containers/cup/glass/bottle/trappist = 1);
+ loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer=10, /obj/item/reagent_containers/cup/glass/bottle/ale=10, /obj/item/reagent_containers/cup/glass/bottle/beer/light=5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor=5, /obj/item/reagent_containers/cup/glass/bottle/whiskey=5, /obj/item/reagent_containers/cup/glass/bottle/gin=5, /obj/item/reagent_containers/cup/glass/bottle/vodka=5, /obj/item/reagent_containers/cup/glass/bottle/tequila=5, /obj/item/reagent_containers/cup/glass/bottle/rum=5, /obj/item/reagent_containers/cup/glass/bottle/vermouth=5, /obj/item/reagent_containers/cup/glass/bottle/cognac=5, /obj/item/reagent_containers/cup/glass/bottle/wine=5, /obj/item/reagent_containers/cup/glass/bottle/kahlua=5, /obj/item/reagent_containers/cup/glass/bottle/amaretto=5, /obj/item/reagent_containers/cup/glass/bottle/hcider=5, /obj/item/reagent_containers/cup/glass/bottle/absinthe=5, /obj/item/reagent_containers/cup/glass/bottle/sake=5, /obj/item/reagent_containers/cup/glass/bottle/grappa=5, /obj/item/reagent_containers/cup/glass/bottle/applejack=5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic=5, /obj/item/reagent_containers/cup/bottle/ethanol=2, /obj/item/reagent_containers/cup/glass/bottle/fernet=2, /obj/item/reagent_containers/cup/glass/bottle/champagne=2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium=2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager=2, /obj/item/reagent_containers/cup/glass/bottle/patron=1, /obj/item/reagent_containers/cup/glass/bottle/kong=1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine=1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka=1, /obj/item/reagent_containers/cup/glass/bottle/trappist=1);
spawn_random_offset = 2
},
/turf/open/floor/carpet/cyan,
/area/awaymission/museum/mothroachvoid)
"qw" = (
/obj/item/flashlight/flare{
- start_on = 1;
- icon_state = "flare-on"
+ icon_state = "flare-on";
+ start_on = 1
},
/obj/structure/table,
/obj/effect/decal/cleanable/dirt/dust,
@@ -1822,6 +2031,10 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine,
/area/awaymission/museum)
+"qK" = (
+/obj/machinery/vending/hotdog/museum,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"qL" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -1879,8 +2092,8 @@
/area/awaymission/museum)
"qY" = (
/obj/machinery/power/shuttle_engine/heater{
- dir = 4;
- opacity = 1
+ opacity = 1;
+ dir = 4
},
/obj/structure/window/reinforced/spawner/directional/west,
/turf/open/indestructible/plating,
@@ -1909,22 +2122,29 @@
/turf/open/floor/carpet/executive,
/area/awaymission/museum)
"rq" = (
+/mob/living/basic/statue/mannequin/suspicious,
/obj/effect/decal/cleanable/blood/old,
/obj/effect/gibspawner/human,
/obj/effect/gibspawner/human,
/obj/effect/gibspawner/human,
/obj/effect/gibspawner/human,
-/mob/living/basic/statue/mannequin/suspicious,
/turf/open/floor/iron,
/area/awaymission/museum)
"rr" = (
/turf/open/floor/wood/tile,
/area/awaymission/museum)
+"ry" = (
+/obj/machinery/door/airlock{
+ name = "Restroom Cabin 6";
+ id_tag = "museum_toilet6"
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"rA" = (
+/mob/living/basic/mothroach,
/obj/structure/chair/comfy/beige{
dir = 8
},
-/mob/living/basic/mothroach,
/obj/effect/mapping_helpers/mob_buckler,
/turf/open/floor/wood/large,
/area/awaymission/museum)
@@ -1964,13 +2184,17 @@
dir = 1
},
/obj/structure/railing/corner/end,
+/obj/structure/fluff/wallsign/directional/south{
+ name = "Cafeteria";
+ dir = 4
+ },
/turf/open/floor/iron/dark,
/area/awaymission/museum)
"rU" = (
/mob/living/basic/statue/mannequin{
+ name = "Michael Trasen";
dir = 4;
- held_item = /obj/item/wrench;
- name = "Michael Trasen"
+ held_item = /obj/item/wrench
},
/obj/structure/sign/flag/nanotrasen/directional/south,
/obj/machinery/light/small/dim/directional/west,
@@ -1997,9 +2221,9 @@
/turf/open/floor/engine,
/area/awaymission/museum)
"rY" = (
+/mob/living/basic/mouse/rat,
/obj/machinery/light/small/broken/directional/north,
/obj/effect/decal/cleanable/dirt/dust,
-/mob/living/basic/mouse/rat,
/turf/open/floor/iron/dark/textured_large,
/area/awaymission/museum)
"sd" = (
@@ -2110,13 +2334,20 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"ta" = (
+/obj/machinery/door/airlock{
+ name = "Restroom Cabin 5";
+ id_tag = "museum_toilet5"
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"tc" = (
+/mob/living/basic/mothroach,
/obj/structure/lattice/catwalk/mining,
/obj/structure/railing{
dir = 6
},
/obj/structure/chair,
-/mob/living/basic/mothroach,
/obj/effect/mapping_helpers/mob_buckler,
/turf/open/misc/grass,
/area/awaymission/museum/mothroachvoid)
@@ -2136,15 +2367,15 @@
/turf/open/floor/holofloor/asteroid,
/area/awaymission/museum)
"tj" = (
+/mob/living/basic/statue/mannequin{
+ dir = 1;
+ held_item = /obj/item/wrench;
+ hat = /obj/item/clothing/head/utility/hardhat
+ },
/obj/effect/turf_decal/sand/plating,
/obj/effect/turf_decal/stripes/asteroid/line{
dir = 1
},
-/mob/living/basic/statue/mannequin{
- dir = 1;
- hat = /obj/item/clothing/head/utility/hardhat;
- held_item = /obj/item/wrench
- },
/turf/open/indestructible/plating,
/area/awaymission/museum)
"tk" = (
@@ -2185,7 +2416,7 @@
"tx" = (
/obj/structure/table/wood,
/obj/effect/spawner/random/food_or_drink/booze{
- loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer = 10, /obj/item/reagent_containers/cup/glass/bottle/ale = 10, /obj/item/reagent_containers/cup/glass/bottle/beer/light = 5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor = 5, /obj/item/reagent_containers/cup/glass/bottle/whiskey = 5, /obj/item/reagent_containers/cup/glass/bottle/gin = 5, /obj/item/reagent_containers/cup/glass/bottle/vodka = 5, /obj/item/reagent_containers/cup/glass/bottle/tequila = 5, /obj/item/reagent_containers/cup/glass/bottle/rum = 5, /obj/item/reagent_containers/cup/glass/bottle/vermouth = 5, /obj/item/reagent_containers/cup/glass/bottle/cognac = 5, /obj/item/reagent_containers/cup/glass/bottle/wine = 5, /obj/item/reagent_containers/cup/glass/bottle/kahlua = 5, /obj/item/reagent_containers/cup/glass/bottle/amaretto = 5, /obj/item/reagent_containers/cup/glass/bottle/hcider = 5, /obj/item/reagent_containers/cup/glass/bottle/absinthe = 5, /obj/item/reagent_containers/cup/glass/bottle/sake = 5, /obj/item/reagent_containers/cup/glass/bottle/grappa = 5, /obj/item/reagent_containers/cup/glass/bottle/applejack = 5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic = 5, /obj/item/reagent_containers/cup/bottle/ethanol = 2, /obj/item/reagent_containers/cup/glass/bottle/fernet = 2, /obj/item/reagent_containers/cup/glass/bottle/champagne = 2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium = 2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager = 2, /obj/item/reagent_containers/cup/glass/bottle/patron = 1, /obj/item/reagent_containers/cup/glass/bottle/kong = 1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1, /obj/item/reagent_containers/cup/glass/bottle/trappist = 1);
+ loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer=10, /obj/item/reagent_containers/cup/glass/bottle/ale=10, /obj/item/reagent_containers/cup/glass/bottle/beer/light=5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor=5, /obj/item/reagent_containers/cup/glass/bottle/whiskey=5, /obj/item/reagent_containers/cup/glass/bottle/gin=5, /obj/item/reagent_containers/cup/glass/bottle/vodka=5, /obj/item/reagent_containers/cup/glass/bottle/tequila=5, /obj/item/reagent_containers/cup/glass/bottle/rum=5, /obj/item/reagent_containers/cup/glass/bottle/vermouth=5, /obj/item/reagent_containers/cup/glass/bottle/cognac=5, /obj/item/reagent_containers/cup/glass/bottle/wine=5, /obj/item/reagent_containers/cup/glass/bottle/kahlua=5, /obj/item/reagent_containers/cup/glass/bottle/amaretto=5, /obj/item/reagent_containers/cup/glass/bottle/hcider=5, /obj/item/reagent_containers/cup/glass/bottle/absinthe=5, /obj/item/reagent_containers/cup/glass/bottle/sake=5, /obj/item/reagent_containers/cup/glass/bottle/grappa=5, /obj/item/reagent_containers/cup/glass/bottle/applejack=5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic=5, /obj/item/reagent_containers/cup/bottle/ethanol=2, /obj/item/reagent_containers/cup/glass/bottle/fernet=2, /obj/item/reagent_containers/cup/glass/bottle/champagne=2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium=2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager=2, /obj/item/reagent_containers/cup/glass/bottle/patron=1, /obj/item/reagent_containers/cup/glass/bottle/kong=1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine=1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka=1, /obj/item/reagent_containers/cup/glass/bottle/trappist=1);
spawn_random_offset = 2
},
/turf/open/floor/wood/tile,
@@ -2193,9 +2424,9 @@
"ty" = (
/obj/structure/table,
/obj/item/clothing/gloves/color/yellow{
- siemens_coefficient = 10;
name = "fake stungloves";
- desc = "A crude replica of stungloves. Essentially gloves wrapped with wire. Extremely unsafe."
+ desc = "A crude replica of stungloves. Essentially gloves wrapped with wire. Extremely unsafe.";
+ siemens_coefficient = 10
},
/obj/machinery/light/floor,
/turf/open/floor/iron,
@@ -2293,6 +2524,13 @@
dir = 2
},
/area/awaymission/museum/mothroachvoid)
+"um" = (
+/obj/structure/window/reinforced/spawner/directional/east,
+/obj/structure/sign/warning/fire/directional/west,
+/obj/structure/tank_holder/extinguisher/anti,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"up" = (
/obj/effect/turf_decal/siding/wood{
dir = 4
@@ -2302,6 +2540,21 @@
},
/turf/open/floor/iron/showroomfloor,
/area/awaymission/museum)
+"us" = (
+/obj/machinery/door/airlock{
+ name = "Restroom Cabin 2";
+ id_tag = "museum_toilet2"
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum)
+"ut" = (
+/obj/machinery/light/very_dim/directional/north,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/structure/fluff/fake_vent,
+/obj/structure/mop_bucket,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"uu" = (
/obj/structure/rack,
/obj/effect/spawner/random/engineering/material,
@@ -2315,6 +2568,10 @@
},
/turf/open/floor/grass,
/area/awaymission/museum)
+"uH" = (
+/obj/structure/sign/clock/directional/north,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"uM" = (
/obj/structure/fluff/fake_camera{
dir = 10
@@ -2345,8 +2602,8 @@
"vc" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/structure/sign/painting/large{
- persistence_id = "museumgate_big";
- dir = 1
+ dir = 1;
+ persistence_id = "museumgate_big"
},
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/dark,
@@ -2418,6 +2675,11 @@
/obj/structure/filingcabinet,
/turf/open/floor/iron,
/area/awaymission/museum)
+"vG" = (
+/turf/closed/indestructible/fakedoor{
+ name = "Kitchen"
+ },
+/area/awaymission/museum/cafeteria)
"vM" = (
/mob/living/basic/statue/mannequin{
dir = 1;
@@ -2448,6 +2710,16 @@
/obj/effect/turf_decal/siding/dark_blue,
/turf/open/floor/mineral/titanium/blue,
/area/awaymission/museum)
+"wg" = (
+/obj/machinery/door/airlock{
+ name = "Restroom Cabin 3"
+ },
+/obj/effect/mapping_helpers/airlock/locked,
+/obj/effect/mapping_helpers/airlock_note_placer{
+ note_info = "I'VE WORKED HERE FOR 7 YEARS! JUST TO BE REPLACED BY A VENDING MACHINE?! YOU KNOW WHAT? FUCK YOU, I'VE LOCKED DOWN THE CAFETERIA AND WON'T BE COMING OUT 'TILL YOU GIVE ME MY JOB BACK!"
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum)
"wh" = (
/obj/structure/broken_flooring/corner/always_floorplane/directional/west,
/obj/structure/lattice,
@@ -2456,7 +2728,7 @@
"wi" = (
/obj/machinery/door/poddoor/shutters/indestructible{
dir = 8;
- id = "nothing"
+ id = "museum_secret"
},
/turf/open/floor/iron,
/area/awaymission/museum)
@@ -2526,8 +2798,8 @@
"wN" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/structure/sign/painting/large{
- persistence_id = "museumgate_big";
- dir = 1
+ dir = 1;
+ persistence_id = "museumgate_big"
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -2535,6 +2807,13 @@
/obj/item/kirbyplants/random,
/turf/open/floor/wood/large,
/area/awaymission/museum)
+"wV" = (
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"wZ" = (
/turf/open/misc/beach/coast{
dir = 1
@@ -2558,8 +2837,8 @@
/obj/structure/table/reinforced,
/obj/structure/window/spawner/directional/west,
/obj/effect/spawner/random/bureaucracy/paper{
- spawn_random_offset = 7;
- spawn_loot_count = 8
+ spawn_loot_count = 8;
+ spawn_random_offset = 7
},
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/white,
@@ -2575,8 +2854,8 @@
"xg" = (
/obj/structure/table/reinforced,
/obj/item/circuitboard{
- icon_state = "bluespacearray";
- name = "fancy replica tech"
+ name = "fancy replica tech";
+ icon_state = "bluespacearray"
},
/turf/open/floor/iron/smooth_large,
/area/awaymission/museum)
@@ -2599,6 +2878,10 @@
},
/turf/open/misc/beach/sand,
/area/awaymission/museum/mothroachvoid)
+"xp" = (
+/obj/structure/table,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"xr" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/structure/closet/crate/freezer/food,
@@ -2668,6 +2951,11 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"xO" = (
+/obj/structure/table,
+/obj/item/reagent_containers/cup/soda_cans/canned_laughter,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"xP" = (
/obj/structure/closet/crate/cardboard,
/obj/item/storage/toolbox/artistic,
@@ -2704,10 +2992,10 @@
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
"yi" = (
+/mob/living/basic/mothroach,
/obj/structure/chair/comfy/beige{
dir = 1
},
-/mob/living/basic/mothroach,
/obj/effect/mapping_helpers/mob_buckler,
/turf/open/floor/wood/large,
/area/awaymission/museum)
@@ -2731,9 +3019,9 @@
/turf/open/floor/holofloor/hyperspace/ns,
/area/awaymission/museum)
"yr" = (
+/mob/living/basic/mothroach,
/obj/structure/chair/comfy,
/obj/effect/mapping_helpers/mob_buckler,
-/mob/living/basic/mothroach,
/turf/open/floor/wood/large,
/area/awaymission/museum)
"yu" = (
@@ -2855,14 +3143,14 @@
/turf/closed/indestructible/rock,
/area/awaymission/museum)
"zG" = (
-/obj/structure/chair/office{
- dir = 8
- },
-/obj/effect/turf_decal/siding/red,
/mob/living/basic/statue/mannequin{
dir = 8;
hat = /obj/item/clothing/head/fedora
},
+/obj/structure/chair/office{
+ dir = 8
+ },
+/obj/effect/turf_decal/siding/red,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/smooth_half,
/area/awaymission/museum)
@@ -2891,13 +3179,13 @@
pixel_y = 12
},
/obj/item/stamp/granted{
- pixel_y = 12;
- pixel_x = 8
+ pixel_x = 8;
+ pixel_y = 12
},
/obj/effect/spawner/random/bureaucracy/paper{
- spawn_random_offset = 12;
+ spawn_loot_count = 8;
spawn_scatter_radius = 1;
- spawn_loot_count = 8
+ spawn_random_offset = 12
},
/turf/open/floor/iron,
/area/awaymission/museum)
@@ -3043,8 +3331,8 @@
teleport_y_offset = -30
},
/turf/open/mirage{
- target_turf_y = -29;
- dir = 1
+ dir = 1;
+ target_turf_y = -29
},
/area/awaymission/museum)
"AP" = (
@@ -3054,6 +3342,13 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"AQ" = (
+/obj/machinery/door/airlock{
+ name = "Restroom Cabin 4";
+ id_tag = "museum_toilet4"
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"AR" = (
/obj/structure/railing{
dir = 8
@@ -3217,9 +3512,9 @@
"Cy" = (
/obj/structure/table/wood,
/obj/effect/spawner/random/food_or_drink/booze{
- loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer = 10, /obj/item/reagent_containers/cup/glass/bottle/ale = 10, /obj/item/reagent_containers/cup/glass/bottle/beer/light = 5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor = 5, /obj/item/reagent_containers/cup/glass/bottle/whiskey = 5, /obj/item/reagent_containers/cup/glass/bottle/gin = 5, /obj/item/reagent_containers/cup/glass/bottle/vodka = 5, /obj/item/reagent_containers/cup/glass/bottle/tequila = 5, /obj/item/reagent_containers/cup/glass/bottle/rum = 5, /obj/item/reagent_containers/cup/glass/bottle/vermouth = 5, /obj/item/reagent_containers/cup/glass/bottle/cognac = 5, /obj/item/reagent_containers/cup/glass/bottle/wine = 5, /obj/item/reagent_containers/cup/glass/bottle/kahlua = 5, /obj/item/reagent_containers/cup/glass/bottle/amaretto = 5, /obj/item/reagent_containers/cup/glass/bottle/hcider = 5, /obj/item/reagent_containers/cup/glass/bottle/absinthe = 5, /obj/item/reagent_containers/cup/glass/bottle/sake = 5, /obj/item/reagent_containers/cup/glass/bottle/grappa = 5, /obj/item/reagent_containers/cup/glass/bottle/applejack = 5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic = 5, /obj/item/reagent_containers/cup/bottle/ethanol = 2, /obj/item/reagent_containers/cup/glass/bottle/fernet = 2, /obj/item/reagent_containers/cup/glass/bottle/champagne = 2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium = 2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager = 2, /obj/item/reagent_containers/cup/glass/bottle/patron = 1, /obj/item/reagent_containers/cup/glass/bottle/kong = 1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1, /obj/item/reagent_containers/cup/glass/bottle/trappist = 1);
- spawn_random_offset = 2;
- spawn_loot_count = 2
+ loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer=10, /obj/item/reagent_containers/cup/glass/bottle/ale=10, /obj/item/reagent_containers/cup/glass/bottle/beer/light=5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor=5, /obj/item/reagent_containers/cup/glass/bottle/whiskey=5, /obj/item/reagent_containers/cup/glass/bottle/gin=5, /obj/item/reagent_containers/cup/glass/bottle/vodka=5, /obj/item/reagent_containers/cup/glass/bottle/tequila=5, /obj/item/reagent_containers/cup/glass/bottle/rum=5, /obj/item/reagent_containers/cup/glass/bottle/vermouth=5, /obj/item/reagent_containers/cup/glass/bottle/cognac=5, /obj/item/reagent_containers/cup/glass/bottle/wine=5, /obj/item/reagent_containers/cup/glass/bottle/kahlua=5, /obj/item/reagent_containers/cup/glass/bottle/amaretto=5, /obj/item/reagent_containers/cup/glass/bottle/hcider=5, /obj/item/reagent_containers/cup/glass/bottle/absinthe=5, /obj/item/reagent_containers/cup/glass/bottle/sake=5, /obj/item/reagent_containers/cup/glass/bottle/grappa=5, /obj/item/reagent_containers/cup/glass/bottle/applejack=5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic=5, /obj/item/reagent_containers/cup/bottle/ethanol=2, /obj/item/reagent_containers/cup/glass/bottle/fernet=2, /obj/item/reagent_containers/cup/glass/bottle/champagne=2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium=2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager=2, /obj/item/reagent_containers/cup/glass/bottle/patron=1, /obj/item/reagent_containers/cup/glass/bottle/kong=1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine=1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka=1, /obj/item/reagent_containers/cup/glass/bottle/trappist=1);
+ spawn_loot_count = 2;
+ spawn_random_offset = 2
},
/obj/machinery/light/warm/directional/west,
/turf/open/floor/wood/large,
@@ -3255,6 +3550,11 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"CG" = (
+/obj/structure/mirror/directional/east,
+/obj/structure/sink/directional/west,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"CI" = (
/obj/effect/turf_decal/caution,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3293,6 +3593,18 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"Db" = (
+/obj/item/maneki_neko{
+ pixel_y = 4
+ },
+/obj/structure/table,
+/obj/machinery/status_display/random_message{
+ pixel_y = 32;
+ firstline_to_secondline = list(ACCEPTING="DONATIONS")
+ },
+/obj/structure/fluff/fake_vent,
+/turf/open/floor/iron,
+/area/awaymission/museum/cafeteria)
"De" = (
/obj/effect/oneway{
dir = 8
@@ -3383,6 +3695,11 @@
/obj/machinery/light/floor,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"DX" = (
+/obj/structure/reagent_dispensers/water_cooler,
+/obj/machinery/light/warm/directional/west,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"DY" = (
/turf/closed/indestructible/reinforced/titanium,
/area/awaymission/museum)
@@ -3400,8 +3717,8 @@
/obj/machinery/computer/old{
name = "replica computer";
dir = 4;
- icon_keyboard = "rd_key";
- icon_screen = "rdcomp"
+ icon_screen = "rdcomp";
+ icon_keyboard = "rd_key"
},
/turf/open/floor/iron/smooth_large,
/area/awaymission/museum)
@@ -3421,8 +3738,8 @@
dir = 4
},
/obj/structure/fluff/wallsign/directional/south{
- dir = 4;
- name = "Oddities"
+ name = "Oddities";
+ dir = 4
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -3435,12 +3752,17 @@
/turf/open/indestructible/plating,
/area/awaymission/museum)
"Er" = (
-/obj/structure/chair/comfy/beige,
/mob/living/basic/mothroach,
+/obj/structure/chair/comfy/beige,
/obj/effect/mapping_helpers/mob_buckler,
/obj/machinery/light/warm/directional/west,
/turf/open/floor/wood/large,
/area/awaymission/museum)
+"Es" = (
+/obj/structure/table,
+/obj/effect/spawner/random/food_or_drink/donkpockets,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"EA" = (
/obj/machinery/door/airlock/shuttle/glass,
/obj/effect/turf_decal/siding/dark_blue,
@@ -3460,9 +3782,9 @@
/area/awaymission/museum)
"EG" = (
/obj/item/flashlight/flare{
- start_on = 1;
icon_state = "flare-on";
- light_range = 4
+ light_range = 4;
+ start_on = 1
},
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/indestructible/plating,
@@ -3476,9 +3798,9 @@
"EM" = (
/obj/structure/table/wood,
/obj/effect/spawner/random/food_or_drink/booze{
- loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer = 10, /obj/item/reagent_containers/cup/glass/bottle/ale = 10, /obj/item/reagent_containers/cup/glass/bottle/beer/light = 5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor = 5, /obj/item/reagent_containers/cup/glass/bottle/whiskey = 5, /obj/item/reagent_containers/cup/glass/bottle/gin = 5, /obj/item/reagent_containers/cup/glass/bottle/vodka = 5, /obj/item/reagent_containers/cup/glass/bottle/tequila = 5, /obj/item/reagent_containers/cup/glass/bottle/rum = 5, /obj/item/reagent_containers/cup/glass/bottle/vermouth = 5, /obj/item/reagent_containers/cup/glass/bottle/cognac = 5, /obj/item/reagent_containers/cup/glass/bottle/wine = 5, /obj/item/reagent_containers/cup/glass/bottle/kahlua = 5, /obj/item/reagent_containers/cup/glass/bottle/amaretto = 5, /obj/item/reagent_containers/cup/glass/bottle/hcider = 5, /obj/item/reagent_containers/cup/glass/bottle/absinthe = 5, /obj/item/reagent_containers/cup/glass/bottle/sake = 5, /obj/item/reagent_containers/cup/glass/bottle/grappa = 5, /obj/item/reagent_containers/cup/glass/bottle/applejack = 5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic = 5, /obj/item/reagent_containers/cup/bottle/ethanol = 2, /obj/item/reagent_containers/cup/glass/bottle/fernet = 2, /obj/item/reagent_containers/cup/glass/bottle/champagne = 2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium = 2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager = 2, /obj/item/reagent_containers/cup/glass/bottle/patron = 1, /obj/item/reagent_containers/cup/glass/bottle/kong = 1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1, /obj/item/reagent_containers/cup/glass/bottle/trappist = 1);
- spawn_random_offset = 2;
- spawn_loot_count = 2
+ loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer=10, /obj/item/reagent_containers/cup/glass/bottle/ale=10, /obj/item/reagent_containers/cup/glass/bottle/beer/light=5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor=5, /obj/item/reagent_containers/cup/glass/bottle/whiskey=5, /obj/item/reagent_containers/cup/glass/bottle/gin=5, /obj/item/reagent_containers/cup/glass/bottle/vodka=5, /obj/item/reagent_containers/cup/glass/bottle/tequila=5, /obj/item/reagent_containers/cup/glass/bottle/rum=5, /obj/item/reagent_containers/cup/glass/bottle/vermouth=5, /obj/item/reagent_containers/cup/glass/bottle/cognac=5, /obj/item/reagent_containers/cup/glass/bottle/wine=5, /obj/item/reagent_containers/cup/glass/bottle/kahlua=5, /obj/item/reagent_containers/cup/glass/bottle/amaretto=5, /obj/item/reagent_containers/cup/glass/bottle/hcider=5, /obj/item/reagent_containers/cup/glass/bottle/absinthe=5, /obj/item/reagent_containers/cup/glass/bottle/sake=5, /obj/item/reagent_containers/cup/glass/bottle/grappa=5, /obj/item/reagent_containers/cup/glass/bottle/applejack=5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic=5, /obj/item/reagent_containers/cup/bottle/ethanol=2, /obj/item/reagent_containers/cup/glass/bottle/fernet=2, /obj/item/reagent_containers/cup/glass/bottle/champagne=2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium=2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager=2, /obj/item/reagent_containers/cup/glass/bottle/patron=1, /obj/item/reagent_containers/cup/glass/bottle/kong=1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine=1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka=1, /obj/item/reagent_containers/cup/glass/bottle/trappist=1);
+ spawn_loot_count = 2;
+ spawn_random_offset = 2
},
/turf/open/floor/wood/large,
/area/awaymission/museum)
@@ -3502,15 +3824,15 @@
/turf/open/floor/circuit/green,
/area/awaymission/museum)
"ET" = (
+/mob/living/basic/statue/mannequin{
+ dir = 1
+ },
/obj/structure/chair/stool/directional/north,
/obj/effect/turf_decal/tile/green/opposingcorners,
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/turf_decal/siding/green{
dir = 1
},
-/mob/living/basic/statue/mannequin{
- dir = 1
- },
/turf/open/floor/iron,
/area/awaymission/museum)
"EU" = (
@@ -3520,8 +3842,8 @@
dir = 4
},
/obj/structure/fluff/wallsign/directional/north{
- dir = 4;
- name = "Oddities"
+ name = "Oddities";
+ dir = 4
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -3594,8 +3916,8 @@
/area/awaymission/museum)
"Fw" = (
/obj/effect/decal/cleanable/blood/tracks{
- should_dry = 0;
- name = "replica blood"
+ name = "replica blood";
+ should_dry = 0
},
/obj/effect/mapping_helpers/burnt_floor,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3604,8 +3926,8 @@
"FA" = (
/obj/structure/table/reinforced,
/obj/item/circuitboard{
- icon_state = "printer";
- name = "fancy replica tech"
+ name = "fancy replica tech";
+ icon_state = "printer"
},
/turf/open/floor/iron/smooth_large,
/area/awaymission/museum)
@@ -3642,6 +3964,32 @@
/obj/structure/sign/departments/restroom/directional/south,
/turf/open/floor/wood/large,
/area/awaymission/museum)
+"FO" = (
+/obj/effect/decal/cleanable/crayon/puzzle/pin{
+ puzzle_id = "museum_r_wing_puzzle"
+ },
+/turf/closed/indestructible/reinforced,
+/area/awaymission/museum)
+"FU" = (
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/structure/fluff/wallsign/directional/south{
+ name = "Cafeteria";
+ dir = 4
+ },
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
+"FY" = (
+/obj/structure/chair/sofa/bench/left,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
+"Ga" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/machinery/door/airlock/grunge,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"Gh" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -3655,6 +4003,9 @@
/obj/structure/closet/crate/miningcar,
/turf/open/floor/tram/plate,
/area/awaymission/museum)
+"Gn" = (
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"Gv" = (
/obj/effect/decal/cleanable/crayon{
icon_state = "l";
@@ -3675,20 +4026,27 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/iron,
/area/awaymission/museum)
+"GB" = (
+/obj/structure/table,
+/obj/item/reagent_containers/cup/soda_cans/thirteenloko{
+ pixel_y = 7
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"GE" = (
/obj/structure/plaque/static_plaque/golden/commission/meta,
/turf/open/floor/mineral/gold,
/area/awaymission/museum)
"GG" = (
+/mob/living/basic/statue/mannequin{
+ dir = 4
+ },
/obj/structure/chair/office{
dir = 4
},
/obj/effect/turf_decal/siding/wood{
dir = 1
},
-/mob/living/basic/statue/mannequin{
- dir = 4
- },
/turf/open/floor/wood/tile,
/area/awaymission/museum)
"GO" = (
@@ -3762,8 +4120,8 @@
/area/awaymission/museum)
"Hn" = (
/mob/living/basic/statue/mannequin{
- hat = /obj/item/clothing/head/costume/kitty;
- dir = 8
+ dir = 8;
+ hat = /obj/item/clothing/head/costume/kitty
},
/obj/effect/turf_decal/trimline/yellow,
/obj/effect/turf_decal/trimline/yellow/corner{
@@ -3797,7 +4155,7 @@
/area/awaymission/museum)
"HA" = (
/obj/machinery/status_display/random_message{
- firstline_to_secondline = list("NO" = "LITTERING","YOU ARE" = "BEING WATCHED", "DO NOT TOUCH" = "THE EXHIBITS")
+ firstline_to_secondline = list(NO="LITTERING", "YOU ARE"="BEING WATCHED", "DO NOT TOUCH"="THE EXHIBITS")
},
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
@@ -3806,7 +4164,7 @@
/obj/effect/turf_decal/siding/dark_blue,
/obj/machinery/door/poddoor/shutters/indestructible{
dir = 8;
- id = "nothing"
+ id = "museum_secret"
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -3838,6 +4196,9 @@
"HP" = (
/turf/open/floor/iron/freezer,
/area/awaymission/museum)
+"HQ" = (
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"HU" = (
/obj/structure/railing{
dir = 4
@@ -3848,6 +4209,19 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"HW" = (
+/obj/machinery/button/door/directional/north{
+ name = "Lock Control";
+ id = "museum_toilet1";
+ specialfunctions = 4;
+ normaldoorcontrol = 1
+ },
+/obj/structure/toilet/museum{
+ dir = 4
+ },
+/obj/machinery/light/small/dim/directional/west,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"HY" = (
/obj/machinery/light/floor,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3857,6 +4231,12 @@
/obj/machinery/light/warm/dim/directional/north,
/turf/open/floor/carpet,
/area/awaymission/museum)
+"Id" = (
+/obj/effect/decal/cleanable/crayon/puzzle/pin{
+ puzzle_id = "museum_r_wing_puzzle"
+ },
+/turf/closed/indestructible/wood,
+/area/awaymission/museum)
"Ij" = (
/obj/machinery/door/airlock/external,
/obj/effect/mapping_helpers/airlock/locked,
@@ -3871,6 +4251,9 @@
/obj/structure/holosign/barrier/engineering,
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
+"Ir" = (
+/turf/closed/indestructible/fakedoor,
+/area/awaymission/museum)
"Iu" = (
/turf/open/floor/mineral/titanium/blue,
/area/awaymission/museum)
@@ -3898,6 +4281,12 @@
/obj/item/food/grilled_beef_gyro,
/turf/open/floor/wood/tile,
/area/awaymission/museum)
+"IG" = (
+/obj/structure/fluff/fake_camera{
+ dir = 9
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"IH" = (
/obj/machinery/portable_atmospherics/canister/water_vapor,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3914,11 +4303,22 @@
/obj/effect/turf_decal/stripes,
/turf/open/floor/iron/smooth_large,
/area/awaymission/museum)
+"IX" = (
+/mob/living/basic/statue/mannequin{
+ name = "cafeteria patron";
+ held_item = /obj/item/knife
+ },
+/obj/structure/chair/sofa/bench{
+ dir = 1
+ },
+/obj/effect/mapping_helpers/mob_buckler,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"IZ" = (
+/mob/living/basic/mothroach,
/obj/structure/chair/comfy/beige{
dir = 4
},
-/mob/living/basic/mothroach,
/obj/effect/mapping_helpers/mob_buckler,
/turf/open/floor/wood/large,
/area/awaymission/museum)
@@ -3959,6 +4359,13 @@
/obj/machinery/light/small/dim/directional/west,
/turf/open/floor/carpet/executive,
/area/awaymission/museum)
+"Jl" = (
+/obj/machinery/status_display/random_message{
+ pixel_x = 32;
+ firstline_to_secondline = list(CAFETERIA="YUMMY", CAFETERIA="HOTDOGS", ENJOY="YOUR MEAL")
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Jn" = (
/obj/structure/table/reinforced,
/obj/effect/spawner/random/entertainment/toy,
@@ -3967,6 +4374,13 @@
/obj/effect/turf_decal/siding/dark_blue,
/turf/open/floor/mineral/titanium/blue,
/area/awaymission/museum)
+"Jp" = (
+/obj/machinery/door/airlock{
+ name = "Restroom Cabin 1";
+ id_tag = "museum_toilet1"
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum)
"Js" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -4077,11 +4491,24 @@
/turf/open/floor/catwalk_floor,
/area/awaymission/museum)
"Kx" = (
-/obj/effect/decal/cleanable/dirt/dust,
/mob/living/basic/skeleton,
+/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/spawner/random/maintenance/three,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"Kz" = (
+/obj/structure/sign/warning/no_smoking/directional/west,
+/obj/machinery/computer/terminal/museum{
+ name = "extinguisher manual terminal";
+ dir = 4;
+ content = list("Instructions; stand upright; remove safety clip; aim noozle at base of fire... the rest is up to you.")
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
+"KB" = (
+/obj/structure/sign/warning/no_smoking/circle/directional/east,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"KI" = (
/turf/open/floor/iron/dark/side{
dir = 10
@@ -4112,7 +4539,7 @@
/area/awaymission/museum)
"Lp" = (
/obj/machinery/status_display/random_message{
- firstline_to_secondline = list("NO" = "LITTERING","YOU ARE" = "BEING WATCHED", "DO NOT TOUCH" = "THE EXHIBITS")
+ firstline_to_secondline = list(NO="LITTERING", "YOU ARE"="BEING WATCHED", "DO NOT TOUCH"="THE EXHIBITS")
},
/turf/closed/indestructible/reinforced/titanium/nodiagonal,
/area/awaymission/museum)
@@ -4162,6 +4589,12 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"LK" = (
+/obj/structure/table,
+/obj/item/piggy_bank/museum,
+/obj/machinery/light/warm/directional/north,
+/turf/open/floor/iron,
+/area/awaymission/museum/cafeteria)
"LN" = (
/obj/effect/decal/cleanable/glass/titanium,
/turf/open/floor/iron/dark/textured_large,
@@ -4197,6 +4630,11 @@
"Ma" = (
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
+"Mb" = (
+/obj/effect/turf_decal/siding/dark_blue,
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"Mg" = (
/obj/structure/plaque/static_plaque/golden/commission/tram,
/turf/closed/indestructible/reinforced,
@@ -4215,9 +4653,9 @@
/area/awaymission/museum)
"Mv" = (
/mob/living/basic/statue/mannequin{
+ name = "Michael Trasen";
dir = 4;
- held_item = /obj/item/wrench;
- name = "Michael Trasen"
+ held_item = /obj/item/wrench
},
/obj/effect/turf_decal/stripes{
dir = 4
@@ -4300,10 +4738,16 @@
/obj/structure/plaque/static_plaque/golden/commission/birdboat,
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
+"Nn" = (
+/obj/machinery/door/airlock/public{
+ name = "Restrooms"
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"Ns" = (
/obj/structure/table/wood,
/obj/effect/spawner/random/food_or_drink/booze{
- loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer = 10, /obj/item/reagent_containers/cup/glass/bottle/ale = 10, /obj/item/reagent_containers/cup/glass/bottle/beer/light = 5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor = 5, /obj/item/reagent_containers/cup/glass/bottle/whiskey = 5, /obj/item/reagent_containers/cup/glass/bottle/gin = 5, /obj/item/reagent_containers/cup/glass/bottle/vodka = 5, /obj/item/reagent_containers/cup/glass/bottle/tequila = 5, /obj/item/reagent_containers/cup/glass/bottle/rum = 5, /obj/item/reagent_containers/cup/glass/bottle/vermouth = 5, /obj/item/reagent_containers/cup/glass/bottle/cognac = 5, /obj/item/reagent_containers/cup/glass/bottle/wine = 5, /obj/item/reagent_containers/cup/glass/bottle/kahlua = 5, /obj/item/reagent_containers/cup/glass/bottle/amaretto = 5, /obj/item/reagent_containers/cup/glass/bottle/hcider = 5, /obj/item/reagent_containers/cup/glass/bottle/absinthe = 5, /obj/item/reagent_containers/cup/glass/bottle/sake = 5, /obj/item/reagent_containers/cup/glass/bottle/grappa = 5, /obj/item/reagent_containers/cup/glass/bottle/applejack = 5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic = 5, /obj/item/reagent_containers/cup/bottle/ethanol = 2, /obj/item/reagent_containers/cup/glass/bottle/fernet = 2, /obj/item/reagent_containers/cup/glass/bottle/champagne = 2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium = 2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager = 2, /obj/item/reagent_containers/cup/glass/bottle/patron = 1, /obj/item/reagent_containers/cup/glass/bottle/kong = 1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1, /obj/item/reagent_containers/cup/glass/bottle/trappist = 1);
+ loot = list(/obj/item/reagent_containers/cup/glass/bottle/beer=10, /obj/item/reagent_containers/cup/glass/bottle/ale=10, /obj/item/reagent_containers/cup/glass/bottle/beer/light=5, /obj/item/reagent_containers/cup/glass/bottle/maltliquor=5, /obj/item/reagent_containers/cup/glass/bottle/whiskey=5, /obj/item/reagent_containers/cup/glass/bottle/gin=5, /obj/item/reagent_containers/cup/glass/bottle/vodka=5, /obj/item/reagent_containers/cup/glass/bottle/tequila=5, /obj/item/reagent_containers/cup/glass/bottle/rum=5, /obj/item/reagent_containers/cup/glass/bottle/vermouth=5, /obj/item/reagent_containers/cup/glass/bottle/cognac=5, /obj/item/reagent_containers/cup/glass/bottle/wine=5, /obj/item/reagent_containers/cup/glass/bottle/kahlua=5, /obj/item/reagent_containers/cup/glass/bottle/amaretto=5, /obj/item/reagent_containers/cup/glass/bottle/hcider=5, /obj/item/reagent_containers/cup/glass/bottle/absinthe=5, /obj/item/reagent_containers/cup/glass/bottle/sake=5, /obj/item/reagent_containers/cup/glass/bottle/grappa=5, /obj/item/reagent_containers/cup/glass/bottle/applejack=5, /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic=5, /obj/item/reagent_containers/cup/bottle/ethanol=2, /obj/item/reagent_containers/cup/glass/bottle/fernet=2, /obj/item/reagent_containers/cup/glass/bottle/champagne=2, /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium=2, /obj/item/reagent_containers/cup/glass/bottle/goldschlager=2, /obj/item/reagent_containers/cup/glass/bottle/patron=1, /obj/item/reagent_containers/cup/glass/bottle/kong=1, /obj/item/reagent_containers/cup/glass/bottle/lizardwine=1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka=1, /obj/item/reagent_containers/cup/glass/bottle/trappist=1);
spawn_random_offset = 2
},
/turf/open/floor/wood/large,
@@ -4324,8 +4768,8 @@
/obj/structure/railing,
/obj/structure/table,
/obj/item/clothing/mask/cigarette/cigar{
- lit = 1;
- icon_state = "cigaron"
+ icon_state = "cigaron";
+ lit = 1
},
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
@@ -4431,11 +4875,11 @@
/turf/open/floor/iron,
/area/awaymission/museum)
"OS" = (
+/mob/living/basic/mothroach,
/obj/structure/chair/stool/bar/directional/east{
can_buckle = 1
},
/obj/effect/mapping_helpers/mob_buckler,
-/mob/living/basic/mothroach,
/turf/open/floor/wood/large,
/area/awaymission/museum)
"OT" = (
@@ -4481,6 +4925,9 @@
/obj/item/food/kebab/pineapple_skewer,
/turf/open/floor/iron/freezer,
/area/awaymission/museum)
+"Ph" = (
+/turf/closed/indestructible/reinforced,
+/area/awaymission/museum/cafeteria)
"Pi" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue/corner{
@@ -4584,8 +5031,8 @@
"PZ" = (
/obj/effect/mapping_helpers/broken_floor,
/obj/item/flashlight/flare{
- start_on = 1;
- icon_state = "flare-on"
+ icon_state = "flare-on";
+ start_on = 1
},
/turf/open/indestructible/plating,
/area/awaymission/museum)
@@ -4756,9 +5203,9 @@
},
/obj/structure/fluff{
name = "replica prototype autolathe";
+ desc = "A non-functional replica of a prototype Autolathe.";
icon = 'icons/obj/machines/lathes.dmi';
- icon_state = "autolathe";
- desc = "A non-functional replica of a prototype Autolathe."
+ icon_state = "autolathe"
},
/turf/open/floor/iron/smooth_corner{
dir = 4
@@ -4803,6 +5250,18 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/white,
/area/awaymission/museum)
+"RQ" = (
+/obj/effect/turf_decal/tile/neutral/opposingcorners,
+/obj/effect/turf_decal/siding/dark_blue{
+ dir = 1
+ },
+/obj/structure/fluff/fake_camera,
+/obj/effect/decal/puzzle_dots{
+ pixel_y = -32;
+ id = "museum_r_wing_puzzle"
+ },
+/turf/open/floor/iron/dark,
+/area/awaymission/museum)
"RR" = (
/obj/machinery/suit_storage_unit/open,
/obj/effect/turf_decal/box,
@@ -4829,8 +5288,8 @@
/turf/open/floor/bluespace,
/area/awaymission/museum)
"Se" = (
-/obj/structure/chair/comfy/beige,
/mob/living/basic/mothroach,
+/obj/structure/chair/comfy/beige,
/obj/effect/mapping_helpers/mob_buckler,
/turf/open/floor/wood/large,
/area/awaymission/museum)
@@ -4839,6 +5298,11 @@
/obj/structure/railing,
/turf/open/floor/holofloor/asteroid,
/area/awaymission/museum)
+"Sm" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/structure/fluff/fake_scrubber,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"So" = (
/obj/machinery/shower/directional/east,
/turf/open/floor/iron/white/textured_large,
@@ -4849,7 +5313,7 @@
/area/awaymission/museum)
"Sv" = (
/obj/machinery/status_display/random_message{
- firstline_to_secondline = list("SOUVENIR" = "SHOP")
+ firstline_to_secondline = list(SOUVENIR="SHOP")
},
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
@@ -4880,7 +5344,11 @@
},
/obj/machinery/door/poddoor/shutters/indestructible{
dir = 8;
- id = "nothing"
+ id = "museum_secret"
+ },
+/obj/machinery/puzzle/password/pin/directional/south{
+ id = "museum_r_wing_puzzle";
+ late_initialize_pop = 1
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -4889,6 +5357,14 @@
/obj/item/stack/spacecash/c1000,
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"Ta" = (
+/obj/machinery/light/directional/west,
+/obj/effect/decal/cleanable/crayon/puzzle/pin{
+ pixel_x = -32;
+ puzzle_id = "museum_r_wing_puzzle"
+ },
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"Tr" = (
/obj/structure/plaque/static_plaque/golden/commission/kilo,
/obj/machinery/light/floor,
@@ -4923,6 +5399,13 @@
},
/turf/open/indestructible/plating,
/area/awaymission/museum)
+"TC" = (
+/obj/machinery/door/airlock/multi_tile/public/glass{
+ name = "Cafeteria";
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/awaymission/museum/cafeteria)
"TF" = (
/turf/open/floor/iron/stairs/right{
dir = 4
@@ -4998,8 +5481,8 @@
dir = 8
},
/obj/structure/fluff/wallsign/directional/east{
- dir = 2;
- name = "Exit"
+ name = "Exit";
+ dir = 2
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -5037,8 +5520,8 @@
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/structure/table,
/obj/item/computer_disk{
- icon_state = "datadisk_hydro";
- name = "plant data disk"
+ name = "plant data disk";
+ icon_state = "datadisk_hydro"
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
@@ -5066,6 +5549,12 @@
/mob/living/basic/mothroach,
/turf/open/misc/beach/sand,
/area/awaymission/museum/mothroachvoid)
+"UH" = (
+/obj/structure/mirror/broken/directional/east,
+/obj/structure/sink/directional/west,
+/obj/effect/decal/cleanable/oil/slippery,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"UI" = (
/obj/effect/turf_decal/tile/green/opposingcorners,
/obj/effect/decal/cleanable/dirt/dust,
@@ -5106,8 +5595,8 @@
/area/awaymission/museum)
"UT" = (
/obj/machinery/status_display/random_message{
- firstline_to_secondline = list("NO" = "LITTERING","YOU ARE" = "BEING WATCHED", "DO NOT TOUCH" = "THE EXHIBITS");
- pixel_x = 32
+ pixel_x = 32;
+ firstline_to_secondline = list(NO="LITTERING", "YOU ARE"="BEING WATCHED", "DO NOT TOUCH"="THE EXHIBITS")
},
/turf/open/floor/carpet,
/area/awaymission/museum)
@@ -5129,6 +5618,14 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/smooth_half,
/area/awaymission/museum)
+"Vb" = (
+/obj/effect/replica_spawner{
+ obvious_replica = 0;
+ pixel_y = 30;
+ target_path = /obj/structure/sign/painting/eldritch/weeping
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Vc" = (
/obj/machinery/light/warm/directional/east,
/obj/effect/turf_decal/tile/neutral/opposingcorners,
@@ -5380,6 +5877,25 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"WY" = (
+/obj/machinery/button/door/directional/north{
+ name = "Lock Control";
+ id = "museum_toilet2";
+ specialfunctions = 4;
+ normaldoorcontrol = 1
+ },
+/obj/structure/toilet/museum{
+ dir = 4
+ },
+/obj/machinery/light/small/dim/directional/west,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
+"WZ" = (
+/obj/structure/chair/sofa/bench{
+ dir = 1
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Xa" = (
/obj/structure/broken_flooring/corner/always_floorplane{
dir = 2
@@ -5402,6 +5918,10 @@
"Xh" = (
/turf/closed/indestructible/fakedoor/maintenance,
/area/awaymission/museum)
+"Xi" = (
+/obj/structure/chair/sofa/bench/right,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Xo" = (
/obj/structure/lattice/catwalk/mining,
/obj/structure/railing,
@@ -5502,8 +6022,8 @@
/turf/closed/indestructible/reinforced/titanium/nodiagonal,
/area/awaymission/museum)
"Yg" = (
-/obj/effect/decal/cleanable/dirt/dust,
/mob/living/basic/cockroach,
+/obj/effect/decal/cleanable/dirt/dust,
/turf/open/indestructible/plating,
/area/awaymission/museum)
"Yk" = (
@@ -5512,6 +6032,12 @@
},
/turf/open/floor/iron,
/area/awaymission/museum)
+"Yn" = (
+/obj/machinery/light/warm/directional/east,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/structure/fluff/fake_camera,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"Yr" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/structure/table/reinforced,
@@ -5521,13 +6047,21 @@
/obj/item/reagent_containers/cup/glass/mug/nanotrasen,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"Yy" = (
+/obj/machinery/computer/terminal/museum{
+ name = "donation info terminal";
+ dir = 8;
+ content = list("We're once again asking for your financial support; We love our job, but love alone can only get us so far. Please consider leaving a donation to help keep the musuem running. Thank you.")
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Yz" = (
-/obj/effect/turf_decal/siding,
/mob/living/basic/statue/mannequin{
dir = 8;
held_item = /obj/item/pickaxe;
hat = /obj/item/clothing/suit/hooded/explorer
},
+/obj/effect/turf_decal/siding,
/obj/structure/railing,
/turf/open/floor/holofloor/asteroid,
/area/awaymission/museum)
@@ -5571,8 +6105,15 @@
/obj/item/reagent_containers/cup/glass/coffee/no_lid{
pixel_x = 12
},
+/obj/item/paper/fluff/museum/numbers_on_walls,
/turf/open/floor/iron,
/area/awaymission/museum)
+"Za" = (
+/obj/structure/chair/sofa/bench/right{
+ dir = 1
+ },
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Zf" = (
/obj/structure/plaque/static_plaque/golden/commission/donut,
/turf/closed/indestructible/reinforced,
@@ -5589,6 +6130,11 @@
/obj/structure/lattice,
/turf/open/chasm/true/no_smooth,
/area/awaymission/museum)
+"Zo" = (
+/obj/structure/table,
+/obj/effect/spawner/random/food_or_drink/snack,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"Zp" = (
/obj/structure/plaque/static_plaque/golden/commission/icebox,
/turf/closed/indestructible/reinforced,
@@ -5613,6 +6159,16 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"Zx" = (
+/obj/structure/chair/sofa/bench,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
+"Zz" = (
+/obj/effect/mapping_helpers/turn_off_lights_with_lightswitch,
+/obj/machinery/light_switch/directional/west,
+/turf/open/floor/iron/cafeteria,
+/area/awaymission/museum/cafeteria)
"ZB" = (
/obj/machinery/door/airlock/maintenance_hatch,
/obj/structure/broken_flooring/side/always_floorplane/directional/east,
@@ -5644,6 +6200,13 @@
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
+"ZO" = (
+/obj/structure/sink/directional/south{
+ pixel_y = 6
+ },
+/obj/structure/mirror/directional/north,
+/turf/open/floor/iron/white/small,
+/area/awaymission/museum)
"ZP" = (
/obj/structure/statue/gold/ce{
anchored = 1
@@ -26150,7 +26713,7 @@ re
re
re
re
-re
+Uq
re
re
re
@@ -26403,12 +26966,12 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
+FK
+FK
+FK
+FK
+FK
+Uq
re
re
re
@@ -26660,11 +27223,11 @@ re
re
re
re
-re
-re
-re
-re
-re
+FK
+kZ
+FK
+oD
+FK
re
re
re
@@ -26915,13 +27478,13 @@ Wc
FK
re
re
-re
-re
-re
-re
-re
-re
-re
+FK
+FO
+FK
+ta
+FK
+AQ
+FK
re
re
re
@@ -27172,13 +27735,13 @@ fy
FK
re
re
-re
-re
-re
-re
-re
-re
-re
+FK
+jO
+ry
+Gn
+Ta
+Gn
+FK
re
re
re
@@ -27429,13 +27992,13 @@ tD
FK
re
re
-re
-re
-re
-re
-re
-re
-re
+FK
+FK
+FO
+IG
+Gn
+ax
+FK
re
re
re
@@ -27687,12 +28250,12 @@ FK
re
re
re
-re
-re
-re
-re
-re
-re
+FK
+ZO
+Gn
+Gn
+Gn
+FK
re
re
re
@@ -27947,7 +28510,7 @@ FK
FK
FK
FK
-FK
+Nn
FK
FK
Uq
@@ -29699,7 +30262,7 @@ aW
MF
MF
MF
-MF
+Id
Re
PZ
Ma
@@ -34375,7 +34938,7 @@ FK
FK
FK
FK
-FK
+FO
FK
FK
FK
@@ -35113,7 +35676,7 @@ re
re
re
re
-FK
+FO
qw
XK
PP
@@ -35916,7 +36479,7 @@ FK
FK
FK
Yd
-FK
+FO
NO
dZ
mn
@@ -35958,6 +36521,9 @@ nu
FK
FK
FK
+FK
+FK
+FK
Uq
re
re
@@ -35995,9 +36561,6 @@ re
re
re
re
-re
-re
-re
"}
(119,1,1) = {"
re
@@ -36214,10 +36777,10 @@ qQ
xI
gT
Qb
-FK
-re
-re
-re
+Ga
+gg
+iJ
+FO
re
re
re
@@ -36472,6 +37035,9 @@ xI
xd
ns
FK
+FK
+FK
+FK
re
re
re
@@ -36509,9 +37075,6 @@ re
re
re
re
-re
-re
-re
"}
(121,1,1) = {"
re
@@ -36731,7 +37294,7 @@ BO
FK
re
re
-re
+Uq
re
re
re
@@ -36986,7 +37549,7 @@ Nc
FK
FK
FK
-Uq
+re
re
re
re
@@ -37461,7 +38024,7 @@ FK
FK
FK
PB
-FK
+FO
Ma
Ma
Ma
@@ -40781,7 +41344,7 @@ FK
FK
FK
FK
-lb
+eW
uY
rQ
FK
@@ -42582,7 +43145,7 @@ FK
FK
lb
uY
-qX
+RQ
FK
FK
FK
@@ -43085,19 +43648,19 @@ re
re
re
re
+FK
+FK
+FK
+FK
+FK
+FK
+FK
re
-re
-re
-re
-re
-re
-re
-re
-Uq
-re
-re
-re
-Uq
+FK
+aa
+uY
+ci
+jC
re
re
re
@@ -43342,19 +43905,19 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+FK
+aO
+FK
+WY
+FK
+HW
+FK
+FK
+FK
+Mb
+TM
+wV
+FK
re
re
re
@@ -43599,19 +44162,19 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+FK
+wg
+FK
+us
+FK
+Jp
+FK
+um
+FK
+Mb
+uY
+wV
+FK
re
re
re
@@ -43856,19 +44419,19 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+FK
+Gn
+Gn
+Gn
+Sm
+Gn
+Kz
+Gn
+FK
+ju
+uY
+ci
+Ir
re
re
re
@@ -44113,19 +44676,19 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+FK
+nY
+Gn
+Gn
+Gn
+Gn
+Gn
+Gn
+kx
+uY
+uY
+wV
+FK
re
re
re
@@ -44370,19 +44933,19 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+FK
+ut
+UH
+gE
+CG
+Gn
+CG
+Yn
+FK
+RC
+TM
+FU
+FK
re
re
re
@@ -44627,20 +45190,20 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+FK
+FK
+FK
+FK
+FK
+FK
+FK
+FK
+FK
+Mb
+uY
+wV
+FK
+Uq
re
re
re
@@ -44892,11 +45455,11 @@ re
re
re
re
-re
-re
-re
-re
-re
+FK
+pN
+uY
+hS
+oP
re
re
re
@@ -45149,11 +45712,11 @@ re
re
re
re
-re
-re
-re
-re
-re
+FK
+FK
+pz
+kL
+FK
re
re
re
@@ -45403,16 +45966,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+Ph
+Ph
+Ph
+Ph
+ms
+TC
+Ph
+Ph
+Ph
re
re
re
@@ -45660,16 +46223,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+DX
+HQ
+fl
+Zz
+HQ
+HQ
+HQ
+ac
+Ph
re
re
re
@@ -45917,16 +46480,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+qK
+HQ
+HQ
+HQ
+HQ
+HQ
+HQ
+HQ
+vG
re
re
re
@@ -46174,16 +46737,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+uH
+HQ
+Xi
+xp
+nZ
+Xi
+Es
+nZ
+Ph
re
re
re
@@ -46431,17 +46994,17 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+Vb
+HQ
+Zx
+hm
+WZ
+ql
+xp
+WZ
+Ph
+Uq
re
re
re
@@ -46688,16 +47251,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+HQ
+HQ
+ql
+Zo
+WZ
+ql
+GB
+IX
+Ph
re
re
re
@@ -46945,16 +47508,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+Db
+HQ
+FY
+xO
+Za
+FY
+xp
+Za
+Ph
re
re
re
@@ -47202,16 +47765,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+LK
+Yy
+HQ
+HQ
+KB
+Jl
+HQ
+cY
+Ph
re
re
re
@@ -47459,16 +48022,16 @@ re
re
re
re
-re
-re
-re
-re
-re
-re
-re
-re
-re
-re
+Ph
+Ph
+Ph
+Ph
+Ph
+Ph
+Ph
+Ph
+Ph
+Ph
re
re
re
diff --git a/_maps/map_files/Deathmatch/mech_madness.dmm b/_maps/map_files/Deathmatch/mech_madness.dmm
index d36ccfb16cc20..3f804d2ee5452 100644
--- a/_maps/map_files/Deathmatch/mech_madness.dmm
+++ b/_maps/map_files/Deathmatch/mech_madness.dmm
@@ -664,7 +664,7 @@
/area/deathmatch)
"ot" = (
/obj/structure/mop_bucket/janitorialcart{
- dir = 4
+ dir = 4
},
/turf/open/floor/engine,
/area/deathmatch)
diff --git a/_maps/map_files/Deathmatch/starwars.dmm b/_maps/map_files/Deathmatch/starwars.dmm
index c1f005461073a..c7654810360e1 100644
--- a/_maps/map_files/Deathmatch/starwars.dmm
+++ b/_maps/map_files/Deathmatch/starwars.dmm
@@ -1142,9 +1142,6 @@
},
/turf/open/indestructible/large,
/area/deathmatch)
-"US" = (
-/turf/closed/indestructible/reinforced,
-/area/deathmatch)
"Ve" = (
/obj/effect/turf_decal/tile/red/full,
/obj/structure/barricade/security/murderdome,
@@ -1320,7 +1317,7 @@ tV
tV
IC
IC
-US
+KX
Vz
sZ
sZ
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 28143ce53ea8b..30e548835e8be 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -8724,10 +8724,10 @@
"cdJ" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/cable,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/structure/cable,
/turf/open/floor/iron/dark/corner{
dir = 1
},
@@ -10426,7 +10426,12 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/newscaster/directional/west,
/obj/structure/cable,
-/turf/open/floor/iron,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/turf/open/floor/iron/dark/corner{
+ dir = 1
+ },
/area/station/hallway/secondary/exit/departure_lounge)
"czL" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
@@ -36979,7 +36984,6 @@
/turf/open/floor/iron,
/area/station/security/prison/garden)
"jgl" = (
-/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/grunge{
name = "Morgue"
},
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 443f7049dea71..7ac2807b4801e 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -43180,8 +43180,8 @@
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/door/airlock/research/glass{
- name = "Chemistry Lab"
+/obj/machinery/door/airlock/medical/glass{
+ name = "Chemistry"
},
/obj/effect/mapping_helpers/airlock/access/all/medical/chemistry,
/obj/machinery/door/firedoor,
@@ -45173,7 +45173,6 @@
},
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/mapping_helpers/airlock/access/any/medical/general,
/obj/effect/mapping_helpers/airlock/access/any/medical/pharmacy,
/turf/open/floor/plating,
/area/station/maintenance/department/medical/central)
@@ -50097,7 +50096,7 @@
name = "Surgery C Maintenance"
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/mapping_helpers/airlock/access/all/medical/general,
+/obj/effect/mapping_helpers/airlock/access/all/medical/surgery,
/turf/open/floor/plating,
/area/station/maintenance/aft/greater)
"rTL" = (
@@ -62655,13 +62654,12 @@
"whx" = (
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/door/airlock/research/glass{
+/obj/machinery/door/airlock/medical/glass{
name = "Pharmacy"
},
/obj/structure/disposalpipe/segment{
dir = 4
},
-/obj/effect/mapping_helpers/airlock/access/any/medical/general,
/obj/effect/mapping_helpers/airlock/access/any/medical/pharmacy,
/obj/effect/turf_decal/tile/yellow/fourcorners,
/obj/effect/landmark/navigate_destination,
diff --git a/code/__DEFINES/alerts.dm b/code/__DEFINES/alerts.dm
index 1933b592d55c5..3d09a3e5a22d5 100644
--- a/code/__DEFINES/alerts.dm
+++ b/code/__DEFINES/alerts.dm
@@ -51,7 +51,6 @@
#define ALERT_MECH_DAMAGE "mech_damage"
/** Food related */
-#define ALERT_NUTRITION "nutrition"
#define ALERT_DISGUST "disgust"
/** Environment related */
diff --git a/code/__DEFINES/atmospherics/atmos_piping.dm b/code/__DEFINES/atmospherics/atmos_piping.dm
index 1993f10222523..3870a7aed34ac 100644
--- a/code/__DEFINES/atmospherics/atmos_piping.dm
+++ b/code/__DEFINES/atmospherics/atmos_piping.dm
@@ -9,11 +9,13 @@
#define EAST_SHORTPIPE (1<<6)
#define WEST_SHORTPIPE (1<<7)
// Helpers to convert cardinals to and from pipe bitfields
-// Assumes X_FULLPIPE = X, X_SHORTPIPE >> 4 = X as above
+// Assumes X_FULLPIPE = X, X_SHORTPIPE >> 4 = X, X_PIPECAPS >> 8 = X as above
#define FULLPIPE_TO_CARDINALS(bitfield) ((bitfield) & ALL_CARDINALS)
#define SHORTPIPE_TO_CARDINALS(bitfield) (((bitfield) >> 4) & ALL_CARDINALS)
+#define PIPECAPS_TO_CARDINALS(bitfield) (((bitfield) >> 8) & ALL_CARDINALS)
#define CARDINAL_TO_FULLPIPES(cardinals) (cardinals)
#define CARDINAL_TO_SHORTPIPES(cardinals) ((cardinals) << 4)
+#define CARDINAL_TO_PIPECAPS(cardinals) ((cardinals) << 8)
// A pipe is a stub if it only has zero or one permitted direction. For a regular pipe this is nonsensical, and there are no pipe sprites for this, so it is not allowed.
#define ISSTUB(bits) !((bits) & ((bits) - 1))
#define ISNOTSTUB(bits) ((bits) & ((bits) - 1))
diff --git a/code/__DEFINES/client.dm b/code/__DEFINES/client.dm
index 0914bc025adda..17571b5270bb1 100644
--- a/code/__DEFINES/client.dm
+++ b/code/__DEFINES/client.dm
@@ -1,11 +1,6 @@
/// Checks if the given target is either a client or a mock client
#define IS_CLIENT_OR_MOCK(target) (istype(target, /client) || istype(target, /datum/client_interface))
-/// Ensures that the client has been fully initialized via New(), and can't somehow execute actions before that. Security measure.
-/// WILL RETURN OUT OF THE ENTIRE PROC COMPLETELY IF THE CLIENT IS NOT FULLY INITIALIZED. BE WARNED IF YOU WANT RETURN VALUES.
-#define VALIDATE_CLIENT(target)\
- if (!target.fully_created) {\
- to_chat(target, span_warning("You are not fully initialized yet! Please wait a moment."));\
- log_access("Client [key_name(target)] attempted to execute a verb before being fully initialized.");\
- return\
- }
+/// Checks to see if a /client has fully gone through New() as a safeguard against certain operations.
+/// Should return the boolean value of the fully_created var, which should be TRUE if New() has finished running. FALSE otherwise.
+#define VALIDATE_CLIENT_INITIALIZATION(target) (target.fully_created)
diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm
index 24ab2eb330327..55c6d496e0cfe 100644
--- a/code/__DEFINES/construction/material.dm
+++ b/code/__DEFINES/construction/material.dm
@@ -68,13 +68,13 @@
//Stock market stock values.
/// How much quantity of a material stock exists for common materials like iron & glass.
-#define MATERIAL_QUANTITY_COMMON 25000
+#define MATERIAL_QUANTITY_COMMON 5000
/// How much quantity of a material stock exists for uncommon materials like silver & titanium.
-#define MATERIAL_QUANTITY_UNCOMMON 10000
+#define MATERIAL_QUANTITY_UNCOMMON 1000
/// How much quantity of a material stock exists for rare materials like gold, uranium, & diamond.
-#define MATERIAL_QUANTITY_RARE 2500
+#define MATERIAL_QUANTITY_RARE 200
/// How much quantity of a material stock exists for exotic materials like diamond & bluespace crystals.
-#define MATERIAL_QUANTITY_EXOTIC 500
+#define MATERIAL_QUANTITY_EXOTIC 50
// The number of ore vents that will spawn boulders with this material.
/// Is this material going to spawn often in ore vents? (80% of vents on lavaland)
diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
index 3654b4cfce5d3..e3c57b59f6221 100644
--- a/code/__DEFINES/dcs/signals/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -158,6 +158,9 @@
/// Return to prevent the default behavior (attack_selfing) from ocurring.
#define COMPONENT_ITEM_ACTION_SLOT_INVALID (1<<0)
+/// Sent from /obj/item/attack_atom(): (atom/attacked_atom, mob/living/user)
+#define COMSIG_ITEM_POST_ATTACK_ATOM "item_post_attack_atom"
+
///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone"
///from base of obj/item/hit_reaction(): (owner, hitby, attack_text, final_block_chance, damage, attack_type, damage_type)
diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm
index 93b0678581ae8..32408e4f538e9 100644
--- a/code/__DEFINES/economy.dm
+++ b/code/__DEFINES/economy.dm
@@ -70,12 +70,13 @@
#define PAYMENT_CLINICAL "clinical"
#define PAYMENT_FRIENDLY "friendly"
#define PAYMENT_ANGRY "angry"
+#define PAYMENT_VENDING "vending"
#define MARKET_TREND_UPWARD 1
#define MARKET_TREND_DOWNWARD -1
#define MARKET_TREND_STABLE 0
-#define MARKET_EVENT_PROBABILITY 1 //Probability of a market event firing, in percent. Fires once per material, every 20 seconds.
+#define MARKET_EVENT_PROBABILITY 8 //Probability of a market event firing, in percent. Fires once per material, every stock market tick.
#define MARKET_PROFIT_MODIFIER 0.8 //We don't make every sale a 1-1 of the actual buy price value, like with real life taxes and to encourage more smart trades
diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm
index 0d2fb6b874d48..a4d826d87caf6 100644
--- a/code/__DEFINES/hud.dm
+++ b/code/__DEFINES/hud.dm
@@ -79,13 +79,6 @@
#define ui_navigate_menu "EAST-4:22,SOUTH:5"
#define ui_floor_menu "EAST-4:14,SOUTH:37"
-//Upper-middle right (alerts)
-#define ui_alert1 "EAST-1:28,CENTER+5:27"
-#define ui_alert2 "EAST-1:28,CENTER+4:25"
-#define ui_alert3 "EAST-1:28,CENTER+3:23"
-#define ui_alert4 "EAST-1:28,CENTER+2:21"
-#define ui_alert5 "EAST-1:28,CENTER+1:19"
-
//Upper left (action buttons)
#define ui_action_palette "WEST+0:23,NORTH-1:5"
#define ui_action_palette_offset(north_offset) ("WEST+0:23,NORTH-[1+north_offset]:5")
@@ -98,6 +91,7 @@
#define ui_health "EAST-1:28,CENTER-1:19"
#define ui_internal "EAST-1:28,CENTER+1:21"
#define ui_mood "EAST-1:28,CENTER:21"
+#define ui_hunger "EAST-1:2,CENTER:21"
#define ui_spacesuit "EAST-1:28,CENTER-4:14"
#define ui_stamina "EAST-1:28,CENTER-3:14"
diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm
index 2509d685d35df..29a2c6dc07ec7 100644
--- a/code/__DEFINES/icon_smoothing.dm
+++ b/code/__DEFINES/icon_smoothing.dm
@@ -192,8 +192,13 @@ DEFINE_BITFIELD(smoothing_junction, list(
#define SMOOTH_GROUP_CLEANABLE_DIRT S_OBJ(68) ///obj/effect/decal/cleanable/dirt
-#define SMOOTH_GROUP_GAS_TANK S_OBJ(72)
+#define SMOOTH_GROUP_GAS_TANK S_OBJ(69)
+#define SMOOTH_GROUP_SPIDER_WEB S_OBJ(70) // /obj/structure/spider/stickyweb
+#define SMOOTH_GROUP_SPIDER_WEB_WALL S_OBJ(71) // /obj/structure/spider/stickyweb/sealed
+#define SMOOTH_GROUP_SPIDER_WEB_ROOF S_OBJ(72) // /obj/structure/spider/passage
+#define SMOOTH_GROUP_SPIDER_WEB_WALL_TOUGH S_OBJ(73) // /obj/structure/spider/stickyweb/sealed/thick
+#define SMOOTH_GROUP_SPIDER_WEB_WALL_MIRROR S_OBJ(74) // /obj/structure/spider/stickyweb/sealed/reflector
/// Performs the work to set smoothing_groups and canSmoothWith.
/// An inlined function used in both turf/Initialize and atom/Initialize.
diff --git a/code/__DEFINES/procpath.dm b/code/__DEFINES/procpath.dm
index 642ca3eab6cc8..16716d6c091f2 100644
--- a/code/__DEFINES/procpath.dm
+++ b/code/__DEFINES/procpath.dm
@@ -15,12 +15,12 @@
// below, their accesses are optimized away.
/// A text string of the verb's name.
- var/name as text
+ var/name = null as text|null
/// The verb's help text or description.
- var/desc as text
+ var/desc = null as text|null
/// The category or tab the verb will appear in.
- var/category as text
+ var/category = null as text|null
/// Only clients/mobs with `see_invisibility` higher can use the verb.
- var/invisibility as num
+ var/invisibility = null as num|null
/// Whether or not the verb appears in statpanel and commandbar when you press space
- var/hidden as num
+ var/hidden = null as num|null
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index 8301a9fb107e8..5b0ea31dfbfd0 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -173,3 +173,4 @@ GLOBAL_LIST_INIT(announcer_keys, list(
#define SFX_ROCK_TAP "rock_tap"
#define SFX_SEAR "sear"
#define SFX_REEL "reel"
+#define SFX_RATTLE "rattle"
diff --git a/code/__DEFINES/time.dm b/code/__DEFINES/time.dm
index 1935c3c0aee3d..6a2a5152903ba 100644
--- a/code/__DEFINES/time.dm
+++ b/code/__DEFINES/time.dm
@@ -39,6 +39,7 @@
#define PRIDE_WEEK "Pride Week"
#define MOTH_WEEK "Moth Week"
#define IAN_HOLIDAY "Ian's Birthday"
+#define HOTDOG_DAY "National Hot Dog Day"
/*
Days of the week to make it easier to reference them.
diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm
index dd237bf54b704..7f4fbd929367f 100644
--- a/code/__DEFINES/traits/sources.dm
+++ b/code/__DEFINES/traits/sources.dm
@@ -34,6 +34,8 @@
#define CULT_TRAIT "cult"
#define LICH_TRAIT "lich"
+#define VENDING_MACHINE_TRAIT "vending_machine"
+
#define ABSTRACT_ITEM_TRAIT "abstract-item"
/// A trait given by any status effect
#define STATUS_EFFECT_TRAIT "status-effect"
diff --git a/code/__HELPERS/clients.dm b/code/__HELPERS/clients.dm
index 3b61cf1e1c456..156f9e2b5dcdf 100644
--- a/code/__HELPERS/clients.dm
+++ b/code/__HELPERS/clients.dm
@@ -10,3 +10,9 @@
if (ch < 48 || ch > 57) //0-9
return FALSE
return TRUE
+
+/// Proc that just logs whenever an uninitialized client tries to do something before they have fully gone through New().
+/// Intended to be used in conjunction with the `VALIDATE_CLIENT_INITIALIZATION()` macro, but can be dropped anywhere when we look at the `fully_created` var on /client.
+/proc/unvalidated_client_error(client/target)
+ to_chat(target, span_warning("You are not fully initialized yet! Please wait a moment."))
+ log_access("Client [key_name(target)] attempted to execute a verb before being fully initialized.")
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index f7889f0b5af80..f0741f3d8f3f2 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -258,3 +258,10 @@ GLOBAL_LIST_INIT(WALLITEMS_EXTERIOR, typecacheof(list(
/obj/structure/camera_assembly,
/obj/structure/light_construct,
)))
+
+/// A static typecache of all the money-based items that can be actively used as currency.
+GLOBAL_LIST_INIT(allowed_money, typecacheof(list(
+ /obj/item/coin,
+ /obj/item/holochip,
+ /obj/item/stack/spacecash,
+)))
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 1f5f7588162ab..8b96a5491bd47 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -68,8 +68,8 @@
if(client && hud_used)
hud_used.reorganize_alerts()
if(!no_anim)
- thealert.transform = matrix(32, 6, MATRIX_TRANSLATE)
- animate(thealert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
+ thealert.transform = matrix(32, 0, MATRIX_TRANSLATE)
+ animate(thealert, transform = matrix(), time = 1 SECONDS, easing = ELASTIC_EASING)
if(timeout_override)
thealert.timeout = timeout_override
if(thealert.timeout)
@@ -185,22 +185,6 @@
//End gas alerts
-
-/atom/movable/screen/alert/fat
- name = "Fat"
- desc = "You ate too much food, lardass. Run around the station and lose some weight."
- icon_state = "fat"
-
-/atom/movable/screen/alert/hungry
- name = "Hungry"
- desc = "Some food would be good right about now."
- icon_state = "hungry"
-
-/atom/movable/screen/alert/starving
- name = "Starving"
- desc = "You're severely malnourished. The hunger pains make moving around a chore."
- icon_state = "starving"
-
/atom/movable/screen/alert/gross
name = "Grossed out."
desc = "That was kind of gross..."
@@ -887,7 +871,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
set_never_round()
return
if(LAZYACCESS(modifiers, CTRL_CLICK) && poll.jump_to_me)
- jump_to_pic_source()
+ jump_to_jump_target()
return
handle_sign_up()
@@ -907,7 +891,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
poll.undo_never_for_this_round(owner)
color = initial(color)
-/atom/movable/screen/alert/poll_alert/proc/jump_to_pic_source()
+/atom/movable/screen/alert/poll_alert/proc/jump_to_jump_target()
if(!poll?.jump_to_me || !isobserver(owner))
return
var/turf/target_turf = get_turf(poll.jump_to_me)
@@ -921,7 +905,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
if(href_list["signup"])
handle_sign_up()
if(href_list["jump"])
- jump_to_pic_source()
+ jump_to_jump_target()
return
/atom/movable/screen/alert/poll_alert/proc/update_signed_up_overlay()
@@ -1034,39 +1018,34 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
// PRIVATE = only edit, use, or override these if you're editing the system as a whole
+/// Gets the placement for the alert based on its index
+/datum/hud/proc/get_ui_alert_placement(index)
+ // Only has support for 5 slots currently
+ if(index > 5)
+ return ""
+
+ return "EAST-1:28,CENTER+[6 - index]:[29 - (index * 2)]"
+
// Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there
/datum/hud/proc/reorganize_alerts(mob/viewmob)
var/mob/screenmob = viewmob || mymob
if(!screenmob.client)
- return
+ return FALSE
var/list/alerts = mymob.alerts
if(!hud_shown)
for(var/i in 1 to alerts.len)
screenmob.client.screen -= alerts[alerts[i]]
- return 1
- for(var/i in 1 to alerts.len)
+ return TRUE
+ for(var/i in 1 to length(alerts))
var/atom/movable/screen/alert/alert = alerts[alerts[i]]
if(alert.icon_state == "template")
alert.icon = ui_style
- switch(i)
- if(1)
- . = ui_alert1
- if(2)
- . = ui_alert2
- if(3)
- . = ui_alert3
- if(4)
- . = ui_alert4
- if(5)
- . = ui_alert5 // Right now there's 5 slots
- else
- . = ""
- alert.screen_loc = .
+ alert.screen_loc = get_ui_alert_placement(i)
screenmob.client.screen |= alert
if(!viewmob)
- for(var/M in mymob.observers)
- reorganize_alerts(M)
- return 1
+ for(var/viewer in mymob.observers)
+ reorganize_alerts(viewer)
+ return TRUE
/atom/movable/screen/alert/Click(location, control, params)
if(!usr || !usr.client)
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index b915e3dc19c86..0b907833f76c7 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -95,6 +95,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
var/atom/movable/screen/stamina
var/atom/movable/screen/healthdoll
var/atom/movable/screen/spacesuit
+ var/atom/movable/screen/hunger
// subtypes can override this to force a specific UI style
var/ui_style
@@ -239,6 +240,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
stamina = null
healthdoll = null
spacesuit = null
+ hunger = null
blobpwrdisplay = null
alien_plasma_display = null
alien_queen_finder = null
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index b12ade0c58d43..5834a3973555c 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -272,6 +272,9 @@
healths = new /atom/movable/screen/healths(null, src)
infodisplay += healths
+ hunger = new /atom/movable/screen/hunger(null, src)
+ infodisplay += hunger
+
healthdoll = new /atom/movable/screen/healthdoll(null, src)
infodisplay += healthdoll
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index dfb5f072d896c..dcf7e230906e3 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -750,3 +750,102 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash)
name = "stamina"
icon_state = "stamina0"
screen_loc = ui_stamina
+
+#define HUNGER_STATE_FAT 2
+#define HUNGER_STATE_FULL 1
+#define HUNGER_STATE_FINE 0
+#define HUNGER_STATE_HUNGRY -1
+#define HUNGER_STATE_STARVING -2
+
+/atom/movable/screen/hunger
+ name = "hunger"
+ icon_state = "hungerbar"
+ base_icon_state = "hungerbar"
+ screen_loc = ui_hunger
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ /// What state of hunger are we in?
+ VAR_PRIVATE/state = HUNGER_STATE_FINE
+ /// What food icon do we show by the bar
+ var/food_icon = 'icons/obj/food/burgerbread.dmi'
+ /// What food icon state do we show by the bar
+ var/food_icon_state = "hburger"
+ /// The image shown by the bar.
+ VAR_PRIVATE/image/food_image
+
+/atom/movable/screen/hunger/Initialize(mapload, datum/hud/hud_owner)
+ . = ..()
+ var/mob/living/hungry = hud_owner?.mymob
+ if(!istype(hungry))
+ return
+
+ if(!ishuman(hungry) || CONFIG_GET(flag/disable_human_mood))
+ screen_loc = ui_mood // Slot in where mood normally is if mood is disabled
+
+ food_image = image(icon = food_icon, icon_state = food_icon_state, pixel_x = -5)
+ food_image.plane = plane
+ food_image.appearance_flags |= KEEP_APART // To be unaffected by filters applied to src
+ food_image.add_filter("simple_outline", 2, outline_filter(1, COLOR_BLACK))
+ underlays += food_image // To be below filters applied to src
+
+ SetInvisibility(INVISIBILITY_ABSTRACT, name) // Start invisible, update later
+ update_appearance()
+
+/atom/movable/screen/hunger/proc/update_hunger_state()
+ var/mob/living/hungry = hud?.mymob
+ if(!istype(hungry))
+ return
+
+ if(HAS_TRAIT(hungry, TRAIT_NOHUNGER) || !hungry.get_organ_slot(ORGAN_SLOT_STOMACH))
+ state = HUNGER_STATE_FINE
+ return
+
+ if(HAS_TRAIT(hungry, TRAIT_FAT))
+ state = HUNGER_STATE_FAT
+ return
+
+ switch(hungry.nutrition)
+ if(NUTRITION_LEVEL_FULL to INFINITY)
+ state = HUNGER_STATE_FULL
+ if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
+ state = HUNGER_STATE_FINE
+ if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
+ state = HUNGER_STATE_HUNGRY
+ if(0 to NUTRITION_LEVEL_STARVING)
+ state = HUNGER_STATE_STARVING
+
+/atom/movable/screen/hunger/update_appearance(updates)
+ var/old_state = state
+ update_hunger_state() // Do this before we call all the other update procs
+ . = ..()
+ if(state == old_state) // Let's not be wasteful
+ return
+ if(state == HUNGER_STATE_FINE)
+ SetInvisibility(INVISIBILITY_ABSTRACT, name)
+ return
+
+ else if(invisibility)
+ RemoveInvisibility(name)
+
+ if(state == HUNGER_STATE_STARVING)
+ if(!get_filter("hunger_outline"))
+ add_filter("hunger_outline", 1, list("type" = "outline", "color" = "#FF0033", "alpha" = 0, "size" = 2))
+ animate(get_filter("hunger_outline"), alpha = 200, time = 1.5 SECONDS, loop = -1)
+ animate(alpha = 0, time = 1.5 SECONDS)
+
+ else if(get_filter("hunger_outline"))
+ remove_filter("hunger_outline")
+
+ // Update color of the food
+ underlays -= food_image
+ food_image.color = state == HUNGER_STATE_FAT ? COLOR_DARK : null
+ underlays += food_image
+
+/atom/movable/screen/hunger/update_icon_state()
+ . = ..()
+ icon_state = "[base_icon_state][state]"
+
+#undef HUNGER_STATE_FAT
+#undef HUNGER_STATE_FULL
+#undef HUNGER_STATE_FINE
+#undef HUNGER_STATE_HUNGRY
+#undef HUNGER_STATE_STARVING
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index d9a0118a06ded..72ed2cabb6936 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -264,6 +264,7 @@
user.changeNext_move(attack_speed)
user.do_attack_animation(attacked_atom)
attacked_atom.attacked_by(src, user)
+ SEND_SIGNAL(src, COMSIG_ITEM_POST_ATTACK_ATOM, attacked_atom, user)
/// Called from [/obj/item/proc/attack_atom] and [/obj/item/proc/attack] if the attack succeeds
/atom/proc/attacked_by(obj/item/attacking_item, mob/living/user)
diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm
index 15c205b6748f0..b893ee701844a 100644
--- a/code/controllers/subsystem/dbcore.dm
+++ b/code/controllers/subsystem/dbcore.dm
@@ -1,3 +1,4 @@
+#define SHUTDOWN_QUERY_TIMELIMIT (1 MINUTES)
SUBSYSTEM_DEF(dbcore)
name = "Database"
flags = SS_TICKER
@@ -6,12 +7,17 @@ SUBSYSTEM_DEF(dbcore)
init_order = INIT_ORDER_DBCORE
priority = FIRE_PRIORITY_DATABASE
- var/failed_connection_timeout = 0
-
var/schema_mismatch = 0
var/db_minor = 0
var/db_major = 0
+ /// Number of failed connection attempts this try. Resets after the timeout or successful connection
var/failed_connections = 0
+ /// Max number of consecutive failures before a timeout (here and not a define so it can be vv'ed mid round if needed)
+ var/max_connection_failures = 5
+ /// world.time that connection attempts can resume
+ var/failed_connection_timeout = 0
+ /// Total number of times connections have had to be timed out.
+ var/failed_connection_timeout_count = 0
var/last_error
@@ -174,18 +180,27 @@ SUBSYSTEM_DEF(dbcore)
/datum/controller/subsystem/dbcore/Shutdown()
shutting_down = TRUE
- to_chat(world, span_boldannounce("Clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]"))
+ var/msg = "Clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]"
+ to_chat(world, span_boldannounce(msg))
+ log_world(msg)
//This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem
+ var/endtime = REALTIMEOFDAY + SHUTDOWN_QUERY_TIMELIMIT
if(SSdbcore.Connect())
- //Execute all waiting queries
+ //Take over control of all active queries
+ var/queries_to_check = queries_active.Copy()
+ queries_active.Cut()
+
+ //Start all waiting queries
for(var/datum/db_query/query in queries_standby)
- run_query_sync(query)
+ run_query(query)
+ queries_to_check += query
queries_standby -= query
- for(var/datum/db_query/query in queries_active)
- //Finish any remaining active qeries
- UNTIL(query.process())
- queries_active -= query
-
+
+ //wait for them all to finish
+ for(var/datum/db_query/query in queries_to_check)
+ UNTIL(query.process() || REALTIMEOFDAY > endtime)
+
+ //log shutdown to the db
var/datum/db_query/query_round_shutdown = SSdbcore.NewQuery(
"UPDATE [format_table_name("round")] SET shutdown_datetime = Now(), end_state = :end_state WHERE id = :round_id",
list("end_state" = SSticker.end_state, "round_id" = GLOB.round_id),
@@ -194,7 +209,9 @@ SUBSYSTEM_DEF(dbcore)
query_round_shutdown.Execute(FALSE)
qdel(query_round_shutdown)
- to_chat(world, span_boldannounce("Done clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]"))
+ msg = "Done clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]"
+ to_chat(world, span_boldannounce(msg))
+ log_world(msg)
if(IsConnected())
Disconnect()
stop_db_daemon()
@@ -230,12 +247,16 @@ SUBSYSTEM_DEF(dbcore)
/datum/controller/subsystem/dbcore/proc/Connect()
if(IsConnected())
return TRUE
+
+ if(connection)
+ Disconnect() //clear the current connection handle so isconnected() calls stop invoking rustg
+ connection = null //make sure its cleared even if runtimes happened
- if(failed_connection_timeout <= world.time) //it's been more than 5 seconds since we failed to connect, reset the counter
+ if(failed_connection_timeout <= world.time) //it's been long enough since we failed to connect, reset the counter
failed_connections = 0
+ failed_connection_timeout = 0
- if(failed_connections > 5) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect for 5 seconds.
- failed_connection_timeout = world.time + 50
+ if(failed_connection_timeout > 0)
return FALSE
if(!CONFIG_GET(flag/sql_enabled))
@@ -271,6 +292,11 @@ SUBSYSTEM_DEF(dbcore)
last_error = result["data"]
log_sql("Connect() failed | [last_error]")
++failed_connections
+ //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect for a time.
+ if(failed_connections > max_connection_failures)
+ failed_connection_timeout_count++
+ //basic exponential backoff algorithm
+ failed_connection_timeout = world.time + ((2 ** failed_connection_timeout_count) SECONDS)
/datum/controller/subsystem/dbcore/proc/CheckSchemaVersion()
if(CONFIG_GET(flag/sql_enabled))
@@ -650,3 +676,4 @@ Ignore_errors instructes mysql to continue inserting rows if some of them have e
/datum/db_query/proc/Close()
rows = null
item = null
+#undef SHUTDOWN_QUERY_TIMELIMIT
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
index 337d9490b9431..e4c580f535abb 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
@@ -136,11 +136,11 @@
SSdynamic.log_dynamic_and_announce("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
candidates = SSpolling.poll_ghost_candidates(
- question = "Looking for volunteers to become [antag_flag] for [name]",
+ question = "Looking for volunteers to become [span_notice(antag_flag)] for [span_danger(name)]",
check_jobban = antag_flag_override,
role = antag_flag || antag_flag_override,
poll_time = 30 SECONDS,
- pic_source = signup_item_path,
+ alert_pic = signup_item_path,
role_name_text = antag_flag,
)
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index c5df419d735ba..0dbfa267882c8 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -160,7 +160,10 @@ SUBSYSTEM_DEF(job)
continue
new_all_occupations += job
name_occupations[job.title] = job
+ for(var/alt_title in job.alternate_titles)
+ name_occupations[alt_title] = job
type_occupations[job_type] = job
+
if(job.job_flags & JOB_NEW_PLAYER_JOINABLE)
new_joinable_occupations += job
if(!LAZYLEN(job.departments_list))
diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm
index 8f865e5d09871..36679fa1d2a02 100644
--- a/code/controllers/subsystem/persistence/_persistence.dm
+++ b/code/controllers/subsystem/persistence/_persistence.dm
@@ -37,6 +37,14 @@ SUBSYSTEM_DEF(persistence)
/// Will be null'd once the persistence system initializes, and never read from again.
var/list/obj/item/storage/photo_album/queued_photo_albums
+ /// A json_database to data/piggy banks.json
+ /// Schema is persistence_id => array of coins, space cash and holochips.
+ var/datum/json_database/piggy_banks_database
+ /// List of persistene ids which piggy banks.
+ var/list/queued_broken_piggy_ids
+
+ var/list/broken_piggy_banks
+
var/rounds_since_engine_exploded = 0
var/delam_highscore = 0
var/tram_hits_this_round = 0
diff --git a/code/controllers/subsystem/persistence/piggy_banks.dm b/code/controllers/subsystem/persistence/piggy_banks.dm
new file mode 100644
index 0000000000000..240fd98ab0c9e
--- /dev/null
+++ b/code/controllers/subsystem/persistence/piggy_banks.dm
@@ -0,0 +1,56 @@
+///This proc is used to initialize holochips, cash and coins inside our persistent piggy bank.
+/datum/controller/subsystem/persistence/proc/load_piggy_bank(obj/item/piggy_bank/piggy)
+ if(isnull(piggy_banks_database))
+ piggy_banks_database = new("data/piggy_banks.json")
+
+ var/list/data = piggy_banks_database.get_key(piggy.persistence_id)
+ if(isnull(data))
+ return
+ var/total_value = 0
+ for(var/iteration in 1 to length(data))
+ var/money_path = text2path(data[iteration])
+ if(!money_path) //For a reason or another, it was removed.
+ continue
+ var/obj/item/spawned
+ if(ispath(money_path, /obj/item/holochip))
+ //We want to safely access the assoc of this position and not that of last key that happened to match this one.
+ var/list/key_and_assoc = data.Copy(iteration, iteration + 1)
+ var/amount = key_and_assoc["[money_path]"]
+ spawned = new money_path (piggy, amount)
+ //the operations are identical to those of chips, but they're different items, so I'll keep them separated.
+ else if(ispath(money_path, /obj/item/stack/spacecash))
+ var/list/key_and_assoc = data.Copy(iteration, iteration + 1)
+ var/amount = key_and_assoc["[money_path]"]
+ spawned = new money_path (piggy, amount)
+ else if(ispath(money_path, /obj/item/coin))
+ spawned = new money_path (piggy)
+ else
+ stack_trace("Unsupported path found in the data of a persistent piggy bank. item: [money_path], id:[piggy.persistence_id]")
+ continue
+ total_value += spawned.get_item_credit_value()
+ if(total_value >= piggy.maximum_value)
+ break
+
+///This proc is used to save money stored inside our persistent the piggy bank for the next time it's loaded.
+/datum/controller/subsystem/persistence/proc/save_piggy_bank(obj/item/piggy_bank/piggy)
+ if(isnull(piggy_banks_database))
+ return
+
+ if(queued_broken_piggy_ids)
+ for(var/broken_id in queued_broken_piggy_ids)
+ piggy_banks_database.remove(broken_id)
+ queued_broken_piggy_ids = null
+
+ var/list/data = list()
+ for(var/obj/item/item as anything in piggy.contents)
+ var/piggy_value = 1
+ if(istype(item, /obj/item/holochip))
+ var/obj/item/holochip/chip = item
+ piggy_value = chip.credits
+ else if(istype(item, /obj/item/stack/spacecash))
+ var/obj/item/stack/spacecash/cash = item
+ piggy_value = cash.amount
+ else if(!istype(item, /obj/item/coin))
+ continue
+ data += list("[item.type]" = piggy_value)
+ piggy_banks_database.set_key(piggy.persistence_id, data)
diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm
index 3fd8bcc125e5c..1f748806d0041 100644
--- a/code/controllers/subsystem/polling.dm
+++ b/code/controllers/subsystem/polling.dm
@@ -27,10 +27,14 @@ SUBSYSTEM_DEF(polling)
* * ignore_category: Optional, A poll category. If a candidate has this category in their ignore list, they won't be polled.
* * flash_window: If TRUE, the candidate's window will flash when they're polled.
* * list/group: A list of candidates to poll.
- * * pic_source: Optional, An /atom or an /image to display on the poll alert.
+ * * alert_pic: Optional, An /atom or an /image to display on the poll alert.
+ * * jump_target: An /atom to teleport/jump to, if alert_pic is an /atom defaults to that.
* * role_name_text: Optional, A string to display in logging / the (default) question. If null, the role name will be used.
* * list/custom_response_messages: Optional, A list of strings to use as responses to the poll. If null, the default responses will be used. see __DEFINES/polls.dm for valid keys to use.
* * start_signed_up: If TRUE, all candidates will start signed up for the poll, making it opt-out rather than opt-in.
+ * * amount_to_pick: Lets you pick candidates and return a single mob or list of mobs that were chosen.
+ * * chat_text_border_icon: Object or path to make an icon of to decorate the chat announcement.
+ * * announce_chosen: Whether we should announce the chosen candidates in chat. This is ignored unless amount_to_pick is greater than 0.
*
* Returns a list of all mobs who signed up for the poll.
*/
@@ -42,18 +46,21 @@ SUBSYSTEM_DEF(polling)
ignore_category = null,
flash_window = TRUE,
list/group = null,
- pic_source,
+ alert_pic,
+ jump_target,
role_name_text,
list/custom_response_messages,
start_signed_up = FALSE,
+ amount_to_pick = 0,
+ chat_text_border_icon,
+ announce_chosen = TRUE,
)
- RETURN_TYPE(/list/mob)
if(group.len == 0)
- return list()
+ return
if(role && !role_name_text)
role_name_text = role
if(role_name_text && !question)
- question = "Do you want to play as [full_capitalize(role_name_text)]?"
+ question = "Do you want to play as [span_notice(role_name_text)]?"
if(!question)
question = "Do you want to play as a special role?"
log_game("Polling candidates [role_name_text ? "for [role_name_text]" : "\"[question]\""] for [DisplayTimeText(poll_time)] seconds")
@@ -61,9 +68,10 @@ SUBSYSTEM_DEF(polling)
// Start firing
total_polls++
- var/jumpable = isatom(pic_source) ? pic_source : null
+ if(!jump_target && isatom(alert_pic))
+ jump_target = alert_pic
- var/datum/candidate_poll/new_poll = new(role_name_text, question, poll_time, ignore_category, jumpable, custom_response_messages)
+ var/datum/candidate_poll/new_poll = new(role_name_text, question, poll_time, ignore_category, jump_target, custom_response_messages)
LAZYADD(currently_polling, new_poll)
var/category = "[new_poll.poll_key]_poll_alert"
@@ -121,83 +129,130 @@ SUBSYSTEM_DEF(polling)
break
// Image to display
- var/image/poll_image
- if(pic_source)
- if(!ispath(pic_source))
- var/atom/the_pic_source = pic_source
- var/old_layer = the_pic_source.layer
- var/old_plane = the_pic_source.plane
- the_pic_source.plane = poll_alert_button.plane
- the_pic_source.layer = FLOAT_LAYER
- poll_alert_button.add_overlay(the_pic_source)
- the_pic_source.layer = old_layer
- the_pic_source.plane = old_plane
+ var/image/poll_image = image('icons/effects/effects.dmi', icon_state = "static")
+ if(alert_pic)
+ if(!ispath(alert_pic))
+ var/mutable_appearance/picture_source = alert_pic
+ poll_image = picture_source
else
- poll_image = image(pic_source, layer = FLOAT_LAYER)
- else
- // Just use a generic image
- poll_image = image('icons/effects/effects.dmi', icon_state = "static", layer = FLOAT_LAYER)
+ poll_image = image(alert_pic)
if(poll_image)
+ poll_image.layer = FLOAT_LAYER
poll_image.plane = poll_alert_button.plane
poll_alert_button.add_overlay(poll_image)
// Chat message
var/act_jump = ""
- if(isatom(pic_source) && isobserver(candidate_mob))
- act_jump = "\[Teleport\]"
- var/act_signup = "\[[start_signed_up ? "Opt out" : "Sign Up"]\]"
+ var/custom_link_style_start = ""
+ var/custom_link_style_end = "style='color:DodgerBlue;font-weight:bold;-dm-text-outline: 1px black'"
+ if(isatom(alert_pic) && isobserver(candidate_mob))
+ act_jump = "[custom_link_style_start]\[Teleport\]"
+ var/act_signup = "[custom_link_style_start]\[[start_signed_up ? "Opt out" : "Sign Up"]\]"
var/act_never = ""
if(ignore_category)
- act_never = "\[Never For This Round\]"
+ act_never = "[custom_link_style_start]\[Never For This Round\]"
if(!duplicate_message_check(alert_poll)) //Only notify people once. They'll notice if there are multiple and we don't want to spam people.
SEND_SOUND(candidate_mob, 'sound/misc/notice2.ogg')
- to_chat(candidate_mob, span_boldnotice(examine_block("Now looking for candidates [role_name_text ? "to play as \an [role_name_text]." : "\"[question]\""] [act_jump] [act_signup] [act_never]")))
+ var/surrounding_icon
+ if(chat_text_border_icon)
+ var/image/surrounding_image
+ if(!ispath(chat_text_border_icon))
+ var/mutable_appearance/border_image = chat_text_border_icon
+ surrounding_image = border_image
+ else
+ surrounding_image = image(chat_text_border_icon)
+ surrounding_icon = icon2html(surrounding_image, candidate_mob, extra_classes = "bigicon")
+ var/final_message = examine_block("[surrounding_icon] [span_ooc(question)] [surrounding_icon]\n[act_jump] [act_signup] [act_never]")
+ to_chat(candidate_mob, final_message)
// Start processing it so it updates visually the timer
START_PROCESSING(SSprocessing, poll_alert_button)
// Sleep until the time is up
UNTIL(new_poll.finished)
- return new_poll.signed_up
-
-/datum/controller/subsystem/polling/proc/poll_ghost_candidates(question, role, check_jobban, poll_time = 30 SECONDS, ignore_category = null, flashwindow = TRUE, pic_source, role_name_text)
+ if(!(amount_to_pick > 0))
+ return new_poll.signed_up
+ for(var/pick in 1 to amount_to_pick)
+ new_poll.chosen_candidates += pick_n_take(new_poll.signed_up)
+ if(announce_chosen)
+ new_poll.announce_chosen(group)
+ if(new_poll.chosen_candidates.len == 1)
+ var/chosen_one = pick(new_poll.chosen_candidates)
+ return chosen_one
+ return new_poll.chosen_candidates
+
+/datum/controller/subsystem/polling/proc/poll_ghost_candidates(
+ question,
+ role,
+ check_jobban,
+ poll_time = 30 SECONDS,
+ ignore_category = null,
+ flashwindow = TRUE,
+ alert_pic,
+ jump_target,
+ role_name_text,
+ list/custom_response_messages,
+ start_signed_up = FALSE,
+ amount_to_pick = 0,
+ chat_text_border_icon,
+ announce_chosen = TRUE,
+)
var/list/candidates = list()
if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE))
- return candidates
-
+ return
for(var/mob/dead/observer/ghost_player in GLOB.player_list)
candidates += ghost_player
+ return poll_candidates(question, role, check_jobban, poll_time, ignore_category, flashwindow, candidates, alert_pic, jump_target, role_name_text, custom_response_messages, start_signed_up, amount_to_pick, chat_text_border_icon, announce_chosen)
- return poll_candidates(question, role, check_jobban, poll_time, ignore_category, flashwindow, candidates, pic_source, role_name_text)
-
-/datum/controller/subsystem/polling/proc/poll_ghost_candidates_for_mob(question, role, check_jobban, poll_time = 30 SECONDS, mob/target_mob, ignore_category = null, flashwindow = TRUE, pic_source, role_name_text)
- var/static/list/mob/currently_polling_mobs = list()
-
- if(currently_polling_mobs.Find(target_mob))
- return list()
-
- currently_polling_mobs += target_mob
-
- var/list/possible_candidates = poll_ghost_candidates(question, role, check_jobban, poll_time, ignore_category, flashwindow, pic_source, role_name_text)
-
- currently_polling_mobs -= target_mob
- if(!target_mob || QDELETED(target_mob) || !target_mob.loc)
- return list()
-
- return possible_candidates
-
-/datum/controller/subsystem/polling/proc/poll_ghost_candidates_for_mobs(question, role, check_jobban, poll_time = 30 SECONDS, list/mobs, ignore_category = null, flashwindow = TRUE, pic_source, role_name_text)
- var/list/candidate_list = poll_ghost_candidates(question, role, check_jobban, poll_time, ignore_category, flashwindow, pic_source, role_name_text)
-
- for(var/mob/potential_mob as anything in mobs)
- if(QDELETED(potential_mob) || !potential_mob.loc)
- mobs -= potential_mob
-
- if(!length(mobs))
+/datum/controller/subsystem/polling/proc/poll_ghosts_for_target(
+ question,
+ role,
+ check_jobban,
+ poll_time = 30 SECONDS,
+ atom/movable/checked_target,
+ ignore_category = null,
+ flashwindow = TRUE,
+ alert_pic,
+ jump_target,
+ role_name_text,
+ list/custom_response_messages,
+ start_signed_up = FALSE,
+ chat_text_border_icon,
+ announce_chosen = TRUE,
+)
+ var/static/list/atom/movable/currently_polling_targets = list()
+ if(currently_polling_targets.Find(checked_target))
+ return
+ currently_polling_targets += checked_target
+ var/mob/chosen_one = poll_ghost_candidates(question, role, check_jobban, poll_time, ignore_category, flashwindow, alert_pic, jump_target, role_name_text, custom_response_messages, start_signed_up, amount_to_pick = 1, chat_text_border_icon = chat_text_border_icon, announce_chosen = announce_chosen)
+ currently_polling_targets -= checked_target
+ if(!checked_target || QDELETED(checked_target) || !checked_target.loc)
+ return null
+ return chosen_one
+
+/datum/controller/subsystem/polling/proc/poll_ghosts_for_targets(
+ question,
+ role,
+ check_jobban,
+ poll_time = 30 SECONDS,
+ list/checked_targets,
+ ignore_category = null,
+ flashwindow = TRUE,
+ alert_pic,
+ jump_target,
+ role_name_text,
+ list/custom_response_messages,
+ start_signed_up = FALSE,
+ chat_text_border_icon,
+)
+ var/list/candidate_list = poll_ghost_candidates(question, role, check_jobban, poll_time, ignore_category, flashwindow, alert_pic, jump_target, role_name_text, custom_response_messages, start_signed_up, chat_text_border_icon = chat_text_border_icon)
+ for(var/atom/movable/potential_target as anything in checked_targets)
+ if(QDELETED(potential_target) || !potential_target.loc)
+ checked_targets -= potential_target
+ if(!length(checked_targets))
return list()
-
return candidate_list
/datum/controller/subsystem/polling/proc/is_eligible(mob/potential_candidate, role, check_jobban, the_ignore_category)
diff --git a/code/controllers/subsystem/queuelinks.dm b/code/controllers/subsystem/queuelinks.dm
index 6a3b828882162..a6d56cf622ec9 100644
--- a/code/controllers/subsystem/queuelinks.dm
+++ b/code/controllers/subsystem/queuelinks.dm
@@ -18,16 +18,30 @@ SUBSYSTEM_DEF(queuelinks)
if(isnull(id))
CRASH("Attempted to add to queue with no ID; [what]")
- var/datum/queue_link/link
- if(isnull(queues[id]))
+ var/datum/queue_link/link = queues[id]
+ if(isnull(link))
link = new /datum/queue_link(id)
queues[id] = link
- else
- link = queues[id]
if(link.add(what, queue_max))
queues -= id
+/**
+ * Pop a queue link without waiting for it to reach its max size.
+ * This is useful for those links that do not have a fixed size and thus may not pop.
+ */
+/datum/controller/subsystem/queuelinks/proc/pop_link(id)
+ if(isnull(id))
+ CRASH("Attempted to pop a queue with no ID")
+
+ var/datum/queue_link/link = queues[id]
+ if(isnull(queues[id]))
+ CRASH("Attempted to pop a non-existant queue: [id]")
+
+ link.pop()
+ queues -= id
+
+
/datum/queue_link
/// atoms in our queue
var/list/partners = list()
@@ -50,17 +64,17 @@ SUBSYSTEM_DEF(queuelinks)
if(queue_max != 0 && max != 0 && max != queue_max)
CRASH("Tried to change queue size to [max] from [queue_max]!")
else if(!queue_max)
- queue_max = max
-
+ queue_max = max
+
if(!queue_max || length(partners) < queue_max)
return
-
+
pop()
return TRUE
/datum/queue_link/proc/pop()
for(var/atom/item as anything in partners)
- item.MatchedLinks(id, partners)
+ item.MatchedLinks(id, partners - item)
qdel(src)
/datum/queue_link/Destroy()
diff --git a/code/controllers/subsystem/stock_market.dm b/code/controllers/subsystem/stock_market.dm
index c9f632c7faf12..6c4341adc8d8a 100644
--- a/code/controllers/subsystem/stock_market.dm
+++ b/code/controllers/subsystem/stock_market.dm
@@ -1,7 +1,7 @@
SUBSYSTEM_DEF(stock_market)
name = "Stock Market"
- wait = 20 SECONDS
+ wait = 60 SECONDS
init_order = INIT_ORDER_DEFAULT
runlevels = RUNLEVEL_GAME
@@ -28,7 +28,7 @@ SUBSYSTEM_DEF(stock_market)
materials_trends[possible_market] = rand(MARKET_TREND_DOWNWARD,MARKET_TREND_UPWARD) //aka -1 to 1
materials_trend_life += possible_market
- materials_trend_life[possible_market] = rand(1,10)
+ materials_trend_life[possible_market] = rand(1,3)
materials_quantity += possible_market
materials_quantity[possible_market] = possible_market.tradable_base_quantity + (rand(-(possible_market.tradable_base_quantity) * 0.5, possible_market.tradable_base_quantity * 0.5))
@@ -80,7 +80,7 @@ SUBSYSTEM_DEF(stock_market)
materials_trends[mat] = MARKET_TREND_DOWNWARD
else
materials_trends[mat] = MARKET_TREND_STABLE
- materials_trend_life[mat] = rand(3,10) // Change our trend life for x number of fires of the subsystem
+ materials_trend_life[mat] = rand(1,3) // Change our trend life for x number of fires of the subsystem
else
materials_trend_life[mat] -= 1
@@ -88,14 +88,14 @@ SUBSYSTEM_DEF(stock_market)
var/quantity_change = 0
switch(trend)
if(MARKET_TREND_UPWARD)
- price_change = ROUND_UP(gaussian(price_units * 0.1, price_baseline * 0.05)) //If we don't ceil, small numbers will get trapped at low values
- quantity_change = -round(gaussian(quantity_baseline * 0.05, quantity_baseline * 0.05))
+ price_change = ROUND_UP(gaussian(price_units * 0.30, price_baseline * 0.15)) //If we don't ceil, small numbers will get trapped at low values
+ quantity_change = -round(gaussian(quantity_baseline * 0.15, quantity_baseline * 0.15))
if(MARKET_TREND_STABLE)
price_change = round(gaussian(0, price_baseline * 0.01))
- quantity_change = round(gaussian(0, quantity_baseline * 0.01))
+ quantity_change = round(gaussian(0, quantity_baseline * 0.5))
if(MARKET_TREND_DOWNWARD)
- price_change = -ROUND_UP(gaussian(price_units * 0.1, price_baseline * 0.05))
- quantity_change = round(gaussian(quantity_baseline * 0.05, quantity_baseline * 0.05))
+ price_change = -ROUND_UP(gaussian(price_units * 0.3, price_baseline * 0.15))
+ quantity_change = round(gaussian(quantity_baseline * 0.15, quantity_baseline * 0.15))
materials_prices[mat] = round(clamp(price_units + price_change, price_minimum, price_maximum))
materials_quantity[mat] = round(clamp(stock_quantity + quantity_change, 0, quantity_baseline * 2))
diff --git a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm
index a7d43d600b1cd..14f0d03207959 100644
--- a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm
+++ b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm
@@ -50,7 +50,9 @@
if(living_mob.see_invisible < the_target.invisibility) //Target's invisible to us, forget it
return FALSE
- if(isturf(living_mob.loc) && isturf(the_target.loc) && living_mob.z != the_target.z) // z check will always fail if target is in a mech or pawn is shapeshifted or jaunting
+ if(!isturf(living_mob.loc))
+ return FALSE
+ if(isturf(the_target.loc) && living_mob.z != the_target.z) // z check will always fail if target is in a mech or pawn is shapeshifted or jaunting
return FALSE
if(isliving(the_target)) //Targeting vs living mobs
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index 664bf50fd666c..29cf637a86e95 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -45,15 +45,18 @@
/datum/brain_trauma/special/imaginary_friend/proc/make_friend()
friend = new(get_turf(owner), owner)
-/// Tries an orbit poll for the imaginary friend
+/// Tries a poll for the imaginary friend
/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(add_friend))
- owner.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_IMAGINARYFRIEND, \
- job_bans = ROLE_PAI, \
- title = "[owner.real_name]'s imaginary friend", \
- to_call = to_call, \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ question = "Do you want to play as [span_danger("[owner.real_name]'s")] [span_notice("imaginary friend")]?",
+ check_jobban = ROLE_PAI,
+ poll_time = 20 SECONDS,
+ checked_target = owner,
+ ignore_category = POLL_IGNORE_IMAGINARYFRIEND,
+ alert_pic = owner,
+ role_name_text = "imaginary friend",
)
+ add_friend(chosen_one)
/// Yay more friends!
/datum/brain_trauma/special/imaginary_friend/proc/add_friend(mob/dead/observer/ghost)
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index fc30d7fb3b8f6..d78f2abe9bcf0 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -419,7 +419,7 @@
desc = "Patient seems to oxidise things around them at random, and seem to believe they are aiding a creature in climbing a mountin."
scan_desc = "C_)L(#_I_##M;B"
gain_text = span_warning("The rusted climb shall finish at the peak")
- lose_text = span_notice("The rusted climb? Whats that? An odd dream to be sure.")
+ lose_text = span_notice("The rusted climb? What's that? An odd dream to be sure.")
random_gain = FALSE
/datum/brain_trauma/severe/rusting/on_life(seconds_per_tick, times_fired)
diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm
index f6e83c9537c0a..adad6491cf45a 100644
--- a/code/datums/brain_damage/split_personality.dm
+++ b/code/datums/brain_damage/split_personality.dm
@@ -34,13 +34,16 @@
/// Attempts to get a ghost to play the personality
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(schism))
- owner.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_SPLITPERSONALITY, \
- job_bans = ROLE_PAI, \
- title = "[owner.real_name]'s [poll_role]", \
- to_call = to_call, \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ question = "Do you want to play as [span_danger("[owner.real_name]'s")] [span_notice(poll_role)]?",
+ check_jobban = ROLE_PAI,
+ poll_time = 20 SECONDS,
+ checked_target = owner,
+ ignore_category = POLL_IGNORE_SPLITPERSONALITY,
+ alert_pic = owner,
+ role_name_text = poll_role,
)
+ schism(chosen_one)
/// Ghost poll has concluded
/datum/brain_trauma/severe/split_personality/proc/schism(mob/dead/observer/ghost)
@@ -211,10 +214,9 @@
/datum/brain_trauma/severe/split_personality/brainwashing/get_ghost()
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as [owner.real_name]'s brainwashed mind?", poll_time = 7.5 SECONDS, target_mob = stranger_backseat, pic_source = owner, role_name_text = "brainwashed mind")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/C = pick(candidates)
- stranger_backseat.key = C.key
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger("[owner.real_name]'s")] brainwashed mind?", poll_time = 7.5 SECONDS, checked_target = stranger_backseat, alert_pic = owner, role_name_text = "brainwashed mind")
+ if(chosen_one)
+ stranger_backseat.key = chosen_one.key
else
qdel(src)
diff --git a/code/datums/candidate_poll.dm b/code/datums/candidate_poll.dm
index 6ccd43c01fded..fc86d70f54690 100644
--- a/code/datums/candidate_poll.dm
+++ b/code/datums/candidate_poll.dm
@@ -28,6 +28,7 @@
POLL_RESPONSE_TOO_LATE_TO_UNREGISTER = "It's too late to unregister yourself, selection has already begun!",
POLL_RESPONSE_UNREGISTERED = "You have been unregistered as a candidate for %ROLE%. You can sign up again before the poll ends.",
)
+ var/list/chosen_candidates = list()
/datum/candidate_poll/New(
polled_role,
@@ -131,3 +132,14 @@
/datum/candidate_poll/proc/time_left()
return duration - (world.time - time_started)
+
+
+/// Print to chat which candidate was selected
+/datum/candidate_poll/proc/announce_chosen(list/poll_recipients)
+ if(!length(chosen_candidates))
+ return
+ for(var/mob/poll_recipient as anything in poll_recipients)
+ for(var/mob/chosen as anything in chosen_candidates)
+ if(isnull(chosen))
+ continue
+ to_chat(poll_recipient, span_ooc("[isobserver(poll_recipient) ? FOLLOW_LINK(poll_recipient, chosen) : null][span_warning(" [full_capitalize(role)] Poll: ")][key_name(chosen, include_name = FALSE)] was selected."))
diff --git a/code/datums/components/bullet_intercepting.dm b/code/datums/components/bullet_intercepting.dm
index c176de54b94c5..32e757c1823e1 100644
--- a/code/datums/components/bullet_intercepting.dm
+++ b/code/datums/components/bullet_intercepting.dm
@@ -12,8 +12,10 @@
var/mob/wearer
/// Callback called when we catch a projectile
var/datum/callback/on_intercepted
+ /// Number of things we can block before we delete ourself (stop being able to block)
+ var/block_charges = INFINITY
-/datum/component/bullet_intercepting/Initialize(block_chance = 2, block_type = BULLET, active_slots, datum/callback/on_intercepted)
+/datum/component/bullet_intercepting/Initialize(block_chance = 2, block_type = BULLET, active_slots, datum/callback/on_intercepted, block_charges = INFINITY)
. = ..()
if (!isitem(parent))
return COMPONENT_INCOMPATIBLE
@@ -21,6 +23,7 @@
src.block_type = block_type
src.active_slots = active_slots
src.on_intercepted = on_intercepted
+ src.block_charges = block_charges
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_parent_equipped))
RegisterSignal(parent, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_unequipped))
@@ -55,11 +58,14 @@
/// Called when wearer is shot, check if we're going to block the hit
/datum/component/bullet_intercepting/proc/on_wearer_shot(mob/living/victim, list/signal_args, obj/projectile/bullet)
SIGNAL_HANDLER
- if (victim != wearer || victim.stat == DEAD || bullet.armor_flag != block_type )
- return
+ if (victim != wearer || victim.stat == DEAD || bullet.armor_flag != block_type)
+ return NONE
if (!prob(block_chance))
- return
+ return NONE
on_intercepted?.Invoke(victim, bullet)
+ block_charges--
+ if (block_charges <= 0)
+ qdel(src)
return PROJECTILE_INTERRUPT_HIT
/// Called when wearer is deleted, stop tracking them
diff --git a/code/datums/components/ghost_direct_control.dm b/code/datums/components/ghost_direct_control.dm
index a131a2d3ca728..de5bca4fcadde 100644
--- a/code/datums/components/ghost_direct_control.dm
+++ b/code/datums/components/ghost_direct_control.dm
@@ -16,8 +16,11 @@
/datum/component/ghost_direct_control/Initialize(
ban_type = ROLE_SENTIENCE,
role_name = null,
+ poll_question = null,
poll_candidates = TRUE,
+ poll_announce_chosen = TRUE,
poll_length = 10 SECONDS,
+ poll_chat_border_icon = null,
poll_ignore_key = POLL_IGNORE_SENTIENCE_POTION,
assumed_control_message = null,
datum/callback/extra_control_checks,
@@ -36,7 +39,7 @@
LAZYADD(GLOB.joinable_mobs[format_text("[initial(mob_parent.name)]")], mob_parent)
if (poll_candidates)
- INVOKE_ASYNC(src, PROC_REF(request_ghost_control), role_name || "[parent]", poll_length, poll_ignore_key)
+ INVOKE_ASYNC(src, PROC_REF(request_ghost_control), poll_question, role_name || "[parent]", poll_length, poll_ignore_key, poll_announce_chosen, poll_chat_border_icon)
/datum/component/ghost_direct_control/RegisterWithParent()
. = ..()
@@ -70,23 +73,26 @@
examine_text += span_boldnotice("You could take control of this mob by clicking on it.")
/// Send out a request for a brain
-/datum/component/ghost_direct_control/proc/request_ghost_control(role_name, poll_length, poll_ignore_key)
- if (!(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER))
+/datum/component/ghost_direct_control/proc/request_ghost_control(poll_question, role_name, poll_length, poll_ignore_key, poll_announce_chosen, poll_chat_border_icon)
+ if(!(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER))
return
awaiting_ghosts = TRUE
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(
- question = "Do you want to play as [role_name]?",
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ question = poll_question,
check_jobban = ban_type,
role = ban_type,
poll_time = poll_length,
+ checked_target = parent,
ignore_category = poll_ignore_key,
- pic_source = parent,
+ alert_pic = parent,
role_name_text = role_name,
+ chat_text_border_icon = poll_chat_border_icon,
+ announce_chosen = poll_announce_chosen,
)
awaiting_ghosts = FALSE
- if (!LAZYLEN(candidates))
+ if(isnull(chosen_one))
return
- assume_direct_control(pick(candidates))
+ assume_direct_control(chosen_one)
/// A ghost clicked on us, they want to get in this body
/datum/component/ghost_direct_control/proc/on_ghost_clicked(mob/our_mob, mob/dead/observer/hopeful_ghost)
diff --git a/code/datums/components/orbit_poll.dm b/code/datums/components/orbit_poll.dm
deleted file mode 100644
index ceb85d16d64c7..0000000000000
--- a/code/datums/components/orbit_poll.dm
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * A replacement for the standard poll_ghost_candidate.
- * Use this to subtly ask players to join - it picks from orbiters.
- * Please use named arguments for this.
- *
- * @params ignore_key - Required so it doesn't spam
- * @params job_bans - You can insert a list or single items here.
- * @params cb - Invokes this proc and appends the poll winner as the last argument, mob/dead/observer/ghost
- * @params title - Optional. Useful if the role name does not match the parent.
- *
- * @usage
- * ```
- * var/datum/callback/cb = CALLBACK(src, PROC_REF(do_stuff), arg1, arg2)
- * AddComponent(/datum/component/orbit_poll, \
- * ignore_key = POLL_IGNORE_EXAMPLE, \
- * job_bans = ROLE_EXAMPLE or list(ROLE_EXAMPLE, ROLE_EXAMPLE2), \
- * title = "Use this if you want something other than the parent name", \
- * to_call = cb, \
- * )
- */
-/datum/component/orbit_poll
- /// Prevent players with this ban from being selected
- var/list/job_bans = list()
- /// Title of the role to announce after it's done
- var/title
- /// Proc to invoke whenever the poll is complete
- var/datum/callback/to_call
-
-/datum/component/orbit_poll/Initialize( \
- ignore_key, \
- list/job_bans, \
- datum/callback/to_call, \
- title, \
- header = "Ghost Poll", \
- custom_message, \
- timeout = 20 SECONDS \
-)
- . = ..()
- if (!isatom(parent))
- return COMPONENT_INCOMPATIBLE
-
- var/atom/owner = parent
-
- src.job_bans |= job_bans
- src.title = title || owner.name
- src.to_call = to_call
-
- var/message = custom_message || "[capitalize(src.title)] is looking for volunteers"
-
- notify_ghosts(
- "[message]. An orbiter will be chosen in [DisplayTimeText(timeout)].\n",
- source = parent,
- header = "Volunteers requested",
- custom_link = " (Ignore)",
- ignore_key = ignore_key,
- notify_flags = NOTIFY_CATEGORY_NOFLASH,
- )
-
- addtimer(CALLBACK(src, PROC_REF(end_poll)), timeout, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE|TIMER_DELETE_ME)
-
-/datum/component/orbit_poll/Topic(href, list/href_list)
- if(!href_list["ignore"])
- return
-
- var/mob/user = usr
-
- var/ignore_key = href_list["ignore"]
- if(tgui_alert(user, "Ignore further [title] alerts?", "Ignore Alert", list("Yes", "No"), 20 SECONDS, TRUE) != "Yes")
- return
-
- GLOB.poll_ignore[ignore_key] |= user.ckey
-
-/// Concludes the poll, picking one of the orbiters
-/datum/component/orbit_poll/proc/end_poll()
- if(QDELETED(parent))
- return
-
- var/list/candidates = list()
- var/atom/owner = parent
-
- var/datum/component/orbiter/orbiter_comp = owner.GetComponent(/datum/component/orbiter)
- if(isnull(orbiter_comp))
- phone_home()
- return
-
- for(var/mob/dead/observer/ghost as anything in orbiter_comp.orbiter_list)
- var/client/ghost_client = ghost.client
-
- if(QDELETED(ghost) || isnull(ghost_client))
- continue
-
- if(is_banned_from(ghost.ckey, job_bans))
- continue
-
- var/datum/preferences/ghost_prefs = ghost_client.prefs
- if(isnull(ghost_prefs))
- candidates += ghost // we'll assume they wanted to be picked despite prefs being null for whatever fucked up reason
- continue
-
- if(!ghost_prefs.read_preference(/datum/preference/toggle/ghost_roles))
- continue
- if(!isnull(ghost_client.holder) && !ghost_prefs.read_preference(/datum/preference/toggle/ghost_roles_as_admin))
- continue
-
- candidates += ghost
-
- pick_and_offer(candidates)
-
-/// Takes a list, picks a candidate, and offers the role to them.
-/datum/component/orbit_poll/proc/pick_and_offer(list/volunteers)
- if(length(volunteers) <= 0)
- phone_home()
- return
-
- var/mob/dead/observer/chosen = pick(volunteers)
-
- if(isnull(chosen))
- phone_home()
- return
-
- SEND_SOUND(chosen, 'sound/misc/notice2.ogg')
- var/response = tgui_alert(chosen, "Do you want to assume the role of [title]?", "Orbit Polling", list("Yes", "No"), 10 SECONDS)
- if(response != "Yes")
- var/reusable_list = volunteers - chosen
- return pick_and_offer(reusable_list)
-
- deadchat_broadcast("[key_name(chosen, include_name = FALSE)] was selected for the role ([title]).", "Ghost Poll: ", parent)
- phone_home(chosen)
-
-/// Make sure to call your parents my dude
-/datum/component/orbit_poll/proc/phone_home(mob/dead/observer/chosen)
- to_call.Invoke(chosen)
- qdel(src)
diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm
index 1220614e9c386..5e79b28fd5724 100644
--- a/code/datums/components/payment.dm
+++ b/code/datums/components/payment.dm
@@ -19,11 +19,6 @@
var/datum/bank_account/target_acc
///Does this payment component respect same-department-discount?
var/department_discount = FALSE
- ///A static typecache of all the money-based items that can be actively used as currency.
- var/static/list/allowed_money = typecacheof(list(
- /obj/item/stack/spacecash,
- /obj/item/holochip,
- /obj/item/coin))
/datum/component/payment/Initialize(_cost, _target, _style)
target_acc = _target
@@ -80,13 +75,13 @@
//Here is all the possible non-ID payment methods.
var/list/counted_money = list()
var/physical_cash_total = 0
- for(var/obj/item/credit in typecache_filter_list(user.get_all_contents(), allowed_money)) //Coins, cash, and credits.
+ for(var/obj/item/credit in typecache_filter_list(user.get_all_contents(), GLOB.allowed_money)) //Coins, cash, and credits.
if(physical_cash_total > total_cost)
break
physical_cash_total += credit.get_item_credit_value()
counted_money += credit
- if(is_type_in_typecache(user.pulling, allowed_money) && (physical_cash_total < total_cost)) //Coins(Pulled).
+ if(is_type_in_typecache(user.pulling, GLOB.allowed_money) && (physical_cash_total < total_cost)) //Coins(Pulled).
var/obj/item/counted_credit = user.pulling
physical_cash_total += counted_credit.get_item_credit_value()
counted_money += counted_credit
@@ -134,9 +129,11 @@
* Attempts to charge a mob, user, an integer number of credits, total_cost, directly from an ID card/bank account.
*/
/datum/component/payment/proc/handle_card(mob/living/user, obj/item/card/id/idcard, total_cost)
- var/atom/atom_parent = parent
+ var/atom/movable/atom_parent = parent
if(!idcard)
+ if(transaction_style == PAYMENT_VENDING)
+ to_chat(user, span_warning("No card found."))
return FALSE
if(!idcard?.registered_account)
switch(transaction_style)
@@ -146,6 +143,13 @@
to_chat(user, span_warning("ARE YOU JOKING. YOU DON'T HAVE A BANK ACCOUNT ON YOUR ID YOU IDIOT."))
if(PAYMENT_CLINICAL)
to_chat(user, span_warning("ID Card lacks a bank account. Advancing."))
+ if(PAYMENT_VENDING)
+ to_chat(user, span_warning("No account found."))
+
+ return FALSE
+
+ if(!idcard.registered_account.account_job)
+ atom_parent.say("Departmental accounts have been blacklisted from personal expenses due to embezzlement.")
return FALSE
if(!(idcard.registered_account.has_money(total_cost)))
@@ -156,6 +160,8 @@
to_chat(user, span_warning("YOU MORON. YOU ABSOLUTE BAFOON. YOU INSUFFERABLE TOOL. YOU ARE POOR."))
if(PAYMENT_CLINICAL)
to_chat(user, span_warning("ID Card lacks funds. Aborting."))
+ if(PAYMENT_VENDING)
+ to_chat(user, span_warning("You do not possess the funds to purchase that."))
atom_parent.balloon_alert(user, "needs [total_cost] credit\s!")
return FALSE
target_acc.transfer_money(idcard.registered_account, total_cost, "Nanotrasen: Usage of Corporate Machinery")
diff --git a/code/datums/components/spirit_holding.dm b/code/datums/components/spirit_holding.dm
index cb626801d86dc..e2b1cfb96bc3b 100644
--- a/code/datums/components/spirit_holding.dm
+++ b/code/datums/components/spirit_holding.dm
@@ -37,9 +37,10 @@
///signal fired on self attacking parent
/datum/component/spirit_holding/proc/on_attack_self(datum/source, mob/user)
SIGNAL_HANDLER
+ INVOKE_ASYNC(src, PROC_REF(get_ghost), user)
+/datum/component/spirit_holding/proc/get_ghost(mob/user)
var/atom/thing = parent
-
if(attempting_awakening)
thing.balloon_alert(user, "already channeling!")
return
@@ -47,20 +48,23 @@
thing.balloon_alert(user, "spirits are unwilling!")
to_chat(user, span_warning("Anomalous otherworldly energies block you from awakening [parent]!"))
return
-
attempting_awakening = TRUE
thing.balloon_alert(user, "channeling...")
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(affix_spirit), user)
- parent.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_POSSESSED_BLADE, \
- job_bans = ROLE_PAI, \
- to_call = to_call, \
- title = "Spirit of [user.real_name]'s blade", \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ question = "Do you want to play as [span_notice("Spirit of [span_danger("[user.real_name]'s")] blade")]?",
+ check_jobban = ROLE_PAI,
+ poll_time = 20 SECONDS,
+ checked_target = thing,
+ ignore_category = POLL_IGNORE_POSSESSED_BLADE,
+ alert_pic = thing,
+ role_name_text = "possessed blade",
+ chat_text_border_icon = thing,
)
+ affix_spirit(user, chosen_one)
/// On conclusion of the ghost poll
/datum/component/spirit_holding/proc/affix_spirit(mob/awakener, mob/dead/observer/ghost)
+
var/atom/thing = parent
if(isnull(ghost))
diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm
index a0d0317d75540..b2bae5cffeef8 100644
--- a/code/datums/components/tackle.dm
+++ b/code/datums/components/tackle.dm
@@ -443,7 +443,7 @@
if(human_sacker.get_mob_height() <= HUMAN_HEIGHT_SHORTEST) //JUST YOU WAIT TILL I FIND A CHAIR, BUDDY, THEN YOU'LL BE SORRY
attack_mod -= 2
- if(human_sacker.mob_mood.sanity_level == SANITY_INSANE) //I've gone COMPLETELY INSANE
+ if(human_sacker.mob_mood.sanity_level == SANITY_LEVEL_INSANE) //I've gone COMPLETELY INSANE
attack_mod += 15
human_sacker.adjustStaminaLoss(100) //AHAHAHAHAHAHAHAHA
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index 741520ed6ae61..4cf5b4148fed2 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -84,13 +84,12 @@
/datum/disease/transformation/proc/replace_banned_player(mob/living/new_mob) // This can run well after the mob has been transferred, so need a handle on the new mob to kill it if needed.
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as [affected_mob.real_name]?", check_jobban = bantype, role = bantype, poll_time = 5 SECONDS, target_mob = affected_mob, pic_source = affected_mob, role_name_text = "transformation victim")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/C = pick(candidates)
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_notice(affected_mob.real_name)]?", check_jobban = bantype, role = bantype, poll_time = 5 SECONDS, checked_target = affected_mob, alert_pic = affected_mob, role_name_text = "transformation victim")
+ if(chosen_one)
to_chat(affected_mob, span_userdanger("Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!"))
- message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbanned player.")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbanned player.")
affected_mob.ghostize(FALSE)
- affected_mob.key = C.key
+ affected_mob.key = chosen_one.key
else
to_chat(new_mob, span_userdanger("Your mob has been claimed by death! Appeal your job ban if you want to avoid this in the future!"))
new_mob.investigate_log("has been killed because there was no one to replace them as a job-banned player.", INVESTIGATE_DEATHS)
diff --git a/code/datums/elements/bed_tucking.dm b/code/datums/elements/bed_tucking.dm
index 70b10d4a58c0c..58f5640c31c75 100644
--- a/code/datums/elements/bed_tucking.dm
+++ b/code/datums/elements/bed_tucking.dm
@@ -1,7 +1,7 @@
/// Tucking element, for things that can be tucked into bed.
/datum/element/bed_tuckable
element_flags = ELEMENT_BESPOKE
- argument_hash_start_idx = 2
+ argument_hash_start_idx = 3
/// our pixel_x offset - how much the item moves x when in bed (+x is closer to the pillow)
var/x_offset = 0
/// our pixel_y offset - how much the item move y when in bed (-y is closer to the middle)
@@ -11,7 +11,7 @@
/// our starting angle for the item
var/starting_angle = 0
-/datum/element/bed_tuckable/Attach(obj/target, x = 0, y = 0, rotation = 0)
+/datum/element/bed_tuckable/Attach(obj/target, mapload = FALSE, x = 0, y = 0, rotation = 0)
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
@@ -20,6 +20,13 @@
y_offset = y
starting_angle = rotation
RegisterSignal(target, COMSIG_ITEM_ATTACK_ATOM, PROC_REF(tuck_into_bed))
+ if(!mapload)
+ return
+ var/turf/our_home = get_turf(target)
+ var/obj/structure/bed/eepy = locate(/obj/structure/bed) in our_home
+ if(isnull(eepy))
+ return
+ tuck(target, eepy)
/datum/element/bed_tuckable/Detach(obj/target)
. = ..()
@@ -42,6 +49,10 @@
return
to_chat(tucker, span_notice("You lay [tucked] out on [target_bed]."))
+ tuck(tucked, target_bed)
+ return COMPONENT_NO_AFTERATTACK
+
+/datum/element/bed_tuckable/proc/tuck(obj/item/tucked, obj/structure/bed/target_bed)
tucked.dir = target_bed.dir
tucked.pixel_x = target_bed.dir & EAST ? -x_offset : x_offset
tucked.pixel_y = y_offset
@@ -50,8 +61,6 @@
tucked.transform = turn(tucked.transform, rotation_degree)
RegisterSignal(tucked, COMSIG_ITEM_PICKUP, PROC_REF(untuck))
- return COMPONENT_NO_AFTERATTACK
-
/**
* If we rotate our object, then we need to un-rotate it when it's picked up
*
diff --git a/code/datums/elements/shatters_when_thrown.dm b/code/datums/elements/can_shatter.dm
similarity index 69%
rename from code/datums/elements/shatters_when_thrown.dm
rename to code/datums/elements/can_shatter.dm
index cbb5994852c81..73b025ad83c08 100644
--- a/code/datums/elements/shatters_when_thrown.dm
+++ b/code/datums/elements/can_shatter.dm
@@ -1,7 +1,8 @@
/**
* When attached to something, will make that thing shatter into shards on throw impact or z level falling
+ * Or even when used as a weapon if the 'shatters_as_weapon' arg is TRUE
*/
-/datum/element/shatters_when_thrown
+/datum/element/can_shatter
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
@@ -12,7 +13,12 @@
/// What sound plays when the thing we're attached to shatters
var/shattering_sound
-/datum/element/shatters_when_thrown/Attach(datum/target, shard_type = /obj/item/plate_shard, number_of_shards = 5, shattering_sound = 'sound/items/ceramic_break.ogg')
+/datum/element/can_shatter/Attach(datum/target,
+ shard_type = /obj/item/plate_shard,
+ number_of_shards = 5,
+ shattering_sound = 'sound/items/ceramic_break.ogg',
+ shatters_as_weapon = FALSE,
+ )
. = ..()
if(!ismovable(target))
@@ -24,26 +30,28 @@
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(on_throw_impact))
RegisterSignal(target, COMSIG_ATOM_ON_Z_IMPACT, PROC_REF(on_z_impact))
+ if(shatters_as_weapon)
+ RegisterSignal(target, COMSIG_ITEM_POST_ATTACK_ATOM, PROC_REF(on_post_attack_atom))
-/datum/element/shatters_when_thrown/Detach(datum/target)
+/datum/element/can_shatter/Detach(datum/target)
. = ..()
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT, COMSIG_ATOM_ON_Z_IMPACT))
/// Tells the parent to shatter if we impact a lower zlevel
-/datum/element/shatters_when_thrown/proc/on_z_impact(datum/source, turf/impacted_turf, levels)
+/datum/element/can_shatter/proc/on_z_impact(datum/source, turf/impacted_turf, levels)
SIGNAL_HANDLER
shatter(source, impacted_turf)
/// Tells the parent to shatter if we are thrown and impact something
-/datum/element/shatters_when_thrown/proc/on_throw_impact(datum/source, atom/hit_atom)
+/datum/element/can_shatter/proc/on_throw_impact(datum/source, atom/hit_atom)
SIGNAL_HANDLER
shatter(source, hit_atom)
/// Handles the actual shattering part, throwing shards of whatever is defined on the component everywhere
-/datum/element/shatters_when_thrown/proc/shatter(atom/movable/source, atom/hit_atom)
+/datum/element/can_shatter/proc/shatter(atom/movable/source, atom/hit_atom)
var/generator/scatter_gen = generator(GEN_CIRCLE, 0, 48, NORMAL_RAND)
var/scatter_turf = get_turf(hit_atom)
@@ -64,3 +72,7 @@
return
else
qdel(source)
+
+/datum/element/can_shatter/proc/on_post_attack_atom(obj/item/source, atom/attacked_atom, mob/living/user)
+ SIGNAL_HANDLER
+ shatter(source, attacked_atom)
diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm
index 28433ba9064b6..6b9465bf46af0 100644
--- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm
+++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm
@@ -335,3 +335,8 @@
name = "Flower Worn"
icon_file = 'icons/mob/clothing/head/hydroponics.dmi'
json_config = 'code/datums/greyscale/json_configs/simple_flower_worn.json'
+
+/datum/greyscale_config/piggy_bank
+ name = "Piggy Bank"
+ icon_file = 'icons/obj/fluff/general.dmi'
+ json_config = 'code/datums/greyscale/json_configs/piggy_bank.json'
diff --git a/code/datums/greyscale/json_configs/piggy_bank.json b/code/datums/greyscale/json_configs/piggy_bank.json
new file mode 100644
index 0000000000000..71876213e197f
--- /dev/null
+++ b/code/datums/greyscale/json_configs/piggy_bank.json
@@ -0,0 +1,10 @@
+{
+ "piggy_bank": [
+ {
+ "type": "icon_state",
+ "icon_state": "piggy_bank",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ }
+ ]
+}
diff --git a/code/datums/lazy_template.dm b/code/datums/lazy_template.dm
index 0a5e8e5331413..3b19a17a179da 100644
--- a/code/datums/lazy_template.dm
+++ b/code/datums/lazy_template.dm
@@ -13,6 +13,8 @@
var/map_dir = "_maps/templates/lazy_templates"
/// The filename (without extension) of the map to load
var/map_name
+ /// place_on_top: Whether to use /turf/proc/PlaceOnTop rather than /turf/proc/ChangeTurf
+ var/place_on_top = FALSE
/datum/lazy_template/New()
reservations = list()
@@ -83,6 +85,7 @@
bottom_left.z,
z_upper = z_idx,
z_lower = z_idx,
+ place_on_top = place_on_top,
)
for(var/turf/turf as anything in block(bottom_left, top_right))
loaded_turfs += turf
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index 3c5f6ab62d0cb..b19db61c81e28 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -47,12 +47,12 @@
/datum/material/glass/on_applied_obj(atom/source, amount, material_flags)
. = ..()
if(!isstack(source))
- source.AddElement(/datum/element/shatters_when_thrown, shard_type, round(amount / SHEET_MATERIAL_AMOUNT), SFX_SHATTER)
+ source.AddElement(/datum/element/can_shatter, shard_type, round(amount / SHEET_MATERIAL_AMOUNT), SFX_SHATTER)
/datum/material/glass/on_removed(atom/source, amount, material_flags)
. = ..()
- source.RemoveElement(/datum/element/shatters_when_thrown, shard_type)
+ source.RemoveElement(/datum/element/can_shatter, shard_type)
/*
Color matrices are like regular colors but unlike with normal colors, you can go over 255 on a channel.
diff --git a/code/datums/mood.dm b/code/datums/mood.dm
index 150220cfbcfdb..c61ceea0faf6b 100644
--- a/code/datums/mood.dm
+++ b/code/datums/mood.dm
@@ -92,7 +92,6 @@
set_sanity(sanity + 0.4 * seconds_per_tick, SANITY_NEUTRAL, SANITY_MAXIMUM)
if(MOOD_LEVEL_HAPPY4)
set_sanity(sanity + 0.6 * seconds_per_tick, SANITY_NEUTRAL, SANITY_MAXIMUM)
- handle_nutrition()
// 0.416% is 15 successes / 3600 seconds. Calculated with 2 minute
// mood runtime, so 50% average uptime across the hour.
@@ -112,16 +111,18 @@
last_stat = mob_parent.stat
/// Handles mood given by nutrition
-/datum/mood/proc/handle_nutrition()
- if (HAS_TRAIT(mob_parent, TRAIT_NOHUNGER))
- clear_mood_event(MOOD_CATEGORY_NUTRITION) // if you happen to switch species while hungry youre no longer hungy
- return FALSE // no moods for nutrition
+/datum/mood/proc/update_nutrition_moodlets()
+ if(HAS_TRAIT(mob_parent, TRAIT_NOHUNGER))
+ clear_mood_event(MOOD_CATEGORY_NUTRITION)
+ return FALSE
+
+ if(HAS_TRAIT(mob_parent, TRAIT_FAT) && !HAS_TRAIT(mob_parent, TRAIT_VORACIOUS))
+ add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/fat)
+ return TRUE
+
switch(mob_parent.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
- if (!HAS_TRAIT(mob_parent, TRAIT_VORACIOUS))
- add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/fat)
- else
- add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/wellfed) // round and full
+ add_mood_event(MOOD_CATEGORY_NUTRITION, HAS_TRAIT(mob_parent, TRAIT_VORACIOUS) ? /datum/mood_event/wellfed : /datum/mood_event/too_wellfed)
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/wellfed)
if( NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
@@ -133,6 +134,8 @@
if(0 to NUTRITION_LEVEL_STARVING)
add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/starving)
+ return TRUE
+
/**
* Adds a mood event to the mob
*
diff --git a/code/datums/mood_events/eldritch_painting_events.dm b/code/datums/mood_events/eldritch_painting_events.dm
index 7df89104263ba..df801998c1d98 100644
--- a/code/datums/mood_events/eldritch_painting_events.dm
+++ b/code/datums/mood_events/eldritch_painting_events.dm
@@ -17,13 +17,13 @@
mood_change = 5
timeout = 3 MINUTES
-/datum/mood_event/eldritch_painting/weeping_withdrawl
+/datum/mood_event/eldritch_painting/weeping_withdrawal
description = "My mind is clear from his influence."
mood_change = 1
timeout = 3 MINUTES
/datum/mood_event/eldritch_painting/desire_heretic
- description = "A part gained, the manus takes and gives. What did it take from me?"
+ description = "A part gained, the mansus takes and gives. What did it take from me?"
mood_change = -2
timeout = 3 MINUTES
diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm
index dd710554d8d97..72d789da1e062 100644
--- a/code/datums/mood_events/needs_events.dm
+++ b/code/datums/mood_events/needs_events.dm
@@ -3,6 +3,10 @@
description = "I'm so fat..." //muh fatshaming
mood_change = -6
+/datum/mood_event/too_wellfed
+ description = "I think I've eaten too much."
+ mood_change = 0
+
/datum/mood_event/wellfed
description = "I'm stuffed!"
mood_change = 8
diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm
index 789b8787fe6e1..d040c5677d0ec 100644
--- a/code/datums/records/manifest.dm
+++ b/code/datums/records/manifest.dm
@@ -104,7 +104,10 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
if(!(person.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST))
return
- var/assignment = person.mind.assigned_role.title
+ // Attempt to get assignment from ID, otherwise default to mind.
+ var/obj/item/card/id/id_card = person.get_idcard(hand_first = FALSE)
+ var/assignment = id_card?.get_trim_assignment() || person.mind.assigned_role.title
+
var/mutable_appearance/character_appearance = new(person.appearance)
var/person_gender = "Other"
if(person.gender == "male")
diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm
index 5d777858fb3cc..c79d7229ceecf 100644
--- a/code/datums/ruins/icemoon.dm
+++ b/code/datums/ruins/icemoon.dm
@@ -13,62 +13,62 @@
// above ground only
/datum/map_template/ruin/icemoon/gas
- name = "Lizard Gas Station"
+ name = "Ice-Ruin Lizard Gas Station"
id = "lizgasruin"
description = "A gas station. It appears to have been recently open and is in mint condition."
suffix = "icemoon_surface_gas.dmm"
/datum/map_template/ruin/icemoon/lust
- name = "Ruin of Lust"
+ name = "Ice-Ruin Ruin of Lust"
id = "lust"
description = "Not exactly what you expected."
suffix = "icemoon_surface_lust.dmm"
/datum/map_template/ruin/icemoon/asteroid
- name = "Asteroid Site"
+ name = "Ice-Ruin Asteroid Site"
id = "asteroidsite"
description = "Surprised to see us here?"
suffix = "icemoon_surface_asteroid.dmm"
/datum/map_template/ruin/icemoon/engioutpost
- name = "Engineer Outpost"
+ name = "Ice-Ruin Engineer Outpost"
id = "engioutpost"
description = "Blown up by an unfortunate accident."
suffix = "icemoon_surface_engioutpost.dmm"
/datum/map_template/ruin/icemoon/fountain
- name = "Fountain Hall"
+ name = "Ice-Ruin Fountain Hall"
id = "ice_fountain"
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "fountain_hall.dmm"
/datum/map_template/ruin/icemoon/abandoned_homestead
- name = "Abandoned Homestead"
+ name = "Ice-Ruin Abandoned Homestead"
id = "abandoned_homestead"
description = "This homestead was once host to a happy homesteading family. It's now host to hungry bears."
suffix = "icemoon_underground_abandoned_homestead.dmm"
/datum/map_template/ruin/icemoon/entemology
- name = "Insect Research Station"
+ name = "Ice-Ruin Insect Research Station"
id = "bug_habitat"
description = "An independently funded research outpost, long abandoned. Their mission, to boldly go where no insect life would ever live, ever, and look for bugs."
suffix = "icemoon_surface_bughabitat.dmm"
/datum/map_template/ruin/icemoon/pizza
- name = "Moffuchi's Pizzeria"
+ name = "Ice-Ruin Moffuchi's Pizzeria"
id = "pizzeria"
description = "Moffuchi's Family Pizzeria chain has a reputation for providing affordable artisanal meals of questionable edibility. This particular pizzeria seems to have been abandoned for some time."
suffix = "icemoon_surface_pizza.dmm"
/datum/map_template/ruin/icemoon/frozen_phonebooth
- name = "Frozen Phonebooth"
+ name = "Ice-Ruin Frozen Phonebooth"
id = "frozen_phonebooth"
description = "A venture by nanotrasen to help popularize the use of holopads. This one was sent to a icemoon."
suffix = "icemoon_surface_phonebooth.dmm"
/datum/map_template/ruin/icemoon/smoking_room
- name = "Smoking Room"
+ name = "Ice-Ruin Smoking Room"
id = "smoking_room"
description = "Here lies Charles Morlbaro. He died the way he lived."
suffix = "icemoon_surface_smoking_room.dmm"
@@ -76,7 +76,7 @@
// above and below ground together
/datum/map_template/ruin/icemoon/mining_site
- name = "Mining Site"
+ name = "Ice-Ruin Mining Site"
id = "miningsite"
description = "Ruins of a site where people once mined with primitive tools for ore."
suffix = "icemoon_surface_mining_site.dmm"
@@ -84,7 +84,7 @@
always_spawn_with = list(/datum/map_template/ruin/icemoon/underground/mining_site_below = PLACE_BELOW)
/datum/map_template/ruin/icemoon/underground/mining_site_below
- name = "Mining Site Underground"
+ name = "Ice-Ruin Mining Site Underground"
id = "miningsite-underground"
description = "Who knew ladders could be so useful?"
suffix = "icemoon_underground_mining_site.dmm"
@@ -94,60 +94,60 @@
// below ground only
/datum/map_template/ruin/icemoon/underground
- name = "underground ruin"
+ name = "Ice-Ruin underground ruin"
ruin_type = ZTRAIT_ICE_RUINS_UNDERGROUND
default_area = /area/icemoon/underground/unexplored
/datum/map_template/ruin/icemoon/underground/abandonedvillage
- name = "Abandoned Village"
+ name = "Ice-Ruin Abandoned Village"
id = "abandonedvillage"
description = "Who knows what lies within?"
suffix = "icemoon_underground_abandoned_village.dmm"
/datum/map_template/ruin/icemoon/underground/library
- name = "Buried Library"
+ name = "Ice-Ruin Buried Library"
id = "buriedlibrary"
description = "A once grand library, now lost to the confines of the Ice Moon."
suffix = "icemoon_underground_library.dmm"
/datum/map_template/ruin/icemoon/underground/wrath
- name = "Ruin of Wrath"
+ name = "Ice-Ruin Ruin of Wrath"
id = "wrath"
description = "You'll fight and fight and just keep fighting."
suffix = "icemoon_underground_wrath.dmm"
/datum/map_template/ruin/icemoon/underground/hermit
- name = "Frozen Shack"
+ name = "Ice-Ruin Frozen Shack"
id = "hermitshack"
description = "A place of shelter for a lone hermit, scraping by to live another day."
suffix = "icemoon_underground_hermit.dmm"
/datum/map_template/ruin/icemoon/underground/lavaland
- name = "Lavaland Site"
+ name = "Ice-Ruin Lavaland Site"
id = "lavalandsite"
description = "I guess we never really left you huh?"
suffix = "icemoon_underground_lavaland.dmm"
/datum/map_template/ruin/icemoon/underground/puzzle
- name = "Ancient Puzzle"
+ name = "Ice-Ruin Ancient Puzzle"
id = "puzzle"
description = "Mystery to be solved."
suffix = "icemoon_underground_puzzle.dmm"
/datum/map_template/ruin/icemoon/underground/bathhouse
- name = "Bath House"
+ name = "Ice-Ruin Bath House"
id = "bathhouse"
description = "A warm, safe place."
suffix = "icemoon_underground_bathhouse.dmm"
/datum/map_template/ruin/icemoon/underground/wendigo_cave
- name = "Wendigo Cave"
+ name = "Ice-Ruin Wendigo Cave"
id = "wendigocave"
description = "Into the jaws of the beast."
suffix = "icemoon_underground_wendigo_cave.dmm"
/datum/map_template/ruin/icemoon/underground/free_golem
- name = "Free Golem Ship"
+ name = "Ice-Ruin Free Golem Ship"
id = "golem-ship"
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
Seem very intent on research and individual liberty, and also geology-based naming?"
@@ -155,33 +155,33 @@
suffix = "golem_ship.dmm"
/datum/map_template/ruin/icemoon/underground/mailroom
- name = "Frozen-over Post Office"
+ name = "Ice-Ruin Frozen-over Post Office"
id = "mailroom"
description = "This is where all of your paychecks went. Signed, the management."
suffix = "icemoon_underground_mailroom.dmm"
/datum/map_template/ruin/icemoon/underground/frozen_comms
- name = "Frozen Communicatons Outpost"
+ name = "Ice-Ruin Frozen Communicatons Outpost"
id = "frozen_comms"
description = "3 Peaks Radio, where the 2000's live forever."
suffix = "icemoon_underground_frozen_comms.dmm"
//TODO: Bottom-Level ONLY Spawns after Refactoring Related Code
/datum/map_template/ruin/icemoon/underground/plasma_facility
- name = "Abandoned Plasma Facility"
+ name = "Ice-Ruin Abandoned Plasma Facility"
id = "plasma_facility"
description = "Rumors have developed over the many years of Freyja plasma mining. These rumors suggest that the ghosts of dead mistreated excavation staff have returned to \
exact revenge on their (now former) employers. Coorperate reminds all staff that rumors are just that: Old Housewife tales meant to scare misbehaving kids to bed."
suffix = "icemoon_underground_abandoned_plasma_facility.dmm"
/datum/map_template/ruin/icemoon/underground/hotsprings
- name = "Hot Springs"
+ name = "Ice-Ruin Hot Springs"
id = "hotsprings"
description = "Just relax and take a dip, nothing will go wrong, I swear!"
suffix = "icemoon_underground_hotsprings.dmm"
/datum/map_template/ruin/icemoon/underground/vent
- name = "Icemoon Ore Vent"
+ name = "Ice-Ruin Icemoon Ore Vent"
id = "ore_vent_i"
description = "A vent that spews out ore. Seems to be a natural phenomenon." //Make this a subtype that only spawns medium and large vents. Some smalls will go to the top level.
suffix = "icemoon_underground_ore_vent.dmm"
@@ -191,7 +191,7 @@
always_place = TRUE
/datum/map_template/ruin/icemoon/ruin/vent
- name = "Surface Icemoon Ore Vent"
+ name = "Ice-Ruin Surface Icemoon Ore Vent"
id = "ore_vent_i"
description = "A vent that spews out ore. Seems to be a natural phenomenon. Smaller than the underground ones."
suffix = "icemoon_surface_ore_vent.dmm"
diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm
index 7627d89cd3f8b..9e562ef0c669a 100644
--- a/code/datums/ruins/lavaland.dm
+++ b/code/datums/ruins/lavaland.dm
@@ -10,27 +10,27 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/biodome/beach
- name = "Biodome Beach"
+ name = "Lava-Ruin Biodome Beach"
id = "biodome-beach"
description = "Seemingly plucked from a tropical destination, this beach is calm and cool, with the salty waves roaring softly in the background. \
Comes with a rustic wooden bar and suicidal bartender."
suffix = "lavaland_biodome_beach.dmm"
/datum/map_template/ruin/lavaland/biodome/winter
- name = "Biodome Winter"
+ name = "Lava-Ruin Biodome Winter"
id = "biodome-winter"
description = "For those getaways where you want to get back to nature, but you don't want to leave the fortified military compound where you spend your days. \
Includes a unique(*) laser pistol display case, and the recently introduced I.C.E(tm)."
suffix = "lavaland_surface_biodome_winter.dmm"
/datum/map_template/ruin/lavaland/biodome/clown
- name = "Biodome Clown Planet"
+ name = "Lava-Ruin Biodome Clown Planet"
id = "biodome-clown"
description = "WELCOME TO CLOWN PLANET! HONK HONK HONK etc.!"
suffix = "lavaland_biodome_clown_planet.dmm"
/datum/map_template/ruin/lavaland/cube
- name = "The Wishgranter Cube"
+ name = "Lava-Ruin The Wishgranter Cube"
id = "wishgranter-cube"
description = "Nothing good can come from this. Learn from their mistakes and turn around."
suffix = "lavaland_surface_cube.dmm"
@@ -38,7 +38,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/seed_vault
- name = "Seed Vault"
+ name = "Lava-Ruin Seed Vault"
id = "seed-vault"
description = "The creators of these vaults were a highly advanced and benevolent race, and launched many into the stars, hoping to aid fledgling civilizations. \
However, all the inhabitants seem to do is grow drugs and guns."
@@ -47,7 +47,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/ash_walker
- name = "Ash Walker Nest"
+ name = "Lava-Ruin Ash Walker Nest"
id = "ash-walker"
description = "A race of unbreathing lizards live here, that run faster than a human can, worship a broken dead city, and are capable of reproducing by something involving tentacles? \
Probably best to stay clear."
@@ -56,7 +56,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/syndicate_base
- name = "Syndicate Lava Base"
+ name = "Lava-Ruin Syndicate Lava Base"
id = "lava-base"
description = "A secret base researching illegal bioweapons, it is closely guarded by an elite team of syndicate agents."
suffix = "lavaland_surface_syndicate_base1.dmm"
@@ -64,7 +64,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/free_golem
- name = "Free Golem Ship"
+ name = "Lava-Ruin Free Golem Ship"
id = "golem-ship"
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
Seem very intent on research and individual liberty, and also geology-based naming?"
@@ -74,7 +74,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/gaia
- name = "Patch of Eden"
+ name = "Lava-Ruin Patch of Eden"
id = "gaia"
description = "Who would have thought that such a peaceful place could be on such a horrific planet?"
cost = 5
@@ -86,32 +86,32 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/sin/envy
- name = "Ruin of Envy"
+ name = "Lava-Ruin Ruin of Envy"
id = "envy"
description = "When you get what they have, then you'll finally be happy."
suffix = "lavaland_surface_envy.dmm"
/datum/map_template/ruin/lavaland/sin/gluttony
- name = "Ruin of Gluttony"
+ name = "Lava-Ruin Ruin of Gluttony"
id = "gluttony"
description = "If you eat enough, then eating will be all that you do."
suffix = "lavaland_surface_gluttony.dmm"
/datum/map_template/ruin/lavaland/sin/greed
- name = "Ruin of Greed"
+ name = "Lava-Ruin Ruin of Greed"
id = "greed"
description = "Sure you don't need magical powers, but you WANT them, and \
that's what's important."
suffix = "lavaland_surface_greed.dmm"
/datum/map_template/ruin/lavaland/sin/pride
- name = "Ruin of Pride"
+ name = "Lava-Ruin Ruin of Pride"
id = "pride"
description = "Wormhole lifebelts are for LOSERS, whom you are better than."
suffix = "lavaland_surface_pride.dmm"
/datum/map_template/ruin/lavaland/sin/sloth
- name = "Ruin of Sloth"
+ name = "Lava-Ruin Ruin of Sloth"
id = "sloth"
description = "..."
suffix = "lavaland_surface_sloth.dmm"
@@ -119,7 +119,7 @@
cost = 0
/datum/map_template/ruin/lavaland/ratvar
- name = "Dead God"
+ name = "Lava-Ruin Dead God"
id = "ratvar"
description = "Ratvar's final resting place."
suffix = "lavaland_surface_dead_ratvar.dmm"
@@ -127,7 +127,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/hierophant
- name = "Hierophant's Arena"
+ name = "Lava-Ruin Hierophant's Arena"
id = "hierophant"
description = "A strange, square chunk of metal of massive size. Inside awaits only death and many, many squares."
suffix = "lavaland_surface_hierophant.dmm"
@@ -135,7 +135,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/blood_drunk_miner
- name = "Blood-Drunk Miner"
+ name = "Lava-Ruin Blood-Drunk Miner"
id = "blooddrunk"
description = "A strange arrangement of stone tiles and an insane, beastly miner contemplating them."
suffix = "lavaland_surface_blooddrunk1.dmm"
@@ -143,15 +143,15 @@
allow_duplicates = FALSE //will only spawn one variant of the ruin
/datum/map_template/ruin/lavaland/blood_drunk_miner/guidance
- name = "Blood-Drunk Miner (Guidance)"
+ name = "Lava-Ruin Blood-Drunk Miner (Guidance)"
suffix = "lavaland_surface_blooddrunk2.dmm"
/datum/map_template/ruin/lavaland/blood_drunk_miner/hunter
- name = "Blood-Drunk Miner (Hunter)"
+ name = "Lava-Ruin Blood-Drunk Miner (Hunter)"
suffix = "lavaland_surface_blooddrunk3.dmm"
/datum/map_template/ruin/lavaland/blood_drunk_miner/random
- name = "Blood-Drunk Miner (Random)"
+ name = "Lava-Ruin Blood-Drunk Miner (Random)"
suffix = null
always_place = TRUE
@@ -160,14 +160,14 @@
return ..()
/datum/map_template/ruin/lavaland/ufo_crash
- name = "UFO Crash"
+ name = "Lava-Ruin UFO Crash"
id = "ufo-crash"
description = "Turns out that keeping your abductees unconscious is really important. Who knew?"
suffix = "lavaland_surface_ufo_crash.dmm"
cost = 5
/datum/map_template/ruin/lavaland/xeno_nest
- name = "Xenomorph Nest"
+ name = "Lava-Ruin Xenomorph Nest"
id = "xeno-nest"
description = "These xenomorphs got bored of horrifically slaughtering people on space stations, and have settled down on a nice lava-filled hellscape to focus on what's really important in life. \
Quality memes."
@@ -175,7 +175,7 @@
cost = 20
/datum/map_template/ruin/lavaland/fountain
- name = "Fountain Hall"
+ name = "Lava-Ruin Fountain Hall"
id = "lava_fountain"
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
prefix = "_maps/RandomRuins/AnywhereRuins/"
@@ -183,14 +183,14 @@
cost = 5
/datum/map_template/ruin/lavaland/survivalcapsule
- name = "Survival Capsule Ruins"
+ name = "Lava-Ruin Survival Capsule Ruins"
id = "survivalcapsule"
description = "What was once sanctuary to the common miner, is now their tomb."
suffix = "lavaland_surface_survivalpod.dmm"
cost = 5
/datum/map_template/ruin/lavaland/pizza
- name = "Ruined Pizza Party"
+ name = "Lava-Ruin Ruined Pizza Party"
id = "pizza"
description = "Little Timmy's birthday pizza bash took a turn for the worse when a bluespace anomaly passed by."
suffix = "lavaland_surface_pizzaparty.dmm"
@@ -198,7 +198,7 @@
cost = 5
/datum/map_template/ruin/lavaland/cultaltar
- name = "Summoning Ritual"
+ name = "Lava-Ruin Summoning Ritual"
id = "cultaltar"
description = "A place of vile worship, the scrawling of blood in the middle glowing eerily. A demonic laugh echoes throughout the caverns."
suffix = "lavaland_surface_cultaltar.dmm"
@@ -206,7 +206,7 @@
cost = 10
/datum/map_template/ruin/lavaland/hermit
- name = "Makeshift Shelter"
+ name = "Lava-Ruin Makeshift Shelter"
id = "hermitcave"
description = "A place of shelter for a lone hermit, scraping by to live another day."
suffix = "lavaland_surface_hermit.dmm"
@@ -214,7 +214,7 @@
cost = 10
/datum/map_template/ruin/lavaland/miningripley
- name = "Ripley"
+ name = "Lava-Ruin Ripley"
id = "ripley"
description = "A heavily-damaged mining ripley, property of a very unfortunate miner. You might have to do a bit of work to fix this thing up."
suffix = "lavaland_surface_random_ripley.dmm"
@@ -222,14 +222,14 @@
cost = 5
/datum/map_template/ruin/lavaland/dark_wizards
- name = "Dark Wizard Altar"
+ name = "Lava-Ruin Dark Wizard Altar"
id = "dark_wizards"
description = "A ruin with dark wizards. What secret do they guard?"
suffix = "lavaland_surface_wizard.dmm"
cost = 5
/datum/map_template/ruin/lavaland/strong_stone
- name = "Strong Stone"
+ name = "Lava-Ruin Strong Stone"
id = "strong_stone"
description = "A stone that seems particularly powerful."
suffix = "lavaland_strong_rock.dmm"
@@ -237,14 +237,14 @@
cost = 2
/datum/map_template/ruin/lavaland/puzzle
- name = "Ancient Puzzle"
+ name = "Lava-Ruin Ancient Puzzle"
id = "puzzle"
description = "Mystery to be solved."
suffix = "lavaland_surface_puzzle.dmm"
cost = 5
/datum/map_template/ruin/lavaland/elite_tumor
- name = "Pulsating Tumor"
+ name = "Lava-Ruin Pulsating Tumor"
id = "tumor"
description = "A strange tumor which houses a powerful beast..."
suffix = "lavaland_surface_elite_tumor.dmm"
@@ -253,7 +253,7 @@
allow_duplicates = TRUE
/datum/map_template/ruin/lavaland/elephant_graveyard
- name = "Elephant Graveyard"
+ name = "Lava-Ruin Elephant Graveyard"
id = "Graveyard"
description = "An abandoned graveyard, calling to those unable to continue."
suffix = "lavaland_surface_elephant_graveyard.dmm"
@@ -261,7 +261,7 @@
cost = 10
/datum/map_template/ruin/lavaland/bileworm_nest
- name = "Bileworm Nest"
+ name = "Lava-Ruin Bileworm Nest"
id = "bileworm_nest"
description = "A small sanctuary from the harsh wilderness... if you're a bileworm, that is."
cost = 5
@@ -269,7 +269,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/lava_phonebooth
- name = "Phonebooth"
+ name = "Lava-Ruin Phonebooth"
id = "lava_phonebooth"
description = "A venture by nanotrasen to help popularize the use of holopads. This one somehow made its way here."
suffix = "lavaland_surface_phonebooth.dmm"
@@ -277,7 +277,7 @@
cost = 5
/datum/map_template/ruin/lavaland/battle_site
- name = "Battle Site"
+ name = "Lava-Ruin Battle Site"
id = "battle_site"
description = "The long past site of a battle between beast and humanoids. The victor is unknown, but the losers are clear."
suffix = "lavaland_battle_site.dmm"
@@ -285,7 +285,7 @@
cost = 3
/datum/map_template/ruin/lavaland/vent
- name = "Ore Vent"
+ name = "Lava-Ruin Ore Vent"
id = "ore_vent"
description = "A vent that spews out ore. Seems to be a natural phenomenon."
suffix = "lavaland_surface_ore_vent.dmm"
@@ -295,7 +295,7 @@
always_place = TRUE
/datum/map_template/ruin/lavaland/watcher_grave
- name = "Watchers' Grave"
+ name = "Lava-Ruin Watchers' Grave"
id = "watcher-grave"
description = "A lonely cave where an orphaned child awaits a new parent."
suffix = "lavaland_surface_watcher_grave.dmm"
@@ -303,7 +303,7 @@
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/mook_village
- name = "Mook Village"
+ name = "Lava-Ruin Mook Village"
id = "mook_village"
description = "A village hosting a community of friendly mooks!"
suffix = "lavaland_surface_mookvillage.dmm"
diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm
index 05c4940dae9f0..76ac14cef5c92 100644
--- a/code/datums/ruins/space.dm
+++ b/code/datums/ruins/space.dm
@@ -10,65 +10,65 @@
/datum/map_template/ruin/space/zoo
id = "zoo"
suffix = "abandonedzoo.dmm"
- name = "Biological Storage Facility"
+ name = "Space-Ruin Biological Storage Facility"
description = "In case society crumbles, we will be able to restore our zoos to working order with the breeding stock kept in these 100% secure and unbreachable storage facilities. \
At no point has anything escaped. That's our story, and we're sticking to it."
/datum/map_template/ruin/space/asteroid1
id = "asteroid1"
suffix = "asteroid1.dmm"
- name = "Asteroid 1"
+ name = "Space-Ruin Asteroid 1"
description = "I-spy with my little eye, something beginning with R."
/datum/map_template/ruin/space/asteroid2
id = "asteroid2"
suffix = "asteroid2.dmm"
- name = "Asteroid 2"
+ name = "Space-Ruin Asteroid 2"
description = "Oh my god, a giant rock!"
/datum/map_template/ruin/space/asteroid3
id = "asteroid3"
suffix = "asteroid3.dmm"
- name = "Asteroid 3"
+ name = "Space-Ruin Asteroid 3"
description = "This asteroid floating in space has no official designation, because the scientist that discovered it deemed it 'super dull'."
/datum/map_template/ruin/space/asteroid4
id = "asteroid4"
suffix = "asteroid4.dmm"
- name = "Asteroid 4"
+ name = "Space-Ruin Asteroid 4"
description = "Nanotrasen Escape Pods have a 100%* success rate, and a 99%* customer satisfaction rate. \
*Please note that these statistics are taken from pods that have successfully docked with a recovery vessel."
/datum/map_template/ruin/space/asteroid5
id = "asteroid5"
suffix = "asteroid5.dmm"
- name = "Asteroid 5"
+ name = "Space-Ruin Asteroid 5"
description = "Oh my god, another giant rock!"
/datum/map_template/ruin/space/asteroid6
id = "asteroid6"
suffix = "asteroid6.dmm"
- name = "Asteroid 6"
+ name = "Space-Ruin Asteroid 6"
description = "This asteroid has brittle bone disease, so it is fortunate asteroids dont have bones."
/datum/map_template/ruin/space/deep_storage
id = "deep-storage"
suffix = "deepstorage.dmm"
- name = "Survivalist Bunker"
+ name = "Space-Ruin Survivalist Bunker"
description = "Assume the best, prepare for the worst. Generally, you should do so by digging a three-man heavily fortified bunker into a giant unused asteroid. \
Then make it self sufficient, mask any evidence of construction, hook it covertly into the telecommunications network and hope for the best."
/datum/map_template/ruin/space/bigderelict1
id = "bigderelict1"
suffix = "bigderelict1.dmm"
- name = "Derelict Tradepost"
+ name = "Space-Ruin Derelict Tradepost"
description = "A once-bustling tradestation that handled imports and exports from nearby stations now lays eerily dormant. \
The last received message was a distress call from one of the on-board officers, but we had no success in making contact again."
/datum/map_template/ruin/space/derelict_construction
id = "derelict_construction"
suffix = "derelict_construction.dmm"
- name = "Derelict Construction"
+ name = "Space-Ruin Derelict Construction"
description = "Construction supplies are in high demand due to non-trivial damage routinely sustained by most space stations in this sector. \
Space pirates who dont attempt to rob corporate research stations with only 3 collaborators live long enough to sell captured construction \
equipment back to the highest bidder."
@@ -76,14 +76,14 @@
/datum/map_template/ruin/space/derelict_sulaco
id = "derelict_sulaco"
suffix = "derelict_sulaco.dmm"
- name = "Derelict Sulaco"
+ name = "Space-Ruin Derelict Sulaco"
description = "Nothing to see here citizen, move along, certainly no xeno outbreaks here. That purple stuff? It's uh... space nectar... but don't eat it! \
It's the bridge of a top secret military ship."
/datum/map_template/ruin/space/derelict2
id = "derelict2"
suffix = "derelict2.dmm"
- name = "Dinner for Two"
+ name = "Space-Ruin Dinner for Two"
description = "Oh this is the night\n\
It's a beautiful night\n\
And we call it bella notte"
@@ -91,161 +91,161 @@
/datum/map_template/ruin/space/derelict3
id = "derelict3"
suffix = "derelict3.dmm"
- name = "Derelict 3"
+ name = "Space-Ruin Derelict 3"
description = "These hulks were once part of a larger structure, where the three great \[REDACTED\] were forged."
/datum/map_template/ruin/space/derelict4
id = "derelict4"
suffix = "derelict4.dmm"
- name = "Derelict 4"
+ name = "Space-Ruin Derelict 4"
description = "CentCom ferries have never crashed, will never crash, there is no current investigation into a crashed ferry, and we will not let Internal Affairs trample over high security \
information in the name of this baseless witchhunt."
/datum/map_template/ruin/space/derelict5
id = "derelict5"
suffix = "derelict5.dmm"
- name = "Derelict 5"
+ name = "Space-Ruin Derelict 5"
description = "The plan is, we put a whole bunch of crates full of treasure in this disused warehouse, launch it into space, and then ignore it. Forever."
/datum/map_template/ruin/space/derelict6
id = "derelict6"
suffix = "derelict6.dmm"
- name = "Derelict 6"
+ name = "Space-Ruin Derelict 6"
description = "The hush-hush of Nanotrasen when it comes to stations seemingly vanishing off the radar is an interesting topic, theories of nuclear destruction float about while Nanotrasen \
flat-out denies said stations ever existing."
/datum/map_template/ruin/space/derelict7
id = "derelict7"
suffix = "derelict7.dmm"
- name = "Derelict 7"
+ name = "Space-Ruin Derelict 7"
description = "The official report says there was a 'huge explosion' which was 'radical' and 'tubular'. Nothing is said about the explosion's cause."
/datum/map_template/ruin/space/derelict8
id = "derelict8"
suffix = "derelict8.dmm"
- name = "Derelict 8"
+ name = "Space-Ruin Derelict 8"
description = "An auxiliary storage bay might be the least respected room on any functional station, but studies show they are the least likely to be hit in an artillery strike."
/datum/map_template/ruin/space/derelict9
id = "derelict9"
suffix = "derelict9.dmm"
- name = "Derelict 9"
+ name = "Space-Ruin Derelict 9"
description = "Someone already found this high-security supply cache already, but were unable to get inside. Perhaps the next visitor will have more luck."
/datum/map_template/ruin/space/empty_shell
id = "empty-shell"
suffix = "emptyshell.dmm"
- name = "Empty Shell"
+ name = "Space-Ruin Empty Shell"
description = "Cosy, rural property available for young professional couple. Only twelve parsecs from the nearest hyperspace lane!"
/datum/map_template/ruin/space/the_lizards_gas
id = "the-lizards-gas"
suffix = "thelizardsgas.dmm"
- name = "The Lizard's Gas"
+ name = "Space-Ruin The Lizard's Gas"
description = "A refueling station stocked with enough plasma for any space-worthy vessel. Well, maybe if it weren't 50 years ago."
/datum/map_template/ruin/space/intact_empty_ship
id = "intact-empty-ship"
suffix = "intactemptyship.dmm"
- name = "Authorship"
+ name = "Space-Ruin Authorship"
description = "Just somewhere quiet, where I can focus on my work with no interruptions."
/datum/map_template/ruin/space/caravanambush
id = "caravanambush"
suffix = "caravanambush.dmm"
- name = "Syndicate Ambush"
+ name = "Space-Ruin Syndicate Ambush"
description = "A caravan route used by passing cargo freights has been ambushed by a salvage team manned by the syndicate. \
The caravan managed to send off a distress message before being surrounded, their video feed cutting off as the sound of gunfire and a parrot was heard."
/datum/map_template/ruin/space/originalcontent
id = "paperwizard"
suffix = "originalcontent.dmm"
- name = "A Giant Ball of Paper in Space"
+ name = "Space-Ruin A Giant Ball of Paper in Space"
description = "Sightings of a giant wad of paper hurling through the depths of space have been recently reported by multiple outposts near this sector. \
A giant wad of paper, really? Damn prank callers."
/datum/map_template/ruin/space/mech_transport
id = "mech-transport"
suffix = "mechtransport.dmm"
- name = "CF Corsair"
+ name = "Space-Ruin CF Corsair"
description = "Well, when is it getting here? I have bills to pay; very well-armed clients who want their shipments as soon as possible! I don't care, just find it!"
/datum/map_template/ruin/space/onehalf
id = "onehalf"
suffix = "onehalf.dmm"
- name = "DK Excavator 453"
+ name = "Space-Ruin DK Excavator 453"
description = "Based on the trace elements we've detected on the gutted asteroids, we suspect that a mining ship using a restricted engine is somewhere in the area. \
We'd like to request a patrol vessel to investigate."
/datum/map_template/ruin/space/spacehotel
id = "spacehotel"
suffix = "spacehotel.dmm"
- name = "The Twin-Nexus Hotel"
+ name = "Space-Ruin The Twin-Nexus Hotel"
description = "An interstellar hotel, where the weary spaceman can rest their head and relax, assured that the residental staff will not murder them in their sleep. Probably."
/datum/map_template/ruin/space/turreted_outpost
id = "turreted-outpost"
suffix = "turretedoutpost.dmm"
- name = "Unnamed Turreted Outpost"
+ name = "Space-Ruin Unnamed Turreted Outpost"
description = "We'd ask them to stop blaring that ruskiepop music, but none of us are brave enough to go near those death turrets they have."
/datum/map_template/ruin/space/oldshuttle
id = "spaceman-origins"
suffix = "shuttlerelic.dmm"
- name = "Strange Ship"
+ name = "Space-Ruin Strange Ship"
description = "A ship seemingly lost, drifting along the stars. This thing looks like it belongs in ancient times."
/datum/map_template/ruin/space/way_home
id = "way-home"
suffix = "way_home.dmm"
- name = "Salvation"
+ name = "Space-Ruin Salvation"
description = "In the darkest times, we will find our way home."
/datum/map_template/ruin/space/djstation
id = "djstation"
suffix = "dj_station.dmm"
- name = "DJ Station"
+ name = "Space-Ruin DJ Station"
description = "Until very recently this pirate radio station was used to harangue local space stations over a variety of perceived \"ethics violations\". \
It seems like someone finally got sick of it, but the equipment still works."
/datum/map_template/ruin/space/thederelict
id = "thederelict"
suffix = "russian_derelict.dmm"
- name = "Kosmicheskaya Stantsiya 13"
+ name = "Space-Ruin Kosmicheskaya Stantsiya 13"
description = "The true fate of Kosmicheskaya Stantsiya 13 is an open question to this day. Most corporations deny its existence, for fear of questioning on what became of its crew."
/datum/map_template/ruin/space/abandonedteleporter
id = "abandonedteleporter"
suffix = "abandonedteleporter.dmm"
- name = "Abandoned Teleporter"
+ name = "Space-Ruin Abandoned Teleporter"
description = "In space construction the teleporter is often the first system brought online. \
This lonely, half-built teleporter is a sign of a proposed structure that for one reason or another just never got built."
/datum/map_template/ruin/space/crashedclownship
id = "crashedclownship"
suffix = "crashedclownship.dmm"
- name = "Crashed Clown Ship"
+ name = "Space-Ruin Crashed Clown Ship"
description = "For centuries the promise of a new clown homeworld has been the siren call for countless clown vessels. \
Alas, the clown's lust for shenanigans means that successful voyages are almost unheard of, with most vessels falling to hilarious consequences almost immediately."
/datum/map_template/ruin/space/crashedship
id = "crashedship"
suffix = "crashedship.dmm"
- name = "Crashed Ship"
+ name = "Space-Ruin Crashed Ship"
description = "The SSCV Atrus was chartered to survey over 600 planets in its maiden voyage. \
Hopefully the SSC is content with an indepth analysis of just this asteroid."
/datum/map_template/ruin/space/listeningstation
id = "listeningstation"
suffix = "listeningstation.dmm"
- name = "Syndicate Listening Station"
+ name = "Space-Ruin Syndicate Listening Station"
description = "Listening stations form the backbone of the syndicate's information-gathering operations. \
Assignment to these stations is dreaded by most agents, as it entails long and lonely shifts listening to nearby stations chatter incessantly about the most meaningless things."
/datum/map_template/ruin/space/old_ai_sat
id = "oldAIsat"
suffix = "oldAIsat.dmm"
- name = "Abandoned Telecommunications Satellite"
+ name = "Space-Ruin Abandoned Telecommunications Satellite"
description = "When the inspector told the employees that they were all fired, and that their jobs \"could be done by trained lizards anyway\", they reacted badly. \
This event and others is the reason why Central always sends an ERT squad with their competent inspectors. Incompetent inspectors are told they can \"do it alone\" because they're \"that pro\". \
Incompetent inspectors believe this."
@@ -253,258 +253,258 @@
/datum/map_template/ruin/space/oldteleporter
id = "oldteleporter"
suffix = "oldteleporter.dmm"
- name = "Detached Teleporter"
+ name = "Space-Ruin Detached Teleporter"
description = "The structure of this surprisingly intact teleporter suggests that it was once part of a larger structure, but what remains of said structure, if anything, can only be guessed at."
/datum/map_template/ruin/space/vaporwave
id = "vaporwave"
suffix = "vaporwave.dmm"
- name = "Aesthetic Outpost"
+ name = "Space-Ruin Aesthetic Outpost"
description = "Pause and remember-- You are unique.You are special. Every mistake, trial, and hardship has helped to sculpt your real beauty. \
Stop hating yourself and start appreciating and loving yourself!"
/datum/map_template/ruin/space/bus
id = "bus"
suffix = "bus.dmm"
- name = "Waylaid Buses"
+ name = "Space-Ruin Waylaid Buses"
description = "There seems to be a pair of buses that pulled over for repairs. What were they doing...? Their shipment sure seems to be filled with a strange mix. \
Anyway, it looks like some people tried to fix it up for a long time but didn't really get anywhere..."
/datum/map_template/ruin/space/oldstation
id = "oldstation"
suffix = "oldstation.dmm"
- name = "Ancient Space Station"
+ name = "Space-Ruin Ancient Space Station"
description = "The crew of a space station awaken one hundred years after a crisis. Awaking to a derelict space station on the verge of collapse, and a hostile force of invading \
hivebots. Can the surviving crew overcome the odds and survive and rebuild, or will the cold embrace of the stars become their new home?"
/datum/map_template/ruin/space/gondoland
id = "gondolaasteroid"
suffix = "gondolaasteroid.dmm"
- name = "Gondoland"
+ name = "Space-Ruin Gondoland"
description = "Just an ordinary rock- wait, what's that thing?"
/datum/map_template/ruin/space/whiteshipruin_box
id = "whiteshipruin_box"
suffix = "whiteshipruin_box.dmm"
- name = "NT Medical Ship"
+ name = "Space-Ruin NT Medical Ship"
description = "An ancient ship, said to be among the first discovered derelicts near Space Station 13 that was still in working order. \
Aged and deprecated by time, this relic of a vessel is now broken beyond repair."
/datum/map_template/ruin/space/whiteshipdock
id = "whiteshipdock"
suffix = "whiteshipdock.dmm"
- name = "Whiteship Dock"
+ name = "Space-Ruin Whiteship Dock"
description = "An abandoned but functional vessel parked in deep space, ripe for the taking."
/datum/map_template/ruin/space/cat_experiments
id = "meow"
suffix = "mrow_thats_right.dmm"
- name = "Feline-Human Combination Den"
+ name = "Space-Ruin Feline-Human Combination Den"
description = "With heated debates over the legality of the catperson and their status in the workforce, there's always a place for the blackmarket to slip in for some cash. Whether the results \
are morally sound or not is another issue entirely."
/datum/map_template/ruin/space/hilbertresearchfacility
id = "hilbert_facility"
suffix = "hilbertresearchfacility.dmm"
- name = "Hilbert Research Facility"
+ name = "Space-Ruin Hilbert Research Facility"
description = "A research facility of great bluespace discoveries. Long since abandoned, willingly or not..."
/datum/map_template/ruin/space/clownplanet
id = "clownplanet"
suffix = "clownplanet.dmm"
- name = "Clown Planet"
+ name = "Space-Ruin Clown Planet"
description = "Thought lost in 2552, this minor planet has recently been rediscovered."
/datum/map_template/ruin/space/clericden
id = "clericden"
suffix = "clericden.dmm"
- name = "Cleric's Den"
+ name = "Space-Ruin Cleric's Den"
description = "Once part of a larger monastery, this holy order of long dead clerics practiced far less non-violence than they preached. Appears to have been untouched by looters, however. Odd."
/datum/map_template/ruin/space/forgottenship
id = "forgottenship"
suffix = "forgottenship.dmm"
- name = "Syndicate Forgotten Ship"
+ name = "Space-Ruin Syndicate Forgotten Ship"
description = "Seemingly abandoned ship went of course right into NT controlled space. It seems that malfunction caused most systems to turn off, except for sleepers."
/datum/map_template/ruin/space/old_syndie_infiltrator
id = "old_infiltrator"
suffix = "old_infiltrator.dmm"
- name = "Abandoned Infiltrator"
+ name = "Space-Ruin Abandoned Infiltrator"
description = "Only one in five Gorlex Marauder strike forces return from their regular raids into Nanotrasen space. \
For the other four... well, their ship doesn't just disappear when their target evacuates."
/datum/map_template/ruin/space/hellfactory
id = "hellfactory"
suffix = "hellfactory.dmm"
- name = "Heck Brewery"
+ name = "Space-Ruin Heck Brewery"
description = "An abandoned warehouse and brewing facility, which has been recently rediscovered. Reports claim that the security system entered an ultra-hard lockdown, but these reports are inconclusive."
/datum/map_template/ruin/space/space_billboard
id = "space_billboard"
suffix = "space_billboard.dmm"
- name = "Space Billboard"
+ name = "Space-Ruin Space Billboard"
description = "Frequently found alongside well-traversed sublight routes, space billboards have fallen out of favour in recent years as advertisers finally realised that people are incapable of reading billboards going by at over 2/3rds the speed of light."
/datum/map_template/ruin/space/spinwardsmoothies
id = "spinwardsmoothies"
suffix = "spinwardsmoothies.dmm"
- name = "Spinward Smoothies"
+ name = "Space-Ruin Spinward Smoothies"
description = "A branch of the beloved Spinward Smoothies chain of smoothie bars."
/datum/map_template/ruin/space/cyborg_mothership
id = "cyborg_mothership"
suffix = "cyborg_mothership.dmm"
- name = "Cyborg Mothership"
+ name = "Space-Ruin Cyborg Mothership"
description = "An abandoned cyborg mothership that was overtaken by space vines and hivebots. It appears that it hosted an experimental AI focused on mining before it was depowered."
/datum/map_template/ruin/space/dangerous_research
id = "dangerous_research"
suffix = "dangerous_research.dmm"
- name = "Alternate Sciences Research Center"
+ name = "Space-Ruin Alternate Sciences Research Center"
description = "When you're messing with the occult, who knows what you're going to get?"
/datum/map_template/ruin/space/anomaly_research
id = "anomaly_research"
suffix = "anomaly_research.dmm"
- name = "Anomaly Research"
+ name = "Space-Ruin Anomaly Research"
description = "A secret research lab embedded in arctic rock, belonging to a Dr Anna Molly. What could she have been researching?"
/datum/map_template/ruin/space/meateor
id = "meateor"
suffix = "meateor.dmm"
- name = "Meateor"
+ name = "Space-Ruin Meateor"
description = "A big chunk of meat floating in space. How did it get there?"
/datum/map_template/ruin/space/the_faceoff
id = "the_faceoff"
suffix = "the_faceoff.dmm"
- name = "The Faceoff"
+ name = "Space-Ruin The Faceoff"
description = "What do you get when a meeting of the enemy corporations get crashed?"
/datum/map_template/ruin/space/meatstation
id = "meatderelict"
suffix = "meatderelict.dmm"
- name = "Bioresearch Outpost"
+ name = "Space-Ruin Bioresearch Outpost"
description = "A bioresearch experiment gone wrong."
/datum/map_template/ruin/space/ghost_restaurant
id = "space_ghost_restaurant.dmm"
suffix = "space_ghost_restaurant.dmm"
- name = "Space Ghost Restaurant"
+ name = "Space-Ruin Space Ghost Restaurant"
description = "Ever wondered where the restaurant robots come from? On this ruined station, NTgrub interns dressed up robots in clothes, and sent them to stations to cook their meal orders for them."
/datum/map_template/ruin/space/atmosasteroidruin
id = "atmosasteroidruin"
suffix = "atmosasteroidruin.dmm"
- name = "Atmos Asteroid"
+ name = "Space-Ruin Atmos Asteroid"
description = "A dead atmos tech in a continuously pressurizing ruin."
/datum/map_template/ruin/space/massdriverrouter
id = "fasttravel"
suffix = "fasttravel.dmm"
- name = "Mass driver Router"
+ name = "Space-Ruin Mass driver Router"
description = "An old, still functional router for some long destroyed system."
/datum/map_template/ruin/space/prey_pod
id = "prey"
suffix = "prey_pod.dmm"
- name = "Crashed Mimic Escape Pod"
+ name = "Space-Ruin Crashed Mimic Escape Pod"
description = "A pod with a person who has died to a mimic."
/datum/map_template/ruin/space/travelers_rest
id = "travelers_rest"
suffix = "travelers_rest.dmm"
- name = "Traveler's Rest"
+ name = "Space-Ruin Traveler's Rest"
description = "An abandoned capsule floating through space. It seems as if somebody was in here not too long ago."
/datum/map_template/ruin/space/prison_shuttle
id = "prison_shuttle"
suffix = "prison_shuttle.dmm"
- name = "Crashed Prisoner Shuttle"
+ name = "Space-Ruin Crashed Prisoner Shuttle"
description = "A prisoner transport shuttle that had crashed into a stray asteroid long ago."
/datum/map_template/ruin/space/botanical_haven
id = "botanical_haven"
suffix = "botanical_haven.dmm"
- name = "Botanical Haven"
+ name = "Space-Ruin Botanical Haven"
description = "A small sanctuary for plants and botanists, hidden away in a rusted structure."
/datum/map_template/ruin/space/pod_crash
id = "pod_crash"
suffix = "pod_crash.dmm"
- name = "Pod Crash"
+ name = "Space-Ruin Pod Crash"
description = "A tragic display of what happens to drivers who pda and pod."
/datum/map_template/ruin/space/interdyne
id = "interdyne"
suffix = "interdyne.dmm"
- name = "Interdyne Spinward Research Base"
+ name = "Space-Ruin Interdyne Spinward Research Base"
description = "An Interdyne facility abandoned due to the accidental discovery of Romerol"
/datum/map_template/ruin/space/waystation
id = "waystation"
suffix = "waystation.dmm"
- name = "Waystation"
+ name = "Space-Ruin Waystation"
description = "A waytation for a backwater subsector of Spinward gets attacked by the syndicate due to bad luck."
/datum/map_template/ruin/space/allamericandiner
id = "allamericandiner"
suffix = "allamericandiner.dmm"
- name = "The All-American Diner"
+ name = "Space-Ruin The All-American Diner"
description = "A mothballed \"Restaurant\" station of the popular \"The All-American Diner\" franchise."
/datum/map_template/ruin/space/mimesvclowns
id = "mimesvclowns"
suffix = "mimesvsclowns.dmm"
- name = "Abandoned Mime Outpost"
+ name = "Space-Ruin Abandoned Mime Outpost"
description = "When you fight mimes, you better bring more than slips."
/datum/map_template/ruin/space/transit_booth
id = "transit_booth"
suffix = "transit_booth.dmm"
- name = "Transit Booth"
+ name = "Space-Ruin Transit Booth"
description = "Make sure to check out the duty-free store!"
/datum/map_template/ruin/space/space_phonebooth
id = "Space_phonebooth"
suffix = "phonebooth.dmm"
- name = "Space Phonebooth"
+ name = "Space-Ruin Phonebooth"
description = "A venture by nanotrasen to help popularize the use of holopads."
/datum/map_template/ruin/space/the_outlet
id = "the_outlet"
suffix = "the_outlet.dmm"
- name = "calebs krazy clothing outlet"
+ name = "Space-Ruin calebs krazy clothing outlet"
description = "A decrepit clothing store built into an asteroid. It appears long since abandoned and has fallen into disrepair."
/datum/map_template/ruin/space/infested_frigate
id = "infested_frigate"
suffix = "infested_frigate.dmm"
- name = "SYN-C Brutus"
+ name = "Space-Ruin SYN-C Brutus"
description = "This wasn't an outbreak, this was a repelled attack."
/datum/map_template/ruin/space/garbagetruck1
id = "garbagetruck1"
suffix = "garbagetruck1.dmm"
- name = "Decommissioned Garbage Truck NX1"
+ name = "Space-Ruin Decommissioned Garbage Truck NX1"
description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of kitchen waste, and rodents."
/datum/map_template/ruin/space/garbagetruck2
id = "garbagetruck2"
suffix = "garbagetruck2.dmm"
- name = "Decommissioned Garbage Truck NX2"
+ name = "Space-Ruin Decommissioned Garbage Truck NX2"
description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of medical waste, and a syndicate agent."
/datum/map_template/ruin/space/garbagetruck3
id = "garbagetruck3"
suffix = "garbagetruck3.dmm"
- name = "Decommissioned Garbage Truck NX3"
+ name = "Space-Ruin Decommissioned Garbage Truck NX3"
description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of industrial garbage, and a russian drug den."
/datum/map_template/ruin/space/garbagetruck4
id = "garbagetruck4"
suffix = "garbagetruck4.dmm"
- name = "Decommissioned Garbage Truck NX4"
+ name = "Space-Ruin Decommissioned Garbage Truck NX4"
description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of commercial trash, and spiders."
diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm
index 2f433b8e340fb..f5af223672d63 100644
--- a/code/datums/sprite_accessories.dm
+++ b/code/datums/sprite_accessories.dm
@@ -2249,6 +2249,10 @@
name = "Moffra"
icon_state = "moffra"
+/datum/sprite_accessory/moth_wings/lightbearer
+ name = "Lightbearer"
+ icon_state = "lightbearer"
+
/datum/sprite_accessory/moth_antennae //Finally splitting the sprite
icon = 'icons/mob/human/species/moth/moth_antennae.dmi'
color_src = null
@@ -2336,6 +2340,10 @@
name = "Moffra"
icon_state = "moffra"
+/datum/sprite_accessory/moth_antennae/lightbearer
+ name = "Lightbearer"
+ icon_state = "lightbearer"
+
/datum/sprite_accessory/moth_markings // the markings that moths can have. finally something other than the boring tan
icon = 'icons/mob/human/species/moth/moth_markings.dmi'
color_src = null
@@ -2399,3 +2407,7 @@
/datum/sprite_accessory/moth_markings/witchwing
name = "Witch Wing"
icon_state = "witchwing"
+
+/datum/sprite_accessory/moth_markings/lightbearer
+ name = "Lightbearer"
+ icon_state = "lightbearer"
diff --git a/code/datums/stock_market_events.dm b/code/datums/stock_market_events.dm
index 81142d2300224..4907bf784f63a 100644
--- a/code/datums/stock_market_events.dm
+++ b/code/datums/stock_market_events.dm
@@ -83,7 +83,7 @@
/datum/stock_market_event/large_boost
name = "Large Boost!"
trend_value = MARKET_TREND_UPWARD
- trend_duration = 3
+ trend_duration = 4
circumstance = list(
"has just released a new product that raised the price of ",
"discovered a new valuable use for ",
@@ -93,14 +93,14 @@
/datum/stock_market_event/large_boost/start_event()
. = ..()
var/price_units = SSstock_market.materials_prices[mat]
- SSstock_market.materials_prices[mat] += round(gaussian(price_units * 0.5, price_units * 0.1))
+ SSstock_market.materials_prices[mat] += round(gaussian(price_units, price_units * 0.15))
SSstock_market.materials_prices[mat] = clamp(SSstock_market.materials_prices[mat], price_minimum * mat.value_per_unit, price_maximum * mat.value_per_unit)
create_news()
/datum/stock_market_event/large_drop
name = "Large Drop!"
trend_value = MARKET_TREND_DOWNWARD
- trend_duration = 5
+ trend_duration = 4
circumstance = list(
"'s latest product has seen major controversy, and resulted in a price drop for ",
"has been hit with a major lawsuit, resulting in a price drop for ",
@@ -110,6 +110,42 @@
/datum/stock_market_event/large_drop/start_event()
. = ..()
var/price_units = SSstock_market.materials_prices[mat]
- SSstock_market.materials_prices[mat] -= round(gaussian(price_units * 1.5, price_units * 0.1))
+ SSstock_market.materials_prices[mat] -= round(gaussian(price_units * 1.5, price_units * 0.15))
SSstock_market.materials_prices[mat] = clamp(SSstock_market.materials_prices[mat], price_minimum * mat.value_per_unit, price_maximum * mat.value_per_unit)
create_news()
+
+/datum/stock_market_event/hotcakes
+ name = "Selling like Hotcakes!"
+ trend_value = MARKET_TREND_UPWARD
+ trend_duration = 1
+ circumstance = list(
+ "has just released a new product that is dominating the market for ",
+ "is hitting it big! Dramatically stocking and raising the price of ",
+ ", in a surprise move, monopolized supply and has raised the price of ",
+ )
+
+/datum/stock_market_event/hotcakes/start_event()
+ . = ..()
+ SSstock_market.materials_prices[mat] = round(price_maximum * mat.value_per_unit)
+ create_news()
+
+/datum/stock_market_event/lockdown
+ name = "Lockdown!"
+ trend_value = MARKET_TREND_DOWNWARD
+ trend_duration = 2
+ circumstance = list(
+ "is being investigated by the Galactic Trade Commission, resulting in a halt of trade for ",
+ ", in a stunning move, has been embargoed by TerraGov, resulting in a halt of trade of ",
+ )
+
+/datum/stock_market_event/lockdown/handle()
+ . = ..()
+ SSstock_market.materials_quantity[mat] = 0 //Force the material to be unavailable.
+
+/datum/stock_market_event/lockdown/end_event()
+ . = ..()
+ SSstock_market.materials_quantity[mat] = initial(mat.tradable_base_quantity) //Force the material to be available again.
+ SSstock_market.materials_prices[mat] = initial(mat.value_per_unit) * SHEET_MATERIAL_AMOUNT //Force the price to be reset once the lockdown is over.
+ create_news()
+
+
diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm
index 3b86f56f23587..ded38af6201ab 100644
--- a/code/game/area/areas/away_content.dm
+++ b/code/game/area/areas/away_content.dm
@@ -35,6 +35,10 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
sound_environment = SOUND_ENVIRONMENT_PLAIN
ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/ambiodd.ogg','sound/ambience/ambinice.ogg')
+/area/awaymission/museum/cafeteria
+ name = "Nanotrasen Museum Cafeteria"
+ sound_environment = SOUND_ENVIRONMENT_ROOM
+
/area/awaymission/errorroom
name = "Super Secret Room"
static_lighting = FALSE
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index af6b477e90ba8..d9e3787fd9ead 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -248,7 +248,7 @@ Buildable meters
return TRUE
// no conflicts found
- var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, , , p_init_dir)
+ var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, null, fixed_dir(), p_init_dir)
build_pipe(built_machine)
built_machine.on_construction(user, pipe_color, piping_layer)
transfer_fingerprints_to(built_machine)
@@ -356,9 +356,6 @@ Buildable meters
return FALSE
/obj/item/pipe/proc/build_pipe(obj/machinery/atmospherics/A)
- A.setDir(fixed_dir())
- A.set_init_directions(p_init_dir)
-
if(pipename)
A.name = pipename
if(A.on)
diff --git a/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm b/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm
index 7a04aaf2435f5..412cca0495299 100644
--- a/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm
+++ b/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm
@@ -178,7 +178,7 @@
candidate_list += GLOB.current_observers_list
candidate_list += GLOB.dead_player_list
- var/list/candidates = SSpolling.poll_candidates("Would you like to participate in a spooky ghost swarm? (Warning: you will not be able to return to your body!)", check_jobban = ROLE_SENTIENCE, poll_time = 10 SECONDS, group = candidate_list, pic_source = src, role_name_text = "ghost swarm")
+ var/list/candidates = SSpolling.poll_candidates("Would you like to participate in a spooky ghost swarm? (Warning: you will not be able to return to your body!)", check_jobban = ROLE_SENTIENCE, poll_time = 10 SECONDS, group = candidate_list, alert_pic = src, role_name_text = "ghost swarm")
for(var/mob/dead/observer/candidate_ghost as anything in candidates)
var/mob/living/basic/ghost/swarm/new_ghost = new(get_turf(src))
ghosts_spawned += new_ghost
diff --git a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm
index 87221eeec9fa6..a4880fdc26738 100644
--- a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm
+++ b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm
@@ -39,12 +39,10 @@
var/datum/action/innate/slime/reproduce/repro_action = new
repro_action.Grant(pyro)
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a pyroclastic anomaly slime?", check_jobban = ROLE_SENTIENCE, poll_time = 10 SECONDS, target_mob = pyro, ignore_category = POLL_IGNORE_PYROSLIME, pic_source = pyro, role_name_text = "pyroclastic anomaly slime")
- if(!LAZYLEN(candidates))
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_SENTIENCE, poll_time = 10 SECONDS, checked_target = pyro, ignore_category = POLL_IGNORE_PYROSLIME, alert_pic = pyro, role_name_text = "pyroclastic anomaly slime")
+ if(isnull(chosen_one))
return
-
- var/mob/dead/observer/chosen = pick(candidates)
- pyro.key = chosen.key
+ pyro.key = chosen_one.key
pyro.mind.special_role = ROLE_PYROCLASTIC_SLIME
pyro.mind.add_antag_datum(/datum/antagonist/pyro_slime)
pyro.log_message("was made into a slime by pyroclastic anomaly", LOG_GAME)
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index 7fe6c59075f3f..4b23987b97914 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -129,6 +129,7 @@
desc = "Somebody should remove that."
gender = NEUTER
layer = WALL_OBJ_LAYER
+ icon = 'icons/effects/web.dmi'
icon_state = "cobweb1"
resistance_flags = FLAMMABLE
beauty = -100
diff --git a/code/game/objects/effects/posters/contraband.dm b/code/game/objects/effects/posters/contraband.dm
index 2bb2fcce50e46..52528c251b659 100644
--- a/code/game/objects/effects/posters/contraband.dm
+++ b/code/game/objects/effects/posters/contraband.dm
@@ -625,3 +625,35 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/blood_geometer
icon_state = "singletank_bomb"
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/singletank_bomb, 32)
+
+///a special poster meant to fool people into thinking this is a bombable wall at a glance.
+/obj/structure/sign/poster/contraband/fake_bombable
+ name = "fake bombable poster"
+ desc = "We do a little trolling."
+ icon_state = "fake_bombable"
+ never_random = TRUE
+
+/obj/structure/sign/poster/contraband/fake_bombable/Initialize(mapload)
+ . = ..()
+ var/turf/our_wall = get_turf_pixel(src)
+ name = our_wall.name
+
+/obj/structure/sign/poster/contraband/fake_bombable/examine(mob/user)
+ var/turf/our_wall = get_turf_pixel(src)
+ . = our_wall.examine(user)
+ . += span_notice("It seems to be slightly cracked...")
+
+/obj/structure/sign/poster/contraband/fake_bombable/ex_act(severity, target)
+ addtimer(CALLBACK(src, PROC_REF(fall_off_wall)), 2.5 SECONDS)
+ return FALSE
+
+/obj/structure/sign/poster/contraband/fake_bombable/proc/fall_off_wall()
+ if(QDELETED(src) || !isturf(loc))
+ return
+ var/turf/our_wall = get_turf_pixel(src)
+ our_wall.balloon_alert_to_viewers("it was a ruse!")
+ roll_and_drop(loc)
+ playsound(loc, 'sound/items/handling/paper_drop.ogg', 50, TRUE)
+
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/fake_bombable, 32)
diff --git a/code/game/objects/effects/spawners/random/vending.dm b/code/game/objects/effects/spawners/random/vending.dm
index 74ece7f24f93d..014f07d2967c4 100644
--- a/code/game/objects/effects/spawners/random/vending.dm
+++ b/code/game/objects/effects/spawners/random/vending.dm
@@ -18,6 +18,11 @@
loot_type_path = /obj/machinery/vending/snack
loot = list()
+/obj/effect/spawner/random/vending/snackvend/Initialize(mapload)
+ if(check_holidays(HOTDOG_DAY))
+ loot += /obj/machinery/vending/hotdog
+ return ..()
+
/obj/effect/spawner/random/vending/colavend
name = "spawn random cola vending machine"
desc = "Automagically transforms into a random cola vendor. If you see this while in a shift, please create a bug report."
diff --git a/code/game/objects/effects/spiderwebs.dm b/code/game/objects/effects/spiderwebs.dm
index 5023f9bd8254e..2d0f1b9b14de2 100644
--- a/code/game/objects/effects/spiderwebs.dm
+++ b/code/game/objects/effects/spiderwebs.dm
@@ -1,7 +1,8 @@
-//generic procs copied from obj/effect/alien
+#define SPIDER_WEB_TINT "web_colour_tint"
+
/obj/structure/spider
name = "web"
- icon = 'icons/effects/effects.dmi'
+ icon = 'icons/effects/web.dmi'
desc = "It's stringy and sticky."
anchored = TRUE
density = FALSE
@@ -22,7 +23,7 @@
damage_amount *= 1.25
if(BRUTE)
damage_amount *= 0.25
- . = ..()
+ return ..()
/obj/structure/spider/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return exposed_temperature > 350
@@ -31,17 +32,37 @@
take_damage(5, BURN, 0, 0)
/obj/structure/spider/stickyweb
+ plane = FLOOR_PLANE
+ layer = MID_TURF_LAYER
+ icon = 'icons/obj/smooth_structures/stickyweb.dmi'
+ base_icon_state = "stickyweb"
+ icon_state = "stickyweb-0"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = SMOOTH_GROUP_SPIDER_WEB
+ canSmoothWith = SMOOTH_GROUP_SPIDER_WEB + SMOOTH_GROUP_WALLS
///Whether or not the web is from the genetics power
var/genetic = FALSE
///Whether or not the web is a sealed web
var/sealed = FALSE
- icon_state = "stickyweb1"
+ ///Do we need to offset this based on a sprite frill?
+ var/has_frill = TRUE
+ /// Chance that someone will get stuck when trying to cross this tile
+ var/stuck_chance = 50
+ /// Chance that a bullet will hit this instead of flying through it
+ var/projectile_stuck_chance = 30
+
+/obj/structure/spider/stickyweb/Initialize(mapload)
+ // Offset on init so that they look nice in the map editor
+ if (has_frill)
+ pixel_x = -9
+ pixel_y = -9
+ return ..()
/obj/structure/spider/stickyweb/attack_hand(mob/user, list/modifiers)
.= ..()
if(.)
return
- if(!HAS_TRAIT(user,TRAIT_WEB_WEAVER))
+ if(!HAS_TRAIT(user, TRAIT_WEB_WEAVER))
return
loc.balloon_alert_to_viewers("weaving...")
if(!do_after(user, 2 SECONDS))
@@ -51,11 +72,6 @@
var/obj/item/stack/sheet/cloth/woven_cloth = new /obj/item/stack/sheet/cloth
user.put_in_hands(woven_cloth)
-/obj/structure/spider/stickyweb/Initialize(mapload)
- if(!sealed && prob(50))
- icon_state = "stickyweb2"
- . = ..()
-
/obj/structure/spider/stickyweb/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
if(genetic)
@@ -67,65 +83,125 @@
return TRUE
if(mover.pulledby && HAS_TRAIT(mover.pulledby, TRAIT_WEB_SURFER))
return TRUE
- if(prob(50))
- loc.balloon_alert(mover, "stuck in web!")
+ if(prob(stuck_chance))
+ stuck_react(mover)
return FALSE
- else if(isprojectile(mover))
- return prob(30)
-
-/obj/structure/spider/stickyweb/sealed
- name = "sealed web"
- desc = "A solid thick wall of web, airtight enough to block air flow."
- icon_state = "sealedweb"
- sealed = TRUE
- can_atmos_pass = ATMOS_PASS_NO
+ return .
+ if(isprojectile(mover))
+ return prob(projectile_stuck_chance)
+ return .
-/obj/structure/spider/stickyweb/sealed/Initialize(mapload)
- . = ..()
- air_update_turf(TRUE, TRUE)
+/// Show some feedback when you can't pass through something
+/obj/structure/spider/stickyweb/proc/stuck_react(atom/movable/stuck_guy)
+ loc.balloon_alert(stuck_guy, "stuck in web!")
+ stuck_guy.Shake(duration = 0.1 SECONDS)
-/obj/structure/spider/stickyweb/genetic //for the spider genes in genetics
+/// Web made by geneticists, needs special handling to allow them to pass through their own webs
+/obj/structure/spider/stickyweb/genetic
genetic = TRUE
+ desc = "It's stringy, sticky, and came out of your coworker."
+ /// Mob with special permission to cross this web
var/mob/living/allowed_mob
/obj/structure/spider/stickyweb/genetic/Initialize(mapload, allowedmob)
- allowed_mob = allowedmob
. = ..()
+ // Tint it purple so that spiders don't get confused about why they can't cross this one
+ add_filter(SPIDER_WEB_TINT, 10, list("type" = "outline", "color" = "#ffaaf8ff", "size" = 0.1))
+
+/obj/structure/spider/stickyweb/genetic/Initialize(mapload, allowedmob)
+ allowed_mob = allowedmob
+ return ..()
/obj/structure/spider/stickyweb/genetic/CanAllowThrough(atom/movable/mover, border_dir)
- . = ..() //this is the normal spider web return aka a spider would make this TRUE
+ . = ..()
if(mover == allowed_mob)
return TRUE
else if(isliving(mover)) //we change the spider to not be able to go through here
if(mover.pulledby == allowed_mob)
return TRUE
if(prob(50))
- loc.balloon_alert(mover, "stuck in web!")
+ stuck_react(mover)
return FALSE
else if(isprojectile(mover))
return prob(30)
+ return .
-/obj/structure/spider/solid
- name = "solid web"
- icon = 'icons/effects/effects.dmi'
- desc = "A solid wall of web, thick enough to block air flow."
- icon_state = "solidweb"
+/// Web with a 100% chance to intercept movement
+/obj/structure/spider/stickyweb/very_sticky
+ max_integrity = 20
+ desc = "Extremely sticky silk, you're not easily getting through there."
+ stuck_chance = 100
+ projectile_stuck_chance = 100
+
+/obj/structure/spider/stickyweb/very_sticky/Initialize(mapload)
+ . = ..()
+ add_filter(SPIDER_WEB_TINT, 10, list("type" = "outline", "color" = "#ffffaaff", "size" = 0.1))
+
+/obj/structure/spider/stickyweb/very_sticky/update_overlays()
+ . = ..()
+ var/mutable_appearance/web_overlay = mutable_appearance(icon = 'icons/effects/web.dmi', icon_state = "sticky_overlay", layer = layer + 1)
+ web_overlay.pixel_x -= pixel_x
+ web_overlay.pixel_y -= pixel_y
+ . += web_overlay
+
+
+/// Web 'wall'
+/obj/structure/spider/stickyweb/sealed
+ name = "sealed web"
+ desc = "A solid wall of web, dense enough to block air flow."
+ icon = 'icons/obj/smooth_structures/webwall.dmi'
+ base_icon_state = "webwall"
+ icon_state = "webwall-0"
+ smoothing_groups = SMOOTH_GROUP_SPIDER_WEB_WALL
+ canSmoothWith = SMOOTH_GROUP_SPIDER_WEB_WALL
+ plane = GAME_PLANE
+ layer = OBJ_LAYER
+ sealed = TRUE
+ has_frill = FALSE
can_atmos_pass = ATMOS_PASS_NO
+
+/obj/structure/spider/stickyweb/sealed/Initialize(mapload)
+ . = ..()
+ air_update_turf(TRUE, TRUE)
+
+/// Walls which reflects lasers
+/obj/structure/spider/stickyweb/sealed/reflector
+ name = "reflective silk screen"
+ desc = "Hardened webbing treated with special chemicals which cause it to repel projectiles."
+ icon = 'icons/obj/smooth_structures/webwall_reflector.dmi'
+ base_icon_state = "webwall_reflector"
+ icon_state = "webwall_reflector-0"
+ smoothing_groups = SMOOTH_GROUP_SPIDER_WEB_WALL_MIRROR
+ canSmoothWith = SMOOTH_GROUP_SPIDER_WEB_WALL_MIRROR
+ max_integrity = 30
+ opacity = TRUE
+ flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD
+ receive_ricochet_chance_mod = INFINITY
+
+/// Opaque and durable web 'wall'
+/obj/structure/spider/stickyweb/sealed/tough
+ name = "hardened web"
+ desc = "Webbing hardened through a chemical process into a durable barrier."
+ icon = 'icons/obj/smooth_structures/webwall_dark.dmi'
+ base_icon_state = "webwall_dark"
+ icon_state = "webwall_dark-0"
+ smoothing_groups = SMOOTH_GROUP_SPIDER_WEB_WALL_TOUGH
+ canSmoothWith = SMOOTH_GROUP_SPIDER_WEB_WALL_TOUGH
opacity = TRUE
- density = TRUE
max_integrity = 90
layer = ABOVE_MOB_LAYER
resistance_flags = FIRE_PROOF | FREEZE_PROOF
-/obj/structure/spider/solid/Initialize(mapload)
- . = ..()
- air_update_turf(TRUE, TRUE)
-
+/// Web 'door', blocks atmos but not movement
/obj/structure/spider/passage
name = "web passage"
- icon = 'icons/effects/effects.dmi'
- desc = "A messy connection of webs blocking the other side, but not solid enough to prevent passage."
- icon_state = "webpassage"
+ desc = "An opaque curtain of web which seals in air but doesn't impede passage."
+ icon = 'icons/obj/smooth_structures/stickyweb_rotated.dmi'
+ base_icon_state = "stickyweb_rotated"
+ icon_state = "stickyweb_rotated-0"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = SMOOTH_GROUP_SPIDER_WEB_ROOF
+ canSmoothWith = SMOOTH_GROUP_SPIDER_WEB_ROOF + SMOOTH_GROUP_WALLS
can_atmos_pass = ATMOS_PASS_NO
opacity = TRUE
max_integrity = 60
@@ -135,7 +211,10 @@
/obj/structure/spider/passage/Initialize(mapload)
. = ..()
+ pixel_x = -9
+ pixel_y = -9
air_update_turf(TRUE, TRUE)
+ add_filter(SPIDER_WEB_TINT, 10, list("type" = "outline", "color" = "#ffffffff", "alpha" = 0.8, "size" = 0.1))
/obj/structure/spider/cocoon
name = "cocoon"
@@ -165,56 +244,31 @@
A.forceMove(T)
return ..()
-/obj/structure/spider/sticky
- name = "sticky web"
- icon = 'icons/effects/effects.dmi'
- desc = "Extremely soft and sticky silk."
- icon_state = "verystickyweb"
- max_integrity = 20
-
-/obj/structure/spider/sticky/CanAllowThrough(atom/movable/mover, border_dir)
- . = ..()
- if(HAS_TRAIT(mover, TRAIT_WEB_SURFER))
- return TRUE
- if(!isliving(mover))
- return
- if(!isnull(mover.pulledby) && HAS_TRAIT(mover.pulledby, TRAIT_WEB_SURFER))
- return TRUE
- loc.balloon_alert(mover, "stuck in web!")
- return FALSE
-
+/// Web caltrops
/obj/structure/spider/spikes
name = "web spikes"
- icon = 'icons/effects/effects.dmi'
desc = "Silk hardened into small yet deadly spikes."
- icon_state = "webspikes1"
+ plane = FLOOR_PLANE
+ layer = MID_TURF_LAYER
+ icon = 'icons/obj/smooth_structures/stickyweb_spikes.dmi'
+ base_icon_state = "stickyweb_spikes"
+ icon_state = "stickyweb_spikes-0"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = SMOOTH_GROUP_SPIDER_WEB
+ canSmoothWith = SMOOTH_GROUP_SPIDER_WEB + SMOOTH_GROUP_WALLS
max_integrity = 40
/obj/structure/spider/spikes/Initialize(mapload)
. = ..()
+ pixel_x = -9
+ pixel_y = -9
+ add_filter(SPIDER_WEB_TINT, 10, list("type" = "outline", "color" = "#ac0000ff", "size" = 0.1))
AddComponent(/datum/component/caltrop, min_damage = 20, max_damage = 30, flags = CALTROP_NOSTUN | CALTROP_BYPASS_SHOES)
-/obj/structure/spider/reflector
- name = "Reflective silk screen"
- icon = 'icons/effects/effects.dmi'
- desc = "Made up of an extremly reflective silk material looking at it hurts."
- icon_state = "reflector"
- max_integrity = 30
- density = TRUE
- opacity = TRUE
- anchored = TRUE
- flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD
- receive_ricochet_chance_mod = INFINITY
-
-/obj/structure/spider/reflector/Initialize(mapload)
- . = ..()
- air_update_turf(TRUE, TRUE)
-
/obj/structure/spider/effigy
name = "web effigy"
- icon = 'icons/effects/effects.dmi'
desc = "A giant spider! Fortunately, this one is just a statue of hardened webbing."
- icon_state = "webcarcass"
+ icon_state = "effigy"
max_integrity = 125
density = TRUE
anchored = FALSE
@@ -222,3 +276,5 @@
/obj/structure/spider/effigy/Initialize(mapload)
. = ..()
AddElement(/datum/element/temporary_atom, 1 MINUTES)
+
+#undef SPIDER_WEB_TINT
diff --git a/code/game/objects/items/busts_and_figurines.dm b/code/game/objects/items/busts_and_figurines.dm
new file mode 100644
index 0000000000000..afc4a58334e90
--- /dev/null
+++ b/code/game/objects/items/busts_and_figurines.dm
@@ -0,0 +1,139 @@
+/obj/item/statuebust
+ name = "bust"
+ desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it
+ icon = 'icons/obj/art/statue.dmi'
+ icon_state = "bust"
+ force = 15
+ throwforce = 10
+ throw_speed = 5
+ throw_range = 2
+ attack_verb_continuous = list("busts")
+ attack_verb_simple = list("bust")
+ var/impressiveness = 45
+
+/obj/item/statuebust/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/art, impressiveness)
+ AddElement(/datum/element/beauty, 1000)
+
+/obj/item/statuebust/hippocratic
+ name = "hippocrates bust"
+ desc = "A bust of the famous Greek physician Hippocrates of Kos, often referred to as the father of western medicine."
+ icon_state = "hippocratic"
+ impressiveness = 50
+ // If it hits the prob(reference_chance) chance, this is set to TRUE. Adds medical HUD when wielded, but has a 10% slower attack speed and is too bloody to make an oath with.
+ var/reference = FALSE
+ // Chance for above.
+ var/reference_chance = 1
+ // Minimum time inbetween oaths.
+ COOLDOWN_DECLARE(oath_cd)
+
+/obj/item/statuebust/hippocratic/evil
+ reference_chance = 100
+
+/obj/item/statuebust/hippocratic/Initialize(mapload)
+ . = ..()
+ if(prob(reference_chance))
+ name = "Solemn Vow"
+ desc = "Art lovers will cherish the bust of Hippocrates, commemorating a time when medics still thought doing no harm was a good idea."
+ attack_speed = CLICK_CD_SLOW
+ reference = TRUE
+
+/obj/item/statuebust/hippocratic/examine(mob/user)
+ . = ..()
+ if(reference)
+ . += span_notice("You could activate the bust in-hand to swear or forswear a Hippocratic Oath... but it seems like somebody decided it was more of a Hippocratic Suggestion. This thing is caked with bits of blood and gore.")
+ return
+ . += span_notice("You can activate the bust in-hand to swear or forswear a Hippocratic Oath! This has no effects except pacifism or bragging rights. Does not remove other sources of pacifism. Do not eat.")
+
+/obj/item/statuebust/hippocratic/equipped(mob/living/carbon/human/user, slot)
+ ..()
+ if(!(slot & ITEM_SLOT_HANDS))
+ return
+ var/datum/atom_hud/our_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
+ our_hud.show_to(user)
+ ADD_TRAIT(user, TRAIT_MEDICAL_HUD, type)
+
+/obj/item/statuebust/hippocratic/dropped(mob/living/carbon/human/user)
+ ..()
+ if(HAS_TRAIT_NOT_FROM(user, TRAIT_MEDICAL_HUD, type))
+ return
+ var/datum/atom_hud/our_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
+ our_hud.hide_from(user)
+ REMOVE_TRAIT(user, TRAIT_MEDICAL_HUD, type)
+
+/obj/item/statuebust/hippocratic/attack_self(mob/user)
+ if(!iscarbon(user))
+ to_chat(user, span_warning("You remember how the Hippocratic Oath specifies 'my fellow human beings' and realize that it's completely meaningless to you."))
+ return
+
+ if(reference)
+ to_chat(user, span_warning("As you prepare yourself to swear the Oath, you realize that doing so on a blood-caked bust is probably not a good idea."))
+ return
+
+ if(!COOLDOWN_FINISHED(src, oath_cd))
+ to_chat(user, span_warning("You've sworn or forsworn an oath too recently to undo your decisions. The bust looks at you with disgust."))
+ return
+
+ COOLDOWN_START(src, oath_cd, 5 MINUTES)
+
+ if(HAS_TRAIT_FROM(user, TRAIT_PACIFISM, type))
+ to_chat(user, span_warning("You've already sworn a vow. You start preparing to rescind it..."))
+ if(do_after(user, 5 SECONDS, target = user))
+ user.say("Yeah this Hippopotamus thing isn't working out. I quit!", forced = "hippocratic hippocrisy")
+ REMOVE_TRAIT(user, TRAIT_PACIFISM, type)
+
+ // they can still do it for rp purposes
+ if(HAS_TRAIT_NOT_FROM(user, TRAIT_PACIFISM, type))
+ to_chat(user, span_warning("You already don't want to harm people, this isn't going to do anything!"))
+
+
+ to_chat(user, span_notice("You remind yourself of the Hippocratic Oath's contents and prepare to swear yourself to it..."))
+ if(do_after(user, 4 SECONDS, target = user))
+ user.say("I swear to fulfill, to the best of my ability and judgment, this covenant:", forced = "hippocratic oath")
+ else
+ return fuck_it_up(user)
+ if(do_after(user, 2 SECONDS, target = user))
+ user.say("I will apply, for the benefit of the sick, all measures that are required, avoiding those twin traps of overtreatment and therapeutic nihilism.", forced = "hippocratic oath")
+ else
+ return fuck_it_up(user)
+ if(do_after(user, 3 SECONDS, target = user))
+ user.say("I will remember that I remain a member of society, with special obligations to all my fellow human beings, those sound of mind and body as well as the infirm.", forced = "hippocratic oath")
+ else
+
+ return fuck_it_up(user)
+ if(do_after(user, 3 SECONDS, target = user))
+ user.say("If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help.", forced = "hippocratic oath")
+ else
+ return fuck_it_up(user)
+
+ to_chat(user, span_notice("Contentment, understanding, and purpose washes over you as you finish the oath. You consider for a second the concept of harm and shudder."))
+ ADD_TRAIT(user, TRAIT_PACIFISM, type)
+
+// Bully the guy for fucking up.
+/obj/item/statuebust/hippocratic/proc/fuck_it_up(mob/living/carbon/user)
+ to_chat(user, span_warning("You forget what comes next like a dumbass. The Hippocrates bust looks down on you, disappointed."))
+ user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2)
+ COOLDOWN_RESET(src, oath_cd)
+
+/obj/item/maneki_neko
+ name = "Maneki-Neko"
+ desc = "A figurine of a cat holding a coin, said to bring fortune and wealth, and perpetually moving its paw in a beckoning gesture."
+ icon = 'icons/obj/fluff/general.dmi'
+ icon_state = "maneki-neko"
+ w_class = WEIGHT_CLASS_SMALL
+ force = 5
+ throwforce = 5
+ throw_speed = 3
+ throw_range = 5
+ attack_verb_continuous = list("bashes", "beckons", "hit")
+ attack_verb_simple = list("bash", "beckon", "hit")
+
+/obj/item/maneki_neko/Initialize(mapload)
+ . = ..()
+ //Not compatible with greyscale configs because it's animated.
+ color = pick_weight(list(COLOR_WHITE = 3, COLOR_GOLD = 2, COLOR_DARK = 1))
+ var/mutable_appearance/neko_overlay = mutable_appearance(icon, "maneki-neko-overlay", appearance_flags = RESET_COLOR)
+ add_overlay(neko_overlay)
+ AddElement(/datum/element/art, GOOD_ART)
+ AddElement(/datum/element/beauty, 800)
diff --git a/code/game/objects/items/devices/aicard_evil.dm b/code/game/objects/items/devices/aicard_evil.dm
index f91150bb086a6..8aaa9f0311116 100644
--- a/code/game/objects/items/devices/aicard_evil.dm
+++ b/code/game/objects/items/devices/aicard_evil.dm
@@ -34,14 +34,16 @@
if(isnull(op_datum))
balloon_alert(user, "invalid access!")
return
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(on_poll_concluded), user, op_datum)
- AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_SYNDICATE, \
- job_bans = ROLE_OPERATIVE, \
- to_call = to_call, \
- title = "Nuclear Operative Modsuit AI" \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ check_jobban = ROLE_OPERATIVE,
+ poll_time = 20 SECONDS,
+ checked_target = src,
+ ignore_category = POLL_IGNORE_SYNDICATE,
+ alert_pic = src,
+ role_name_text = "Nuclear Operative Modsuit AI",
+ chat_text_border_icon = mutable_appearance(icon, "syndicard-full"),
)
+ on_poll_concluded(user, op_datum, chosen_one)
/// Poll has concluded with a ghost, create the AI
/obj/item/aicard/syndie/loaded/proc/on_poll_concluded(mob/user, datum/antagonist/nukeop/op_datum, mob/dead/observer/ghost)
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index 6f425b7df6eab..ca2a972006da6 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -425,11 +425,10 @@
var/mob/living/carbon/human/human_servant = new(drop_location())
do_smoke(0, holder = src, location = drop_location())
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as [user.real_name]'s Servant?", check_jobban = ROLE_WIZARD, role = ROLE_WIZARD, poll_time = 5 SECONDS, target_mob = human_servant, pic_source = user, role_name_text = "dice servant")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/candidate = pick(candidates)
- message_admins("[ADMIN_LOOKUPFLW(candidate)] was spawned as Dice Servant")
- human_servant.key = candidate.key
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger("[user.real_name]'s")] [span_notice("Servant")]?", check_jobban = ROLE_WIZARD, role = ROLE_WIZARD, poll_time = 5 SECONDS, checked_target = human_servant, alert_pic = user, role_name_text = "dice servant")
+ if(chosen_one)
+ message_admins("[ADMIN_LOOKUPFLW(chosen_one)] was spawned as Dice Servant")
+ human_servant.key = chosen_one.key
human_servant.equipOutfit(/datum/outfit/butler)
var/datum/mind/servant_mind = new /datum/mind()
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index 920d074ad4a4e..b0189a0c4ecef 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -279,13 +279,8 @@
/obj/item/extinguisher/proc/EmptyExtinguisher(mob/user)
if(loc == user && reagents.total_volume)
+ reagents.expose(user.loc, TOUCH)
reagents.clear_reagents()
-
- var/turf/T = get_turf(loc)
- if(isopenturf(T))
- var/turf/open/theturf = T
- theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
-
user.visible_message(span_notice("[user] empties out \the [src] onto the floor using the release valve."), span_info("You quietly empty out \the [src] using its release valve."))
//firebot assembly
@@ -297,3 +292,10 @@
user.put_in_hands(new /obj/item/bot_assembly/firebot)
else
..()
+
+/obj/item/extinguisher/anti
+ name = "fire extender"
+ desc = "A traditional red fire extinguisher. Made in Britain... wait, what?"
+ chem = /datum/reagent/fuel
+ tanktype = /obj/structure/reagent_dispensers/fueltank
+ cooling_power = 0
diff --git a/code/game/objects/items/food/bread.dm b/code/game/objects/items/food/bread.dm
index ba1845bb40da4..0f95aac6d8528 100644
--- a/code/game/objects/items/food/bread.dm
+++ b/code/game/objects/items/food/bread.dm
@@ -481,6 +481,7 @@
foodtypes = GRAIN | DAIRY
w_class = WEIGHT_CLASS_SMALL
crafting_complexity = FOOD_COMPLEXITY_2
+ custom_price = PAYCHECK_CREW
/obj/item/food/butterdog/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/food/lizard.dm b/code/game/objects/items/food/lizard.dm
index 729ad4d38a971..47b5ff7510916 100644
--- a/code/game/objects/items/food/lizard.dm
+++ b/code/game/objects/items/food/lizard.dm
@@ -34,6 +34,7 @@
foodtypes = MEAT
w_class = WEIGHT_CLASS_SMALL
crafting_complexity = FOOD_COMPLEXITY_2
+ custom_price = PAYCHECK_CREW
/obj/item/food/raw_headcheese
name = "raw headcheese block"
diff --git a/code/game/objects/items/food/martian.dm b/code/game/objects/items/food/martian.dm
index 2441ac0f67478..7ceaf1878176c 100644
--- a/code/game/objects/items/food/martian.dm
+++ b/code/game/objects/items/food/martian.dm
@@ -732,6 +732,7 @@
foodtypes = MEAT | VEGETABLES | FRUIT | PINEAPPLE
w_class = WEIGHT_CLASS_SMALL
crafting_complexity = FOOD_COMPLEXITY_4
+ custom_price = PAYCHECK_CREW * 1.2
/obj/item/food/salt_chilli_fries
name = "salt n' chilli fries"
@@ -1210,6 +1211,7 @@
foodtypes = FRUIT | MEAT | PINEAPPLE | VEGETABLES | GRAIN
w_class = WEIGHT_CLASS_SMALL
crafting_complexity = FOOD_COMPLEXITY_4 //Uses Sambal
+ custom_price = PAYCHECK_CREW * 2
/obj/item/food/frickles
name = "frickles"
diff --git a/code/game/objects/items/food/meatdish.dm b/code/game/objects/items/food/meatdish.dm
index b9a6c34df04ed..b7a4ca9991619 100644
--- a/code/game/objects/items/food/meatdish.dm
+++ b/code/game/objects/items/food/meatdish.dm
@@ -554,6 +554,7 @@
w_class = WEIGHT_CLASS_SMALL
venue_value = FOOD_PRICE_CHEAP
crafting_complexity = FOOD_COMPLEXITY_2
+ custom_price = PAYCHECK_CREW * 0.6
/obj/item/food/sausage/make_processable()
AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/salami, 6, 3 SECONDS, table_required = TRUE, screentip_verb = "Slice")
@@ -734,6 +735,7 @@
foodtypes = MEAT | DAIRY | GRAIN
w_class = WEIGHT_CLASS_TINY
crafting_complexity = FOOD_COMPLEXITY_3
+ custom_price = PAYCHECK_CREW
/obj/item/food/bbqribs
name = "bbq ribs"
diff --git a/code/game/objects/items/food/sandwichtoast.dm b/code/game/objects/items/food/sandwichtoast.dm
index c6488f67a1ed5..e440a1039e6d1 100644
--- a/code/game/objects/items/food/sandwichtoast.dm
+++ b/code/game/objects/items/food/sandwichtoast.dm
@@ -152,6 +152,7 @@
w_class = WEIGHT_CLASS_SMALL
venue_value = FOOD_PRICE_CHEAP
crafting_complexity = FOOD_COMPLEXITY_3
+ custom_price = PAYCHECK_CREW * 0.7
// Used for unit tests, do not delete
/obj/item/food/hotdog/debug
@@ -174,6 +175,7 @@
w_class = WEIGHT_CLASS_SMALL
venue_value = FOOD_PRICE_NORMAL
crafting_complexity = FOOD_COMPLEXITY_4
+ custom_price = PAYCHECK_CREW
/obj/item/food/sandwich/blt
name = "\improper BLT"
diff --git a/code/game/objects/items/piggy_bank.dm b/code/game/objects/items/piggy_bank.dm
new file mode 100644
index 0000000000000..6a9ee494a22ff
--- /dev/null
+++ b/code/game/objects/items/piggy_bank.dm
@@ -0,0 +1,129 @@
+/**
+ * Piggy banks. They store your hard-earned money until you or someone destroys it.
+ * If the persistence id is set, money will be carried between rounds until broken.
+ */
+/obj/item/piggy_bank
+ name = "piggy bank"
+ desc = "A pig-shaped money container made of porkelain, oink. Do not throw." //pun very intended.
+ icon = 'icons/obj/fluff/general.dmi'
+ icon_state = "piggy_bank"
+ max_integrity = 8
+ w_class = WEIGHT_CLASS_NORMAL
+ force = 12
+ throwforce = 15
+ throw_speed = 3
+ throw_range = 7
+ greyscale_config = /datum/greyscale_config/piggy_bank
+ ///Some piggy banks are persistent, meaning they carry dosh between rounds.
+ var/persistence_id
+ ///Callback to execute upon roundend to save the current amount of cash it has stored, IF persistent.
+ var/datum/callback/persistence_cb
+ ///How much dosh can this piggy bank hold.
+ var/maximum_value = PAYCHECK_COMMAND * 20
+ ///How much dosh this piggy bank spawns with.
+ var/initial_value = 0
+
+/obj/item/piggy_bank/Initialize(mapload)
+ if(!greyscale_colors)
+ greyscale_colors = pick(COLOR_PINK,
+ COLOR_LIGHT_ORANGE,
+ COLOR_GREEN_GRAY,
+ COLOR_PALE_BLUE_GRAY,
+ COLOR_DARK_MODERATE_LIME_GREEN,
+ COLOR_OFF_WHITE,
+ )
+
+ . = ..()
+
+ AddElement(/datum/element/can_shatter, shattering_sound = SFX_SHATTER, shatters_as_weapon = TRUE)
+ AddElement(/datum/element/beauty, 500)
+ if(!persistence_id)
+ if(initial_value)
+ new /obj/item/holochip(src, initial_value)
+ return
+
+ SSpersistence.load_piggy_bank(src)
+ persistence_cb = CALLBACK(src, PROC_REF(save_cash))
+ SSticker.OnRoundend(persistence_cb)
+
+ if(initial_value & initial_value + calculate_dosh_amount() <= maximum_value)
+ new /obj/item/holochip(src, initial_value)
+
+/obj/item/piggy_bank/proc/save_cash()
+ SSpersistence.save_piggy_bank(src)
+
+/obj/item/piggy_bank/Destroy()
+ if(persistence_cb)
+ LAZYREMOVE(SSticker.round_end_events, persistence_cb) //cleanup the callback.
+ persistence_cb = null
+ return ..()
+
+/obj/item/piggy_bank/deconstruct(disassembled = TRUE)
+ for(var/obj/item/thing as anything in contents)
+ thing.forceMove(loc)
+ //Smashing the piggy after the round is over doesn't count.
+ if(persistence_id && SSticker.current_state < GAME_STATE_FINISHED)
+ LAZYADD(SSpersistence.queued_broken_piggy_ids, persistence_id)
+ return ..()
+
+/obj/item/piggy_bank/attack_self(mob/user, modifiers)
+ . = ..()
+ if(DOING_INTERACTION_WITH_TARGET(user, src))
+ return
+ balloon_alert(user, "rattle rattle...")
+ if(!do_after(user, 0.5 SECONDS, src))
+ return
+ var/percentile = round(calculate_dosh_amount()/maximum_value * 100, 1)
+ if(percentile >= 10)
+ playsound(src, SFX_RATTLE, percentile * 0.5, FALSE, FALSE)
+ switch(percentile)
+ if(0)
+ balloon_alert(user, "it's empty")
+ if(1 to 9)
+ balloon_alert(user, "it's almost empty")
+ if(10 to 25)
+ balloon_alert(user, "it's some cash")
+ if(25 to 45)
+ balloon_alert(user, "it's plenty of cash")
+ if(45 to 70)
+ balloon_alert(user, "it feels almost full")
+ if(70 to 95)
+ balloon_alert(user, "it feels full")
+ if(95 to INFINITY)
+ balloon_alert(user, "brimming with cash")
+
+/obj/item/piggy_bank/attackby(obj/item/item, mob/user, params)
+ var/creds_value = item.get_item_credit_value()
+ if(isnull(creds_value))
+ return ..()
+
+ var/dosh_amount = calculate_dosh_amount()
+
+ if(dosh_amount >= maximum_value)
+ balloon_alert(user, "it's full!")
+ else if(dosh_amount + creds_value > maximum_value)
+ balloon_alert(user, "too much cash!")
+ else if(!user.transferItemToLoc(item, src))
+ balloon_alert(user, "stuck in your hands!")
+ else
+ balloon_alert(user, "inserted [creds_value] creds")
+ return TRUE
+
+///Returns the total amount of credits that its contents amount to.
+/obj/item/piggy_bank/proc/calculate_dosh_amount()
+ var/total_value = 0
+ for(var/obj/item/item in contents)
+ total_value += item.get_item_credit_value()
+ return total_value
+
+/obj/item/piggy_bank/museum
+ name = "Pigston Swinelord VI"
+ desc = "The museum's mascot piggy bank and favorite embezzler, known to carry donations between shifts without paying taxes. The space IRS hates him."
+ persistence_id = "museum_piggy"
+ greyscale_colors = COLOR_PINK
+ maximum_value = PAYCHECK_COMMAND * 100
+ initial_value = PAYCHECK_COMMAND * 4
+
+/obj/item/piggy_bank/museum/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/areabound) //do not steal.
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index ca669a9733e12..90790a75ea20b 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -44,7 +44,7 @@
/obj/item/toy/plush/Initialize(mapload)
. = ..()
AddComponent(/datum/component/squeak, squeak_override)
- AddElement(/datum/element/bed_tuckable, 6, -5, 90)
+ AddElement(/datum/element/bed_tuckable, mapload, 6, -5, 90)
//have we decided if Pinocchio goes in the blue or pink aisle yet?
if(gender == NEUTER)
diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm
index 7ac22d00897ea..dca3fe172159a 100644
--- a/code/game/objects/items/puzzle_pieces.dm
+++ b/code/game/objects/items/puzzle_pieces.dm
@@ -289,28 +289,47 @@
// literally just buttons
//
-/obj/machinery/puzzle_button
- name = "control panel"
- desc = "A panel that controls something nearby. I'm sure it being covered in hazard stripes is fine."
+/obj/machinery/puzzle
+ name = "abstract puzzle gizmo"
icon = 'icons/obj/machines/wallmounts.dmi'
- icon_state = "lockdown0"
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
- base_icon_state = "lockdown"
/// have we been pressed already?
var/used = FALSE
/// can we be pressed only once?
var/single_use = TRUE
/// puzzle id we send on press
- var/id = "0" //null would literally open every puzzle door without an id
+ var/id //null would literally open every puzzle door without an id
/// queue size, must match count of objects this activates!
var/queue_size = 2
+ /// should the puzzle machinery perform the final step of the queue link on LateInitialize? An alternative to queue size
+ var/late_initialize_pop = FALSE
-/obj/machinery/puzzle_button/Initialize(mapload)
+/obj/machinery/puzzle/Initialize(mapload)
. = ..()
if(!isnull(id))
- SSqueuelinks.add_to_queue(src, id, queue_size)
+ SSqueuelinks.add_to_queue(src, id, late_initialize_pop ? 0 : queue_size)
+ return late_initialize_pop ? INITIALIZE_HINT_LATELOAD : .
+
+/obj/machinery/puzzle/LateInitialize()
+ . = ..()
+ if(late_initialize_pop && id && SSqueuelinks.queues[id])
+ SSqueuelinks.pop_link(id)
+
+/obj/machinery/puzzle/proc/on_puzzle_complete() //incase someone wants to make this do something else for some reason
+ SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
+
+/obj/machinery/puzzle/update_icon_state()
+ icon_state = "[base_icon_state][used]"
+ return ..()
+
+/obj/machinery/puzzle/button
+ name = "control panel"
+ desc = "A panel that controls something nearby. I'm sure it being covered in hazard stripes is fine."
+ icon = 'icons/obj/machines/wallmounts.dmi'
+ icon_state = "lockdown0"
+ base_icon_state = "lockdown"
-/obj/machinery/puzzle_button/attack_hand(mob/user, list/modifiers)
+/obj/machinery/puzzle/button/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
@@ -320,37 +339,17 @@
update_icon_state()
visible_message(span_notice("[user] presses a button on [src]."), span_notice("You press a button on [src]."))
playsound(src, 'sound/machines/terminal_button07.ogg', 45, TRUE)
- open_doors()
+ on_puzzle_complete()
-/obj/machinery/puzzle_button/proc/open_doors() //incase someone wants to make this do something else for some reason
- SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
-
-/obj/machinery/puzzle_button/update_icon_state()
- icon_state = "[base_icon_state][used]"
- return ..()
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle/button, 32)
-MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_button, 32)
-
-/obj/machinery/puzzle_keycardpad
+/obj/machinery/puzzle/keycardpad
name = "keycard panel"
desc = "A panel that controls something nearby. Accepts keycards."
- icon = 'icons/obj/machines/wallmounts.dmi'
icon_state = "keycardpad0"
- resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
base_icon_state = "keycardpad"
- /// were we used successfully?
- var/used = FALSE
- /// puzzle id we send if the correct card is swiped
- var/id = "0"
- /// queue size, must match count of objects this activates!
- var/queue_size = 2
-
-/obj/machinery/puzzle_keycardpad/Initialize(mapload)
- . = ..()
- if(!isnull(id))
- SSqueuelinks.add_to_queue(src, id, queue_size)
-/obj/machinery/puzzle_keycardpad/attackby(obj/item/attacking_item, mob/user, params)
+/obj/machinery/puzzle/keycardpad/attackby(obj/item/attacking_item, mob/user, params)
. = ..()
if(!istype(attacking_item, /obj/item/keycard) || used)
return
@@ -363,13 +362,75 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_button, 32)
used = TRUE
update_icon_state()
playsound(src, 'sound/machines/beep.ogg', 45, TRUE)
- SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
+ on_puzzle_complete()
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle/keycardpad, 32)
+
+/obj/machinery/puzzle/password
+ name = "password panel"
+ desc = "A panel that controls something nearby. This one requires a (case-sensitive) password, and it's not \"Swordfish\"."
+ icon_state = "passpad0"
+ base_icon_state = "passpad"
+ ///The password to this door.
+ var/password = ""
+ ///The text shown in the tgui input popup
+ var/tgui_text = "Please enter the password."
+ ///The title of the tgui input popup
+ var/tgui_title = "What's the password?"
+ ///Decides whether the max length of the input is MAX_NAME_LEN or the length of the password.
+ var/input_max_len_is_pass = FALSE
+
+/obj/machinery/puzzle/password/interact(mob/user, list/modifiers)
+ if(used && single_use)
+ return
+ if(!user.can_perform_action(src, ALLOW_SILICON_REACH) || !user.can_interact_with(src))
+ return
+ var/pass_input = tgui_input_text(user, tgui_text, tgui_title, max_length = input_max_len_is_pass ? length(password) : MAX_NAME_LEN)
+ if(isnull(pass_input) || !user.can_perform_action(src, ALLOW_SILICON_REACH) || !user.can_interact_with(src))
+ return
+ var/correct = pass_input == password
+ balloon_alert_to_viewers("[correct ? "correct" : "wrong"] password[correct ? "" : "!"]")
+ if(!correct)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 45, TRUE)
+ return
+ used = single_use
+ update_icon_state()
+ playsound(src, 'sound/machines/terminal_button07.ogg', 45, TRUE)
+ on_puzzle_complete()
-/obj/machinery/puzzle_keycardpad/update_icon_state()
- icon_state = "[base_icon_state][used]"
- return ..()
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle/password, 32)
-MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_keycardpad, 32)
+/obj/machinery/puzzle/password/pin
+ desc = "A panel that controls something nearby. This one requires a PIN password, so let's start by typing in 1234..."
+ tgui_text = "Please enter the PIN code."
+ tgui_title = "What's the PIN code?"
+ input_max_len_is_pass = TRUE
+ ///The length of the PIN. Suggestion: something between 4 and 12.
+ var/pin_length = 6
+ ///associate a color to each digit that may be found in the password.
+ var/list/digit_to_color = list()
+
+/obj/machinery/puzzle/password/pin/Initialize(mapload)
+ . = ..()
+
+ for(var/iteration in 1 to pin_length)
+ password += "[rand(1, 9)]"
+
+ var/list/possible_colors = list(
+ "white",
+ "black",
+ "red",
+ "green",
+ "blue",
+ "yellow",
+ "orange",
+ "brown",
+ "gray",
+ )
+ for(var/digit in 0 to 9)
+ digit_to_color["[digit]"] = pick_n_take(possible_colors)
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle/password/pin, 32)
//
// blockade
@@ -445,7 +506,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_keycardpad, 32)
if(isnull(id) || isnull(queue_id))
log_mapping("[src] id:[id] has no id or door id and has been deleted")
return INITIALIZE_HINT_QDEL
-
+
SSqueuelinks.add_to_queue(src, queue_id)
/obj/effect/puzzle_poddoor_open/MatchedLinks(id, list/partners)
@@ -461,3 +522,99 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/puzzle_keycardpad, 32)
if(isnull(openclose))
openclose = door.density
INVOKE_ASYNC(door, openclose ? TYPE_PROC_REF(/obj/machinery/door/poddoor, open) : TYPE_PROC_REF(/obj/machinery/door/poddoor, close))
+
+#define MAX_PUZZLE_DOTS_PER_ROW 4
+#define PUZZLE_DOTS_VERTICAL_OFFSET 7
+#define PUZZLE_DOTS_HORIZONTAL_OFFSET 7
+
+///A dotted board that can be used as clue for PIN puzzle machinery
+/obj/effect/decal/puzzle_dots
+ name = "dotted board"
+ desc = "A board filled with colored dots. What could this mean?"
+ icon = 'icons/obj/fluff/puzzle_small.dmi'
+ icon_state = "puzzle_dots"
+ plane = GAME_PLANE //visible over walls
+ resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | UNACIDABLE | LAVA_PROOF
+ flags_1 = UNPAINTABLE_1
+ ///The id of the puzzle we're linked to.
+ var/id
+
+/obj/effect/decal/puzzle_dots/Initialize(mapload)
+ . = ..()
+ if(id)
+ SSqueuelinks.add_to_queue(src, id)
+
+/obj/effect/decal/puzzle_dots/MatchedLinks(id, partners)
+ var/obj/machinery/puzzle/password/pin/pad = locate() in partners
+ var/list/pass_digits = splittext(pad.password, "")
+ var/pass_len = length(pass_digits)
+ var/extra_rows = CEILING((pass_len/MAX_PUZZLE_DOTS_PER_ROW)-1, 1)
+ if(extra_rows)
+ pixel_y += round(extra_rows*(PUZZLE_DOTS_VERTICAL_OFFSET*0.5))
+ for(var/i in 1 to extra_rows)
+ var/mutable_appearance/row = mutable_appearance(icon, icon_state)
+ row.pixel_y = -i*PUZZLE_DOTS_VERTICAL_OFFSET
+ add_overlay(row)
+ for(var/i in 1 to pass_len)
+ var/mutable_appearance/colored_dot = mutable_appearance(icon, "puzzle_dot_single")
+ colored_dot.color = pad.digit_to_color[pass_digits[i]]
+ colored_dot.pixel_x = PUZZLE_DOTS_HORIZONTAL_OFFSET * ((i-1)%MAX_PUZZLE_DOTS_PER_ROW)
+ colored_dot.pixel_y -= CEILING((i/MAX_PUZZLE_DOTS_PER_ROW)-1, 1)*PUZZLE_DOTS_VERTICAL_OFFSET
+ add_overlay(colored_dot)
+
+#undef MAX_PUZZLE_DOTS_PER_ROW
+#undef PUZZLE_DOTS_VERTICAL_OFFSET
+#undef PUZZLE_DOTS_HORIZONTAL_OFFSET
+
+
+/obj/effect/decal/cleanable/crayon/puzzle
+ name = "Password character"
+ icon_state = "0"
+ ///The id of the puzzle we're linked to.
+ var/puzzle_id
+
+/obj/effect/decal/cleanable/crayon/puzzle/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null)
+ . = ..()
+ name = "number"
+ if(puzzle_id)
+ SSqueuelinks.add_to_queue(src, puzzle_id)
+
+/obj/effect/decal/cleanable/crayon/puzzle/MatchedLinks(id, partners)
+ var/obj/machinery/puzzle/password/pad = locate() in partners
+ var/list/pass_character = splittext(pad.password, "")
+ var/chosen_character = icon_state
+ if(!findtext(chosen_character, GLOB.is_alphanumeric))
+ qdel(src)
+ return FALSE
+ icon_state = pick(pass_character)
+ if(!text2num(icon_state))
+ name = "letter"
+ desc = "A letter vandalizing the station."
+ return TRUE
+
+/obj/effect/decal/cleanable/crayon/puzzle/pin
+ name = "PIN number"
+
+/obj/effect/decal/cleanable/crayon/puzzle/pin/MatchedLinks(id, partners)
+ . = ..()
+ var/obj/machinery/puzzle/password/pin/pad = locate() in partners
+ add_atom_colour(pad.digit_to_color[icon_state], FIXED_COLOUR_PRIORITY)
+
+/obj/item/paper/fluff/scrambled_pass
+ name = "gibberish note"
+ icon_state = "scrap"
+ ///The ID associated to the puzzle we're part of.
+ var/puzzle_id
+
+/obj/item/paper/fluff/scrambled_pass/Initialize(mapload)
+ . = ..()
+ if(mapload && puzzle_id)
+ SSqueuelinks.add_to_queue(src, puzzle_id)
+
+/obj/item/paper/fluff/scrambled_pass/MatchedLinks(id, partners)
+ var/obj/machinery/puzzle/password/pad = locate() in partners
+ var/scrambled_text = ""
+ var/list/pass_characters = splittext(pad.password, "")
+ for(var/i in 1 to rand(200, 300))
+ scrambled_text += pick(pass_characters)
+ add_raw_text(scrambled_text)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 306bc0fa9f942..1f33384b39337 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -310,6 +310,7 @@
name = "improvised gauze"
singular_name = "improvised gauze"
desc = "A roll of cloth roughly cut from something that does a decent job of stabilizing wounds, but less efficiently so than real medical gauze."
+ icon_state = "gauze_imp"
self_delay = 6 SECONDS
other_delay = 3 SECONDS
splint_factor = 0.85
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index e042ad4c01cb3..3b32e6b1d9356 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -48,6 +48,11 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
)), \
new /datum/stack_recipe_list("chess pieces", list( \
new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
@@ -779,7 +784,8 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
)
GLOBAL_LIST_INIT(plastic_recipes, list(
new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("thermoplastic tram tile", /obj/item/stack/thermoplastic, 1, 2, time = 4 SECONDS, check_density = FALSE, placement_checks = STACK_CHECK_TRAM_EXCLUSIVE, category = CAT_TILES), \
+ new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
+ new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, check_density = FALSE, category = CAT_FURNITURE), \
new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_solid_ground = TRUE, time = 4 SECONDS, category = CAT_FURNITURE), \
new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, check_density = FALSE, category = CAT_CONTAINERS), \
diff --git a/code/game/objects/items/vending_items.dm b/code/game/objects/items/vending_items.dm
index 0383767ce66e8..7084b313dff59 100644
--- a/code/game/objects/items/vending_items.dm
+++ b/code/game/objects/items/vending_items.dm
@@ -19,8 +19,10 @@
w_class = WEIGHT_CLASS_BULKY
armor_type = /datum/armor/item_vending_refill
- // Built automatically from the corresponding vending machine.
- // If null, considered to be full. Otherwise, is list(/typepath = amount).
+ /**
+ * Built automatically from the corresponding vending machine.
+ * If null, considered to be full. Otherwise, is list(/typepath = amount).
+ */
var/list/products
var/list/product_categories
var/list/contraband
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 059f78b80c90d..f72199217653f 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -554,124 +554,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
/obj/item/ectoplasm/mystic
icon_state = "mysticplasm"
-/obj/item/statuebust
- name = "bust"
- desc = "A priceless ancient marble bust, the kind that belongs in a museum." //or you can hit people with it
- icon = 'icons/obj/art/statue.dmi'
- icon_state = "bust"
- force = 15
- throwforce = 10
- throw_speed = 5
- throw_range = 2
- attack_verb_continuous = list("busts")
- attack_verb_simple = list("bust")
- var/impressiveness = 45
-
-/obj/item/statuebust/Initialize(mapload)
- . = ..()
- AddElement(/datum/element/art, impressiveness)
- AddElement(/datum/element/beauty, 1000)
-
-/obj/item/statuebust/hippocratic
- name = "hippocrates bust"
- desc = "A bust of the famous Greek physician Hippocrates of Kos, often referred to as the father of western medicine."
- icon_state = "hippocratic"
- impressiveness = 50
- // If it hits the prob(reference_chance) chance, this is set to TRUE. Adds medical HUD when wielded, but has a 10% slower attack speed and is too bloody to make an oath with.
- var/reference = FALSE
- // Chance for above.
- var/reference_chance = 1
- // Minimum time inbetween oaths.
- COOLDOWN_DECLARE(oath_cd)
-
-/obj/item/statuebust/hippocratic/evil
- reference_chance = 100
-
-/obj/item/statuebust/hippocratic/Initialize(mapload)
- . = ..()
- if(prob(reference_chance))
- name = "Solemn Vow"
- desc = "Art lovers will cherish the bust of Hippocrates, commemorating a time when medics still thought doing no harm was a good idea."
- attack_speed = CLICK_CD_SLOW
- reference = TRUE
-
-/obj/item/statuebust/hippocratic/examine(mob/user)
- . = ..()
- if(reference)
- . += span_notice("You could activate the bust in-hand to swear or forswear a Hippocratic Oath... but it seems like somebody decided it was more of a Hippocratic Suggestion. This thing is caked with bits of blood and gore.")
- return
- . += span_notice("You can activate the bust in-hand to swear or forswear a Hippocratic Oath! This has no effects except pacifism or bragging rights. Does not remove other sources of pacifism. Do not eat.")
-
-/obj/item/statuebust/hippocratic/equipped(mob/living/carbon/human/user, slot)
- ..()
- if(!(slot & ITEM_SLOT_HANDS))
- return
- var/datum/atom_hud/our_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
- our_hud.show_to(user)
- ADD_TRAIT(user, TRAIT_MEDICAL_HUD, type)
-
-/obj/item/statuebust/hippocratic/dropped(mob/living/carbon/human/user)
- ..()
- if(HAS_TRAIT_NOT_FROM(user, TRAIT_MEDICAL_HUD, type))
- return
- var/datum/atom_hud/our_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
- our_hud.hide_from(user)
- REMOVE_TRAIT(user, TRAIT_MEDICAL_HUD, type)
-
-/obj/item/statuebust/hippocratic/attack_self(mob/user)
- if(!iscarbon(user))
- to_chat(user, span_warning("You remember how the Hippocratic Oath specifies 'my fellow human beings' and realize that it's completely meaningless to you."))
- return
-
- if(reference)
- to_chat(user, span_warning("As you prepare yourself to swear the Oath, you realize that doing so on a blood-caked bust is probably not a good idea."))
- return
-
- if(!COOLDOWN_FINISHED(src, oath_cd))
- to_chat(user, span_warning("You've sworn or forsworn an oath too recently to undo your decisions. The bust looks at you with disgust."))
- return
-
- COOLDOWN_START(src, oath_cd, 5 MINUTES)
-
- if(HAS_TRAIT_FROM(user, TRAIT_PACIFISM, type))
- to_chat(user, span_warning("You've already sworn a vow. You start preparing to rescind it..."))
- if(do_after(user, 5 SECONDS, target = user))
- user.say("Yeah this Hippopotamus thing isn't working out. I quit!", forced = "hippocratic hippocrisy")
- REMOVE_TRAIT(user, TRAIT_PACIFISM, type)
-
- // they can still do it for rp purposes
- if(HAS_TRAIT_NOT_FROM(user, TRAIT_PACIFISM, type))
- to_chat(user, span_warning("You already don't want to harm people, this isn't going to do anything!"))
-
-
- to_chat(user, span_notice("You remind yourself of the Hippocratic Oath's contents and prepare to swear yourself to it..."))
- if(do_after(user, 4 SECONDS, target = user))
- user.say("I swear to fulfill, to the best of my ability and judgment, this covenant:", forced = "hippocratic oath")
- else
- return fuck_it_up(user)
- if(do_after(user, 2 SECONDS, target = user))
- user.say("I will apply, for the benefit of the sick, all measures that are required, avoiding those twin traps of overtreatment and therapeutic nihilism.", forced = "hippocratic oath")
- else
- return fuck_it_up(user)
- if(do_after(user, 3 SECONDS, target = user))
- user.say("I will remember that I remain a member of society, with special obligations to all my fellow human beings, those sound of mind and body as well as the infirm.", forced = "hippocratic oath")
- else
-
- return fuck_it_up(user)
- if(do_after(user, 3 SECONDS, target = user))
- user.say("If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help.", forced = "hippocratic oath")
- else
- return fuck_it_up(user)
-
- to_chat(user, span_notice("Contentment, understanding, and purpose washes over you as you finish the oath. You consider for a second the concept of harm and shudder."))
- ADD_TRAIT(user, TRAIT_PACIFISM, type)
-
-// Bully the guy for fucking up.
-/obj/item/statuebust/hippocratic/proc/fuck_it_up(mob/living/carbon/user)
- to_chat(user, span_warning("You forget what comes next like a dumbass. The Hippocrates bust looks down on you, disappointed."))
- user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2)
- COOLDOWN_RESET(src, oath_cd)
-
/obj/item/tailclub
name = "tail club"
desc = "For the beating to death of lizards with their own tails."
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index f80042f5679a7..50fcae8dec138 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -35,7 +35,7 @@ LINEN BINS
/obj/item/bedsheet/Initialize(mapload)
. = ..()
AddComponent(/datum/component/surgery_initiator)
- AddElement(/datum/element/bed_tuckable, 0, 0, 0)
+ AddElement(/datum/element/bed_tuckable, mapload, 0, 0, 0)
if(bedsheet_type == BEDSHEET_DOUBLE)
stack_amount *= 2
dying_key = DYE_REGISTRY_DOUBLE_BEDSHEET
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index b3d3c7085bd50..d2df088e06f73 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -94,6 +94,11 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
/// Volume of the internal air
var/air_volume = TANK_STANDARD_VOLUME * 3
+ /// How many pixels the closet can shift on the x axis when shaking
+ var/x_shake_pixel_shift = 2
+ /// how many pixels the closet can shift on the y axes when shaking
+ var/y_shake_pixel_shift = 1
+
/datum/armor/structure_closet
melee = 20
bullet = 10
@@ -1031,6 +1036,9 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
user.visible_message(span_warning("[src] begins to shake violently!"), \
span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)"), \
span_hear("You hear banging from [src]."))
+
+ addtimer(CALLBACK(src, PROC_REF(check_if_shake)), 1 SECONDS)
+
if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
return
@@ -1045,6 +1053,23 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
/obj/structure/closet/relay_container_resist_act(mob/living/user, obj/container)
container.container_resist_act()
+/// Check if someone is still resisting inside, and choose to either keep shaking or stop shaking the closet
+/obj/structure/closet/proc/check_if_shake()
+ // Assuming we decide to shake again, how long until we check to shake again
+ var/next_check_time = 1 SECONDS
+
+ // How long we shake between different calls of Shake(), so that it starts shaking and stops, instead of a steady shake
+ var/shake_duration = 0.3 SECONDS
+
+ for(var/mob/living/mob in contents)
+ if(DOING_INTERACTION_WITH_TARGET(mob, src))
+ // Shake and queue another check_if_shake
+ Shake(x_shake_pixel_shift, y_shake_pixel_shift, shake_duration, shake_interval = 0.1 SECONDS)
+ addtimer(CALLBACK(src, PROC_REF(check_if_shake)), next_check_time)
+ return TRUE
+
+ // If we reach here, nobody is resisting, so dont shake
+ return FALSE
/obj/structure/closet/proc/bust_open()
SIGNAL_HANDLER
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index c43a83b085aef..c4f84e9ca3d24 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -18,6 +18,8 @@
drag_slowdown = 0
door_anim_time = 0 // no animation
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
+ x_shake_pixel_shift = 1
+ y_shake_pixel_shift = 2
/// Mobs standing on it are nudged up by this amount.
var/elevation = 14
/// The same, but when the crate is open
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index f35b41c53d2a3..3bb24147f5c49 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -410,11 +410,10 @@
max_integrity = 350
/obj/structure/girder/tram
- name = "tram frame"
+ name = "tram girder"
desc = "Titanium framework to construct tram walls. Can be plated with titanium glass or other wall materials."
icon_state = "tram"
state = GIRDER_TRAM
- density = FALSE
obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN
/obj/structure/girder/tram/corner
diff --git a/code/game/objects/structures/tank_holder.dm b/code/game/objects/structures/tank_holder.dm
index 9b5b33d8417eb..5b7c9d2ed5534 100644
--- a/code/game/objects/structures/tank_holder.dm
+++ b/code/game/objects/structures/tank_holder.dm
@@ -142,3 +142,7 @@
/obj/structure/tank_holder/extinguisher/advanced
icon_state = "holder_foam_extinguisher"
tank = /obj/item/extinguisher/advanced
+
+/obj/structure/tank_holder/extinguisher/anti
+ icon_state = "holder_extinguisher"
+ tank = /obj/item/extinguisher/anti
diff --git a/code/game/sound.dm b/code/game/sound.dm
index e575534bdaeed..17275f5f3a63e 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -424,4 +424,10 @@
'sound/items/reel4.ogg',
'sound/items/reel5.ogg',
)
+ if(SFX_RATTLE)
+ soundin = pick(
+ 'sound/items/rattle1.ogg',
+ 'sound/items/rattle2.ogg',
+ 'sound/items/rattle3.ogg',
+ )
return soundin
diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm
index a970c7a5335ef..877bebffe9509 100644
--- a/code/modules/admin/antag_panel.dm
+++ b/code/modules/admin/antag_panel.dm
@@ -99,6 +99,7 @@ GLOBAL_VAR(antag_prototypes)
out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"] "
out += "Assigned role: [assigned_role.title]. Edit "
out += "Faction and special role: [special_role] "
+ out += "Show Teams
"
var/special_statuses = get_special_statuses()
if(length(special_statuses))
diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm
index 4d74f5425608f..b65f72f8f4d79 100644
--- a/code/modules/admin/fun_balloon.dm
+++ b/code/modules/admin/fun_balloon.dm
@@ -87,14 +87,14 @@
if (!possessable.ckey && possessable.stat == CONSCIOUS) // Only assign ghosts to living, non-occupied mobs!
bodies += possessable
- var/list/candidates = SSpolling.poll_ghost_candidates_for_mobs(
- question = "Would you like to be [group_name]?",
+ var/list/candidates = SSpolling.poll_ghosts_for_targets(
+ question = "Would you like to be [span_notice(group_name)]?",
role = ROLE_SENTIENCE,
check_jobban = ROLE_SENTIENCE,
poll_time = 10 SECONDS,
- mobs = bodies,
+ checked_targets = bodies,
ignore_category = POLL_IGNORE_SHUTTLE_DENIZENS,
- pic_source = src,
+ alert_pic = src,
role_name_text = "sentience fun balloon",
)
diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm
index e98016df74f3d..9d2525ed8fa2d 100644
--- a/code/modules/admin/holder2.dm
+++ b/code/modules/admin/holder2.dm
@@ -232,7 +232,7 @@ GLOBAL_PROTECT(href_token)
return VALID_2FA_CONNECTION
if (!SSdbcore.Connect())
- if (verify_backup_data(client))
+ if (verify_backup_data(client) || (client.ckey in GLOB.protected_admins))
return VALID_2FA_CONNECTION
else
return list(FALSE, null)
diff --git a/code/modules/admin/smites/imaginary_friend_special.dm b/code/modules/admin/smites/imaginary_friend_special.dm
index 5b2bc6ba80547..e670e26fd1fa4 100644
--- a/code/modules/admin/smites/imaginary_friend_special.dm
+++ b/code/modules/admin/smites/imaginary_friend_special.dm
@@ -58,7 +58,6 @@
return FALSE
var/list/volunteers = SSpolling.poll_ghost_candidates(
- question = "Do you want to play as an imaginary friend?",
check_jobban = ROLE_PAI,
poll_time = 10 SECONDS,
ignore_category = POLL_IGNORE_IMAGINARYFRIEND,
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 126d8756762ca..35b1baa063d57 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -680,8 +680,7 @@
names[name] = ruin_landmark
- var/ruinname = input("Select ruin", "Jump to Ruin") as null|anything in sort_list(names)
-
+ var/ruinname = tgui_input_list(usr, "Select ruin", "Jump to Ruin", sort_list(names))
var/obj/effect/landmark/ruin/landmark = names[ruinname]
@@ -715,7 +714,7 @@
themed_names[name] = list(ruin, theme, list(ruin.default_area))
names += sort_list(themed_names)
- var/ruinname = input("Select ruin", "Spawn Ruin") as null|anything in names
+ var/ruinname = tgui_input_list(usr, "Select ruin", "Spawn Ruin", sort_list(names))
var/data = names[ruinname]
if (!data)
return
diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm
index 8b4c7e3c1b823..6fc238931a65e 100644
--- a/code/modules/admin/verbs/ert.dm
+++ b/code/modules/admin/verbs/ert.dm
@@ -121,7 +121,7 @@
var/list/spawnpoints = GLOB.emergencyresponseteamspawn
var/index = 0
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for [ertemplate.polldesc]?", check_jobban = "deathsquad", pic_source = /obj/item/card/id/advanced/centcom/ert, role_name_text = "emergency response team")
+ var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for [span_notice(ertemplate.polldesc)]?", check_jobban = "deathsquad", alert_pic = /obj/item/card/id/advanced/centcom/ert, role_name_text = "emergency response team")
var/teamSpawned = FALSE
// This list will take priority over spawnpoints if not empty
diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm
index a772f69999271..827bbfb16e862 100644
--- a/code/modules/admin/verbs/map_template_loadverb.dm
+++ b/code/modules/admin/verbs/map_template_loadverb.dm
@@ -3,8 +3,7 @@
set name = "Map template - Place"
var/datum/map_template/template
-
- var/map = input(src, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in sort_list(SSmapping.map_templates)
+ var/map = tgui_input_list(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template", sort_list(SSmapping.map_templates))
if(!map)
return
template = SSmapping.map_templates[map]
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index 20a05685bc9ed..fa2a9fa19c628 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -405,7 +405,7 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller)
var/list/candidates = list()
if (prefs["offerghosts"]["value"] == "Yes")
- candidates = SSpolling.poll_ghost_candidates(replacetext(prefs["ghostpoll"]["value"], "%TYPE%", initial(pathToSpawn.name)), check_jobban = ROLE_TRAITOR, pic_source = pathToSpawn, role_name_text = "portal storm")
+ candidates = SSpolling.poll_ghost_candidates(replacetext(prefs["ghostpoll"]["value"], "%TYPE%", initial(pathToSpawn.name)), check_jobban = ROLE_TRAITOR, alert_pic = pathToSpawn, role_name_text = "portal storm")
if (prefs["playersonly"]["value"] == "Yes" && length(candidates) < prefs["minplayers"]["value"])
message_admins("Not enough players signed up to create a portal storm, the minimum was [prefs["minplayers"]["value"]] and the number of signups [length(candidates)]")
@@ -576,7 +576,7 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller)
if(teamsize <= 0)
return FALSE
- candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a Nanotrasen emergency response drone?", check_jobban = ROLE_DRONE, pic_source = /mob/living/basic/drone/classic, role_name_text = "nanotrasen emergency response drone")
+ candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a [span_notice("Nanotrasen emergency response drone")]?", check_jobban = ROLE_DRONE, alert_pic = /mob/living/basic/drone/classic, role_name_text = "nanotrasen emergency response drone")
if(length(candidates) == 0)
return FALSE
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index c679fd45dfa16..89ed48585ed36 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -293,13 +293,12 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a [name]?", check_jobban = "[name]", role = job_rank, poll_time = 5 SECONDS, target_mob = owner.current, pic_source = owner.current, role_name_text = name)
- if(LAZYLEN(candidates))
- var/mob/dead/observer/C = pick(candidates)
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = job_rank, role = job_rank, poll_time = 5 SECONDS, checked_target = owner.current, alert_pic = owner.current, role_name_text = name)
+ if(chosen_one)
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
- message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner)]) to replace a jobbanned player.")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(owner)]) to replace a jobbanned player.")
owner.current.ghostize(FALSE)
- owner.current.key = C.key
+ owner.current.key = chosen_one.key
/**
* Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion.
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index 9ef40a9cebfd9..19ff29651efae 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -55,16 +55,15 @@
/obj/item/antag_spawner/contract/proc/poll_for_student(mob/living/carbon/human/teacher, apprentice_school)
balloon_alert(teacher, "contacting apprentice...")
polling = TRUE
- var/list/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a wizard's [apprentice_school] apprentice?", check_jobban = ROLE_WIZARD, role = ROLE_WIZARD, poll_time = 15 SECONDS, target_mob = src, pic_source = teacher, role_name_text = "wizard apprentice")
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger("[teacher]'s")] [span_notice("[apprentice_school] apprentice")]?", check_jobban = ROLE_WIZARD, role = ROLE_WIZARD, poll_time = 15 SECONDS, checked_target = src, alert_pic = /obj/item/clothing/head/wizard/red, jump_target = src, role_name_text = "wizard apprentice", chat_text_border_icon = /obj/item/clothing/head/wizard/red)
polling = FALSE
- if(!LAZYLEN(candidates))
+ if(isnull(chosen_one))
to_chat(teacher, span_warning("Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later."))
return
if(QDELETED(src) || used)
return
used = TRUE
- var/mob/dead/observer/student = pick(candidates)
- spawn_antag(student.client, get_turf(src), apprentice_school, teacher.mind)
+ spawn_antag(chosen_one.client, get_turf(src), apprentice_school, teacher.mind)
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind, datum/mind/user)
new /obj/effect/particle_effect/fluid/smoke(T)
@@ -134,13 +133,12 @@
return
to_chat(user, span_notice("You activate [src] and wait for confirmation."))
- var/list/nuke_candidates = SSpolling.poll_ghost_candidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", check_jobban = ROLE_OPERATIVE, role = ROLE_OPERATIVE, poll_time = 15 SECONDS, ignore_category = POLL_IGNORE_SYNDICATE, pic_source = src, role_name_text = "syndicate [borg_to_spawn ? "[borg_to_spawn] cyborg":"operative"]")
- if(LAZYLEN(nuke_candidates))
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_OPERATIVE, role = ROLE_OPERATIVE, poll_time = 15 SECONDS, ignore_category = POLL_IGNORE_SYNDICATE, alert_pic = src, role_name_text = "syndicate [borg_to_spawn ? "[borg_to_spawn] cyborg":"operative"]", amount_to_pick = 1)
+ if(chosen_one)
if(QDELETED(src) || !check_usability(user))
return
used = TRUE
- var/mob/dead/observer/G = pick(nuke_candidates)
- spawn_antag(G.client, get_turf(src), "nukeop", user.mind)
+ spawn_antag(chosen_one.client, get_turf(src), "nukeop", user.mind)
do_sparks(4, TRUE, src)
qdel(src)
else
@@ -252,14 +250,13 @@
return
if(used)
return
- var/list/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a [initial(demon_type.name)]?", check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, poll_time = 5 SECONDS, target_mob = src, pic_source = src, role_name_text = initial(demon_type.name))
- if(LAZYLEN(candidates))
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, poll_time = 5 SECONDS, checked_target = src, alert_pic = demon_type, jump_target = src, role_name_text = initial(demon_type.name))
+ if(chosen_one)
if(used || QDELETED(src))
return
used = TRUE
- var/mob/dead/observer/summoned = pick(candidates)
- user.log_message("has summoned forth the [initial(demon_type.name)] (played by [key_name(summoned)]) using a [name].", LOG_GAME) // has to be here before we create antag otherwise we can't get the ckey of the demon
- spawn_antag(summoned.client, get_turf(src), initial(demon_type.name), user.mind)
+ user.log_message("has summoned forth the [initial(demon_type.name)] (played by [key_name(chosen_one)]) using a [name].", LOG_GAME) // has to be here before we create antag otherwise we can't get the ckey of the demon
+ spawn_antag(chosen_one.client, get_turf(src), initial(demon_type.name), user.mind)
to_chat(user, shatter_msg)
to_chat(user, veil_msg)
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, TRUE)
@@ -332,23 +329,22 @@
return
to_chat(user, span_notice("You activate [src] and wait for confirmation."))
- var/list/baddie_candidates = SSpolling.poll_ghost_candidates(
- "Do you want to play as a [role_to_play]?",
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(
check_jobban = poll_role_check,
role = poll_role_check,
poll_time = 10 SECONDS,
ignore_category = poll_ignore_category,
- pic_source = src,
+ alert_pic = src,
role_name_text = role_to_play,
+ amount_to_pick = 1
)
- if(!LAZYLEN(baddie_candidates))
+ if(isnull(chosen_one))
to_chat(user, span_warning(fail_text))
return
if(QDELETED(src) || !check_usability(user))
return
used = TRUE
- var/mob/dead/observer/ghostie = pick(baddie_candidates)
- spawn_antag(ghostie.client, get_turf(src), user)
+ spawn_antag(chosen_one.client, get_turf(src), user)
do_sparks(4, TRUE, src)
qdel(src)
diff --git a/code/modules/antagonists/blob/powers.dm b/code/modules/antagonists/blob/powers.dm
index b35308d092f9d..2f3b51741f9b6 100644
--- a/code/modules/antagonists/blob/powers.dm
+++ b/code/modules/antagonists/blob/powers.dm
@@ -193,14 +193,20 @@
/mob/camera/blob/proc/pick_blobbernaut_candidate(obj/structure/blob/special/factory/factory)
if(isnull(factory))
return
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(on_poll_concluded), factory)
- factory.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_BLOB, \
- job_bans = ROLE_BLOB, \
- to_call = to_call, \
- title = "Blobbernaut", \
+ var/icon/blobbernaut_icon = icon(icon, "blobbernaut")
+ blobbernaut_icon.Blend(blobstrain.color, ICON_MULTIPLY)
+ var/image/blobbernaut_image = image(blobbernaut_icon)
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ check_jobban = ROLE_BLOB,
+ poll_time = 20 SECONDS,
+ checked_target = factory,
+ ignore_category = POLL_IGNORE_BLOB,
+ alert_pic = blobbernaut_image,
+ jump_target = factory,
+ role_name_text = "blobbernaut",
+ chat_text_border_icon = blobbernaut_image,
)
+ on_poll_concluded(factory, chosen_one)
/// Called when the ghost poll concludes
/mob/camera/blob/proc/on_poll_concluded(obj/structure/blob/special/factory/factory, mob/dead/observer/ghost)
diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm
index 9404157ad24ab..49d0ab4ad2300 100644
--- a/code/modules/antagonists/brother/brother.dm
+++ b/code/modules/antagonists/brother/brother.dm
@@ -77,22 +77,23 @@
flashed.balloon_alert(source, "[flashed.p_they()] resist!")
return
- flashed.mind.add_antag_datum(/datum/antagonist/brother, team)
+ if (!team.add_brother(flashed, key_name(source))) // Shouldn't happen given the former, more specific checks but just in case
+ flashed.balloon_alert(source, "failed!")
+ return
+
source.log_message("converted [key_name(flashed)] to blood brother", LOG_ATTACK)
flashed.log_message("was converted by [key_name(source)] to blood brother", LOG_ATTACK)
- log_game("[key_name(flashed)] converted [key_name(source)] to blood brother", list(
- "flashed" = flashed,
- "victim" = source,
+ log_game("[key_name(flashed)] was made into a blood brother by [key_name(source)]", list(
+ "converted" = flashed,
+ "converted by" = source,
))
-
- flashed.balloon_alert(source, "converted")
- to_chat(source, span_notice("[span_bold("[flashed]")] has been converted to aide you as your Brother!"))
flash.burn_out()
flashed.mind.add_memory( \
/datum/memory/recruited_by_blood_brother, \
protagonist = flashed, \
antagonist = owner.current, \
)
+ flashed.balloon_alert(source, "converted")
UnregisterSignal(source, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON)
source.RemoveComponentSource(REF(src), /datum/component/can_flash_from_behind)
@@ -171,6 +172,34 @@
if (prob(10))
brothers_left += 1
+/datum/team/brother_team/add_member(datum/mind/new_member)
+ . = ..()
+ if (!new_member.has_antag_datum(/datum/antagonist/brother))
+ add_brother(new_member.current)
+
+/datum/team/brother_team/remove_member(datum/mind/member)
+ if (!(member in members))
+ return
+ . = ..()
+ member.remove_antag_datum(/datum/antagonist/brother)
+ if (isnull(member.current))
+ return
+ for (var/datum/mind/brother_mind as anything in members)
+ to_chat(brother_mind, span_warning("[span_bold("[member.current.real_name]")] is no longer your brother!"))
+ update_name()
+
+/// Adds a new brother to the team
+/datum/team/brother_team/proc/add_brother(mob/living/new_brother, source)
+ if (isnull(new_brother) || isnull(new_brother.mind) || !GET_CLIENT(new_brother) || new_brother.mind.has_antag_datum(/datum/antagonist/brother))
+ return FALSE
+
+ for (var/datum/mind/brother_mind as anything in members)
+ if (brother_mind == new_brother.mind)
+ continue
+ to_chat(brother_mind, span_notice("[span_bold("[new_brother.real_name]")] has been converted to aid you as your brother!"))
+ new_brother.mind.add_antag_datum(/datum/antagonist/brother, src)
+ return TRUE
+
/datum/team/brother_team/proc/update_name()
var/list/last_names = list()
for(var/datum/mind/team_minds as anything in members)
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index bee8eec306f7c..01aac3e869161 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -147,17 +147,18 @@
asked_cultists += team_member.current
var/list/yes_voters = SSpolling.poll_candidates(
- question = "[nominee] seeks to lead your cult, do you support [nominee.p_them()]?",
+ question = "[span_notice(nominee)] seeks to lead your cult, do you support [nominee.p_them()]?",
poll_time = 30 SECONDS,
group = asked_cultists,
- pic_source = nominee,
- role_name_text = "cult master",
+ alert_pic = nominee,
+ role_name_text = "cult master nomination",
custom_response_messages = list(
POLL_RESPONSE_SIGNUP = "You have pledged your allegience to [nominee].",
POLL_RESPONSE_ALREADY_SIGNED = "You have already pledged your allegience!",
POLL_RESPONSE_NOT_SIGNED = "You aren't nominated for this.",
POLL_RESPONSE_TOO_LATE_TO_UNREGISTER = "It's too late to unregister yourself, voting has already begun!",
POLL_RESPONSE_UNREGISTERED = "You have been removed your pledge to [nominee].",
+ chat_text_border_icon = mutable_appearance('icons/effects/effects.dmi', "cult_master_logo")
)
)
if(QDELETED(nominee) || nominee.incapacitated())
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 8d7d66979f42b..8e5e7099be49a 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -737,13 +737,12 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
if(!mob_to_revive.client || mob_to_revive.client.is_afk())
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a [mob_to_revive.real_name], an inactive blood cultist?", check_jobban = ROLE_CULTIST, role = ROLE_CULTIST, poll_time = 5 SECONDS, target_mob = mob_to_revive, pic_source = mob_to_revive)
- if(LAZYLEN(candidates))
- var/mob/dead/observer/C = pick(candidates)
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger(mob_to_revive.real_name)], an [span_notice("inactive blood cultist")]?", check_jobban = ROLE_CULTIST, role = ROLE_CULTIST, poll_time = 5 SECONDS, checked_target = mob_to_revive, alert_pic = mob_to_revive, role_name_text = "inactive cultist")
+ if(chosen_one)
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
- message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
mob_to_revive.ghostize(FALSE)
- mob_to_revive.key = C.key
+ mob_to_revive.key = chosen_one.key
else
fail_invoke()
return
diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm
index f2cf7b0004771..bb59076a6bb06 100644
--- a/code/modules/antagonists/heretic/heretic_knowledge.dm
+++ b/code/modules/antagonists/heretic/heretic_knowledge.dm
@@ -537,23 +537,22 @@
animate(summoned, 10 SECONDS, alpha = 155)
message_admins("A [summoned.name] is being summoned by [ADMIN_LOOKUPFLW(user)] in [ADMIN_COORDJMP(summoned)].")
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a [summoned.name]?", check_jobban = ROLE_HERETIC, poll_time = 10 SECONDS, target_mob = summoned, ignore_category = poll_ignore_define, pic_source = summoned, role_name_text = summoned.name)
- if(!LAZYLEN(candidates))
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_HERETIC, poll_time = 10 SECONDS, checked_target = summoned, ignore_category = poll_ignore_define, alert_pic = summoned, role_name_text = summoned.name)
+ if(isnull(chosen_one))
loc.balloon_alert(user, "ritual failed, no ghosts!")
animate(summoned, 0.5 SECONDS, alpha = 0)
QDEL_IN(summoned, 0.6 SECONDS)
return FALSE
- var/mob/dead/observer/picked_candidate = pick(candidates)
// Ok let's make them an interactable mob now, since we got a ghost
summoned.alpha = 255
REMOVE_TRAIT(summoned, TRAIT_NO_TRANSFORM, REF(src))
summoned.move_resist = initial(summoned.move_resist)
summoned.ghostize(FALSE)
- summoned.key = picked_candidate.key
+ summoned.key = chosen_one.key
- user.log_message("created a [summoned.name], controlled by [key_name(picked_candidate)].", LOG_GAME)
+ user.log_message("created a [summoned.name], controlled by [key_name(chosen_one)].", LOG_GAME)
message_admins("[ADMIN_LOOKUPFLW(user)] created a [summoned.name], [ADMIN_LOOKUPFLW(summoned)].")
var/datum/antagonist/heretic_monster/heretic_monster = summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
diff --git a/code/modules/antagonists/heretic/items/eldritch_painting.dm b/code/modules/antagonists/heretic/items/eldritch_painting.dm
index 5aa63407dc6ef..5302fc1c9c148 100644
--- a/code/modules/antagonists/heretic/items/eldritch_painting.dm
+++ b/code/modules/antagonists/heretic/items/eldritch_painting.dm
@@ -92,7 +92,7 @@
if(!IS_HERETIC(examiner))
to_chat(examiner, span_hypnophrase("Respite, for now...."))
examiner.mob_mood.mood_events.Remove("eldritch_weeping")
- examiner.add_mood_event("weeping_withdrawl", /datum/mood_event/eldritch_painting/weeping_withdrawl)
+ examiner.add_mood_event("weeping_withdrawal", /datum/mood_event/eldritch_painting/weeping_withdrawal)
return
to_chat(examiner, span_notice("Oh, what arts! Just gazing upon it clears your mind."))
diff --git a/code/modules/antagonists/heretic/knowledge/ash_lore.dm b/code/modules/antagonists/heretic/knowledge/ash_lore.dm
index 3d4a9b3552db0..fe10f7949eae5 100644
--- a/code/modules/antagonists/heretic/knowledge/ash_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/ash_lore.dm
@@ -42,7 +42,7 @@
/datum/heretic_knowledge/ashen_grasp
name = "Grasp of Ash"
- desc = "Your Mansus Grasp will burn the eyes of the victim, causing damage and blindness."
+ desc = "Your Mansus Grasp will burn the eyes of the victim, damaging them and blurring their vision."
gain_text = "The Nightwatcher was the first of them, his treason started it all. \
Their lantern, expired to ash - their watch, absent."
next_knowledge = list(/datum/heretic_knowledge/spell/ash_passage)
@@ -70,7 +70,7 @@
/datum/heretic_knowledge/spell/ash_passage
name = "Ashen Passage"
- desc = "Grants you Ashen Passage, a silent but short range jaunt."
+ desc = "Grants you Ashen Passage, a spell that lets you phase out of reality and traverse a short distance, passing though any walls."
gain_text = "He knew how to walk between the planes."
next_knowledge = list(
/datum/heretic_knowledge/mark/ash_mark,
@@ -181,6 +181,7 @@
When completed, you become a harbinger of flames, gaining two abilites. \
Cascade, which causes a massive, growing ring of fire around you, \
and Oath of Flame, causing you to passively create a ring of flames as you walk. \
+ Some ashen spells you already knew will be empowered as well. \
You will also become immune to flames, space, and similar environmental hazards."
gain_text = "The Watch is dead, the Nightwatcher burned with it. Yet his fire burns evermore, \
for the Nightwatcher brought forth the rite to mankind! His gaze continues, as now I am one with the flames, \
diff --git a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm
index 1a16f2e9f9321..09efb5c2eb8f4 100644
--- a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm
@@ -42,7 +42,8 @@
/datum/heretic_knowledge/cosmic_grasp
name = "Grasp of Cosmos"
- desc = "Your Mansus Grasp will give people a star mark (cosmic ring) and create a cosmic field where you stand."
+ desc = "Your Mansus Grasp will give people a star mark (cosmic ring) and create a cosmic field where you stand. \
+ People with a star mark can not pass cosmic fields."
gain_text = "Some stars dimmed, others' magnitude increased. \
With newfound strength I could channel the nebula's power into myself."
next_knowledge = list(/datum/heretic_knowledge/spell/cosmic_runes)
@@ -82,7 +83,8 @@
/datum/heretic_knowledge/mark/cosmic_mark
name = "Mark of Cosmos"
desc = "Your Mansus Grasp now applies the Mark of Cosmos. The mark is triggered from an attack with your Cosmic Blade. \
- When triggered, the victim is returned to the location where the mark was originally applied to them. \
+ When triggered, the victim is returned to the location where the mark was originally applied to them, \
+ leaving a cosmic field in their place. \
They will then be paralyzed for 2 seconds."
gain_text = "The Beast now whispered to me occasionally, only small tidbits of their circumstances. \
I can help them, I have to help them."
@@ -98,8 +100,7 @@
name = "Star Touch"
desc = "Grants you Star Touch, a spell which places a star mark upon your target \
and creates a cosmic field at your feet and to the turfs next to you. Targets which already have a star mark \
- will be forced to sleep for 4 seconds. When the victim is hit it also creates a beam that \
- deals a bit of fire damage and damages the cells. \
+ will be forced to sleep for 4 seconds. When the victim is hit it also creates a beam that burns them. \
The beam lasts a minute, until the beam is obstructed or until a new target has been found."
gain_text = "After waking in a cold sweat I felt a palm on my scalp, a sigil burned onto me. \
My veins now emitted a strange purple glow, the Beast knows I will surpass its expectations."
@@ -110,7 +111,7 @@
/datum/heretic_knowledge/spell/star_blast
name = "Star Blast"
- desc = "Fires a projectile that moves very slowly and creates cosmic fields on impact. \
+ desc = "Fires a projectile that moves very slowly, raising a short-lived wall of cosmic fields where it goes. \
Anyone hit by the projectile will receive burn damage, a knockdown, and give people in a three tile range a star mark."
gain_text = "The Beast was behind me now at all times, with each sacrifice words of affirmation coursed through me."
next_knowledge = list(
@@ -243,7 +244,8 @@
You can also give it commands through speech. \
The Star Gazer is a strong ally who can even break down reinforced walls. \
The Star Gazer has an aura that will heal you and damage opponents. \
- Star Touch can now teleport you to the Star Gazer when activated in your hand."
+ Star Touch can now teleport you to the Star Gazer when activated in your hand. \
+ Your cosmic expansion spell and your blades also become greatly empowered."
gain_text = "The Beast held out its hand, I grabbed hold and they pulled me to them. Their body was towering, but it seemed so small and feeble after all their tales compiled in my head. \
I clung on to them, they would protect me, and I would protect it. \
I closed my eyes with my head laid against their form. I was safe. \
diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
index f41512d76c069..8898ba7f59c66 100644
--- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
@@ -122,6 +122,7 @@
/datum/heretic_knowledge/limited_amount/flesh_ghoul
name = "Imperfect Ritual"
desc = "Allows you to transmute a corpse and a poppy to create a Voiceless Dead. \
+ The corpse does not need to have a soul. \
Voiceless Dead are mute ghouls and only have 50 health, but can use Bloody Blades effectively. \
You can only create two at a time."
gain_text = "I found notes of a dark ritual, unfinished... yet still, I pushed forward."
@@ -167,15 +168,13 @@
if(!soon_to_be_ghoul.mind || !soon_to_be_ghoul.client)
message_admins("[ADMIN_LOOKUPFLW(user)] is creating a voiceless dead of a body with no player.")
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a [soon_to_be_ghoul.real_name], a voiceless dead?", check_jobban = ROLE_HERETIC, role = ROLE_HERETIC, poll_time = 5 SECONDS, target_mob = soon_to_be_ghoul, pic_source = soon_to_be_ghoul, role_name_text = "voiceless dead")
- if(!LAZYLEN(candidates))
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger(soon_to_be_ghoul.real_name)], a [span_notice("voiceless dead")]?", check_jobban = ROLE_HERETIC, role = ROLE_HERETIC, poll_time = 5 SECONDS, checked_target = soon_to_be_ghoul, alert_pic = mutable_appearance('icons/mob/human/human.dmi', "husk"), jump_target = soon_to_be_ghoul, role_name_text = "voiceless dead")
+ if(isnull(chosen_one))
loc.balloon_alert(user, "ritual failed, no ghosts!")
return FALSE
-
- var/mob/dead/observer/chosen_candidate = pick(candidates)
- message_admins("[key_name_admin(chosen_candidate)] has taken control of ([key_name_admin(soon_to_be_ghoul)]) to replace an AFK player.")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(soon_to_be_ghoul)]) to replace an AFK player.")
soon_to_be_ghoul.ghostize(FALSE)
- soon_to_be_ghoul.key = chosen_candidate.key
+ soon_to_be_ghoul.key = chosen_one.key
selected_atoms -= soon_to_be_ghoul
make_ghoul(user, soon_to_be_ghoul)
diff --git a/code/modules/antagonists/heretic/knowledge/lock_lore.dm b/code/modules/antagonists/heretic/knowledge/lock_lore.dm
index 9f80f47b0ae48..0727b86bb668e 100644
--- a/code/modules/antagonists/heretic/knowledge/lock_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/lock_lore.dm
@@ -92,9 +92,12 @@
/datum/heretic_knowledge/key_ring
name = "Key Keeper’s Burden"
desc = "Allows you to transmute a wallet, an iron rod, and an ID card to create an Eldritch Card. \
- It functions the same as an ID Card, but attacking it with an ID card fuses it and gains its access. \
- You can use it in-hand to change its form to a card you fused. \
- Does not preserve the card used in the ritual."
+ Hit a pair of airlocks with it to create a pair of portals, which will teleport you between them, but teleport non-heretics randomly. \
+ You can ctrl-click the card to invert this behavior for created portals. \
+ Each card may only sustain a single pair of portals at the same time. \
+ It also functions and appears the same as a regular ID Card. \
+ Attacking it with a normal ID card consumes it and gains its access, and you can use it in-hand to change its appearance to a card you fused. \
+ Does not preserve the card originally used in the ritual."
gain_text = "The Keeper sneered. \"These plastic rectangles are a mockery of keys, and I curse every door that desires them.\""
required_atoms = list(
/obj/item/storage/wallet = 1,
@@ -186,7 +189,8 @@
desc = "The ascension ritual of the Path of Knock. \
Bring 3 corpses without organs in their torso to a transmutation rune to complete the ritual. \
When completed, you gain the ability to transform into empowered eldritch creatures \
- and in addition, create a tear to the Labyrinth's heart; \
+ and your keyblades will become even deadlier. \
+ In addition, you will create a tear to the Labyrinth's heart; \
a tear in reality located at the site of this ritual. \
Eldritch creatures will endlessly pour from this rift \
who are bound to obey your instructions."
diff --git a/code/modules/antagonists/heretic/knowledge/moon_lore.dm b/code/modules/antagonists/heretic/knowledge/moon_lore.dm
index d7d1bd3bf22a7..723599ad262f5 100644
--- a/code/modules/antagonists/heretic/knowledge/moon_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/moon_lore.dm
@@ -45,8 +45,8 @@
/datum/heretic_knowledge/moon_grasp
name = "Grasp of Lunacy"
- desc = "Your Mansus Grasp will cause them to hallucinate everyone as lunar mass, \
- and hides your identity for a short dur ation."
+ desc = "Your Mansus Grasp will cause your victims to hallucinate everyone as lunar mass, \
+ and hides your identity for a short duration."
gain_text = "The troupe on the side of the moon showed me truth, and I took it."
next_knowledge = list(/datum/heretic_knowledge/spell/moon_smile)
cost = 1
@@ -85,9 +85,8 @@
/datum/heretic_knowledge/mark/moon_mark
name = "Mark of Moon"
- desc = "Your Mansus Grasp now applies the Mark of Moon. The mark is triggered from an attack with your Moon Blade. \
- When triggered, the victim is confused, and when the mark is applied they are pacified \
- until attacked."
+ desc = "Your Mansus Grasp now applies the Mark of Moon, pacifying the victim until attacked. \
+ The mark can also be triggered from an attack with your Moon Blade, leaving the victim confused."
gain_text = "The troupe on the moon would dance all day long \
and in that dance the moon would smile upon us \
but when the night came its smile would dull forced to gaze on the earth."
@@ -112,9 +111,9 @@
/datum/heretic_knowledge/moon_amulette
name = "Moonlight Amulette"
- desc = "Allows you to transmute 2 sheets of glass, a heart and a tie \
- if the item is used on someone with low sanity they go berserk attacking everyone \
- , if their sanity isnt low enough it decreases their mood."
+ desc = "Allows you to transmute 2 sheets of glass, a heart and a tie to create a Moonlight Amulette. \
+ If the item is used on someone with low sanity they go berserk attacking everyone, \
+ if their sanity isn't low enough it decreases their mood."
gain_text = "At the head of the parade he stood, the moon condensed into one mass, a reflection of the soul."
next_knowledge = list(
/datum/heretic_knowledge/blade_upgrade/moon,
@@ -153,9 +152,9 @@
/datum/heretic_knowledge/spell/moon_ringleader
name = "Ringleaders Rise"
- desc = "Grants you Ringleaders Rise, an aoe spell that deals more brain damage the lower the sanity of everyone in the AoE,\
- causes hallucinations with those who have less sanity getting more. \
- If their sanity is low enough turns them insane, the spell then halves their sanity."
+ desc = "Grants you Ringleaders Rise, an AoE spell that deals more brain damage the lower the sanity of everyone in the AoE \
+ and causes hallucinations, with those who have less sanity getting more. \
+ If their sanity is low enough this turns them insane, the spell then halves their sanity."
gain_text = "I grabbed his hand and we rose, those who saw the truth rose with us. \
The ringleader pointed up and the dim light of truth illuminated us further."
next_knowledge = list(
@@ -170,8 +169,8 @@
name = "The Last Act"
desc = "The ascension ritual of the Path of Moon. \
Bring 3 corpses with more than 50 brain damage to a transmutation rune to complete the ritual. \
- When completed, you become a harbinger of madness gaining and aura of passive sanity decrease \
- , confusion increase and if their sanity is low enough brain damage and blindness. \
+ When completed, you become a harbinger of madness gaining and aura of passive sanity decrease, \
+ confusion increase and, if their sanity is low enough, brain damage and blindness. \
1/5th of the crew will turn into acolytes and follow your command, they will all recieve moonlight amulettes."
gain_text = "We dived down towards the crowd, his soul splitting off in search of greater venture \
for where the Ringleader had started the parade, I shall continue it unto the suns demise \
diff --git a/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm b/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm
index 4ce8f9de9c936..a4810c706c118 100644
--- a/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm
@@ -21,7 +21,7 @@
name = "Curse of Paralysis"
desc = "Allows you to transmute a hatchet and both a left and right leg to cast a curse of immobility on a crew member. \
While cursed, the victim will be unable to walk. You can additionally supply an item that a victim has touched \
- or is covered in the victim's blood to empower the curse."
+ or is covered in the victim's blood to make the curse last longer."
gain_text = "The flesh of humanity is weak. Make them bleed. Show them their fragility."
next_knowledge = list(
/datum/heretic_knowledge/mad_mask,
@@ -58,8 +58,8 @@
/datum/heretic_knowledge/summon/ashy
name = "Ashen Ritual"
- desc = "Allows you to transmute a head, a pile of ash, and a book to create an Ash Man. \
- Ash Men have a short range jaunt and the ability to cause bleeding in foes at range. \
+ desc = "Allows you to transmute a head, a pile of ash, and a book to create an Ash Spirit. \
+ Ash Spirits have a short range jaunt and the ability to cause bleeding in foes at range. \
They also have the ability to create a ring of fire around themselves for a length of time."
gain_text = "I combined my principle of hunger with my desire for destruction. The Marshal knew my name, and the Nightwatcher gazed on."
next_knowledge = list(
diff --git a/code/modules/antagonists/heretic/knowledge/side_cosmos_ash.dm b/code/modules/antagonists/heretic/knowledge/side_cosmos_ash.dm
index 470d98e178b7e..14a003ce11c0b 100644
--- a/code/modules/antagonists/heretic/knowledge/side_cosmos_ash.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_cosmos_ash.dm
@@ -36,8 +36,9 @@
/datum/heretic_knowledge/eldritch_coin
name = "Eldritch Coin"
desc = "Allows you to transmute a sheet of plasma and a diamond to create an Eldritch Coin. \
- The coin will open or close nearby doors when landing on heads and bolt or unbolt nearby doors \
- when landing on tails. If the coin gets inserted into an airlock it emags the door destroying the coin."
+ The coin will open or close nearby doors when landing on heads and toggle their bolts \
+ when landing on tails. If you insert the coin into an airlock, it will be consumed \
+ to fry its electronics, opening the airlock permanently unless bolted. "
gain_text = "The Mansus is a place of all sorts of sins. But greed held a special role."
next_knowledge = list(
/datum/heretic_knowledge/spell/cosmic_expansion,
diff --git a/code/modules/antagonists/heretic/knowledge/side_lock_flesh.dm b/code/modules/antagonists/heretic/knowledge/side_lock_flesh.dm
index e2825c6db2869..74013f2b0bd1d 100644
--- a/code/modules/antagonists/heretic/knowledge/side_lock_flesh.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_lock_flesh.dm
@@ -2,7 +2,8 @@
/datum/heretic_knowledge/spell/opening_blast
name = "Wave Of Desperation"
desc = "Grants you Wave Of Desparation, a spell which can only be cast while restrained. \
- It removes your restraints, repels and knocks down adjacent people, and applies the Mansus Grasp to everything nearby."
+ It removes your restraints, repels and knocks down adjacent people, and applies the Mansus Grasp to everything nearby. \
+ However, you will fall unconscious a short time after casting this spell."
gain_text = "My shackles undone in dark fury, their feeble bindings crumble before my power."
next_knowledge = list(
/datum/heretic_knowledge/summon/raw_prophet,
diff --git a/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm b/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm
index 737e0f08f40a1..f1dd564310be5 100644
--- a/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm
@@ -16,10 +16,10 @@
/datum/heretic_knowledge/unfathomable_curio
name = "Unfathomable Curio"
- desc = "Allows you to transmute 3 rods, a brain and a belt into an Unfathomable Curio\
- , a belt that can hold blades and items for rituals. Whilst worn will also \
+ desc = "Allows you to transmute 3 rods, lungs and any belt into an Unfathomable Curio\
+ , a belt that can hold blades and items for rituals. Whilst worn it will also \
veil you, allowing you to take 5 hits without suffering damage, this veil will recharge very slowly \
- outside of combat. When examined the examiner will suffer brain damage and blindness."
+ outside of combat."
gain_text = "The mansus holds many a curio, some are not meant for the mortal eye."
next_knowledge = list(
/datum/heretic_knowledge/spell/burglar_finesse,
@@ -38,12 +38,12 @@
name = "Unsealed Arts"
desc = "Allows you to transmute a canvas and an additional item to create a piece of art, these paintings \
have different effects depending on the additional item added. Possible paintings: \
- The sister and He Who Wept: Eyes. When a non-heretic looks at the painting they will begin to hallucinate everyone as heretics. \
- The First Desire: Any bodypart. Increases the hunger of non-heretics, when examined drops an organ or body part at your feet. \
- Great chaparral over rolling hills: Any grown food. Spreads kudzu when placed, when examined grants a flower. \
- Lady out of gates: Gloves. Causes non-heretics to scratch themselves, when examined removes all your mutations. \
- Climb over the rusted mountain: Trash. Causes non-heretics to rust the floor they walk on. \
- These effects are mitigated for a few minutes when a non-heretic suffering an effect examines the painting that caused the effect."
+ The sister and He Who Wept: Eyes. Clears your own mind, but curses non-heretics with hallucinations. \
+ The First Desire: Any bodypart. Supplies you with random organs, but curses non-heretics with a hunger for flesh. \
+ Great chaparral over rolling hills: Any grown food. Spreads kudzu when placed and examined by non-heretics. Also supplies you with poppies and harebells. \
+ Lady out of gates: Gloves. Clears your mutations, but mutates non-heretics and curses them with scratching. \
+ Climb over the rusted mountain: Trash. Curses non-heretics to rust the floor they walk on. \
+ Non-heretics can counter most of these effects by examining one of these paintings."
gain_text = "A wind of inspiration blows through me, past the walls and past the gate inspirations lie, yet to be depicted. \
They yearn for mortal eyes again, and I shall grant that wish."
next_knowledge = list(
diff --git a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm
index 2dbb44ea4eb7e..3d326b4a9af45 100644
--- a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm
@@ -44,7 +44,7 @@
name = "Curse of Corrosion"
desc = "Allows you to transmute wirecutters, a pool of vomit, and a heart to cast a curse of sickness on a crew member. \
While cursed, the victim will repeatedly vomit while their organs will take constant damage. You can additionally supply an item \
- that a victim has touched or is covered in the victim's blood to empower the curse."
+ that a victim has touched or is covered in the victim's blood to make the curse last longer."
gain_text = "The body of humanity is temporary. Their weaknesses cannot be stopped, like iron falling to rust. Show them all."
next_knowledge = list(
/datum/heretic_knowledge/spell/area_conversion,
diff --git a/code/modules/antagonists/heretic/knowledge/side_void_blade.dm b/code/modules/antagonists/heretic/knowledge/side_void_blade.dm
index 643fd434af7b5..e044eee8619ef 100644
--- a/code/modules/antagonists/heretic/knowledge/side_void_blade.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_void_blade.dm
@@ -144,7 +144,8 @@
name = "Maid in the Mirror"
desc = "Allows you to transmute five sheets of titanium, a flash, a suit of armor, and a pair of lungs \
to create a Maid in the Mirror. Maid in the Mirrors are decent combatants that can become incorporeal by \
- phasing in and out of the mirror realm, serving as powerful scouts and ambushers."
+ phasing in and out of the mirror realm, serving as powerful scouts and ambushers. \
+ However, they are weak to mortal gaze and take damage by being examined."
gain_text = "Within each reflection, lies a gateway into an unimaginable world of colors never seen and \
people never met. The ascent is glass, and the walls are knives. Each step is blood, if you do not have a guide."
next_knowledge = list(
diff --git a/code/modules/antagonists/heretic/magic/apetravulnera.dm b/code/modules/antagonists/heretic/magic/apetravulnera.dm
index 801104dddf9fc..e80d08911848c 100644
--- a/code/modules/antagonists/heretic/magic/apetravulnera.dm
+++ b/code/modules/antagonists/heretic/magic/apetravulnera.dm
@@ -5,7 +5,7 @@
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
- button_icon_state = "cleave"
+ button_icon_state = "apetra_vulnera"
school = SCHOOL_FORBIDDEN
cooldown_time = 45 SECONDS
@@ -23,7 +23,7 @@
/datum/action/cooldown/spell/pointed/apetra_vulnera/cast(mob/living/carbon/human/cast_on)
. = ..()
-
+
if(IS_HERETIC_OR_MONSTER(cast_on))
return FALSE
@@ -44,7 +44,7 @@
a_limb_got_damaged = TRUE
var/datum/wound/slash/crit_wound = new wound_type()
crit_wound.apply_wound(bodypart)
-
+
if(!a_limb_got_damaged)
var/datum/wound/slash/crit_wound = new wound_type()
crit_wound.apply_wound(pick(cast_on.bodyparts))
@@ -53,7 +53,7 @@
span_danger("[cast_on]'s scratches and bruises are torn open by an unholy force!"),
span_danger("Your scratches and bruises are torn open by some horrible unholy force!")
)
-
+
new /obj/effect/temp_visual/cleave(get_turf(cast_on))
return TRUE
diff --git a/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm b/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm
index 18e8d26fecc60..e792dc116da6f 100644
--- a/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm
+++ b/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm
@@ -6,6 +6,8 @@
cooldown_time = 20 SECONDS
convert_damage = FALSE
die_with_shapeshifted_form = FALSE
+ button_icon = 'icons/mob/actions/actions_ecult.dmi'
+ button_icon_state = "lock_ascension"
possible_shapes = list(
/mob/living/basic/heretic_summon/ash_spirit,
/mob/living/basic/heretic_summon/raw_prophet/ascended,
diff --git a/code/modules/antagonists/heretic/magic/caretaker.dm b/code/modules/antagonists/heretic/magic/caretaker.dm
index 29fcecf076fb0..86ff285001917 100644
--- a/code/modules/antagonists/heretic/magic/caretaker.dm
+++ b/code/modules/antagonists/heretic/magic/caretaker.dm
@@ -6,8 +6,8 @@
and you can be removed from it upon contact with antimagical artifacts."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
- button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
- button_icon_state = "ninja_cloak"
+ button_icon = 'icons/mob/actions/actions_ecult.dmi'
+ button_icon_state = "caretaker"
sound = 'sound/effects/curse2.ogg'
school = SCHOOL_FORBIDDEN
diff --git a/code/modules/antagonists/heretic/magic/cosmic_runes.dm b/code/modules/antagonists/heretic/magic/cosmic_runes.dm
index 5115a2181fa91..4af3b94b44f34 100644
--- a/code/modules/antagonists/heretic/magic/cosmic_runes.dm
+++ b/code/modules/antagonists/heretic/magic/cosmic_runes.dm
@@ -1,6 +1,7 @@
/datum/action/cooldown/spell/cosmic_rune
name = "Cosmic Rune"
- desc = "Creates a cosmic rune at your position, only two can exist at a time. Invoking one rune transports you to the other."
+ desc = "Creates a cosmic rune at your position, only two can exist at a time. Invoking one rune transports you to the other. \
+ Anyone with a star mark gets transported along with you."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
diff --git a/code/modules/antagonists/heretic/magic/moon_parade.dm b/code/modules/antagonists/heretic/magic/moon_parade.dm
index 409e55bf9261a..3b7f1d007cd6e 100644
--- a/code/modules/antagonists/heretic/magic/moon_parade.dm
+++ b/code/modules/antagonists/heretic/magic/moon_parade.dm
@@ -1,6 +1,6 @@
/datum/action/cooldown/spell/pointed/projectile/moon_parade
name = "Lunar parade"
- desc = "This unleashes the parade towards a target."
+ desc = "This unleashes the parade, making everyone in its way join it and suffer hallucinations."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
diff --git a/code/modules/antagonists/heretic/magic/moon_ringleader.dm b/code/modules/antagonists/heretic/magic/moon_ringleader.dm
index 45d3285a876da..3c0b1d2aedb52 100644
--- a/code/modules/antagonists/heretic/magic/moon_ringleader.dm
+++ b/code/modules/antagonists/heretic/magic/moon_ringleader.dm
@@ -1,7 +1,8 @@
/datum/action/cooldown/spell/aoe/moon_ringleader
name = "Ringleaders Rise"
- desc = "Big AoE spell that deals more brain damage the lower the sanity of everyone in the AoE and it also causes hallucinations with those who have less sanity getting more. \
- If their sanity is low enough they snap and go insane, the spell then halves their sanity."
+ desc = "Big AoE spell that deals brain damage and causes hallucinations to everyone in the AoE. \
+ The worse their sanity, the stronger this spell becomes. \
+ If their sanity is low enough, they even snap and go insane, and the spell then further halves their sanity."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
diff --git a/code/modules/antagonists/heretic/magic/moon_smile.dm b/code/modules/antagonists/heretic/magic/moon_smile.dm
index 893059721c428..90a392691e9fa 100644
--- a/code/modules/antagonists/heretic/magic/moon_smile.dm
+++ b/code/modules/antagonists/heretic/magic/moon_smile.dm
@@ -28,7 +28,8 @@
/datum/action/cooldown/spell/pointed/moon_smile/cast(mob/living/carbon/human/cast_on)
. = ..()
/// The duration of these effects are based on sanity, mainly for flavor but also to make it a weaker alpha strike
- var/moon_smile_duration = (150 - cast_on.mob_mood.sanity) / 10
+ var/maximum_duration = 15 SECONDS
+ var/moon_smile_duration = ((SANITY_MAXIMUM - cast_on.mob_mood.sanity) / (SANITY_MAXIMUM - SANITY_INSANE)) * maximum_duration
if(cast_on.can_block_magic(antimagic_flags))
to_chat(cast_on, span_notice("The moon turns, its smile no longer set on you."))
to_chat(owner, span_warning("The moon does not smile upon them."))
@@ -40,7 +41,8 @@
cast_on.set_eye_blur_if_lower(moon_smile_duration + 7 SECONDS)
var/obj/item/organ/internal/ears/ears = cast_on.get_organ_slot(ORGAN_SLOT_EARS)
- ears?.adjustEarDamage(0, moon_smile_duration + 2 SECONDS)
+ //adjustEarDamage takes deafness duration parameter in one unit per two seconds, instead of the normal time, so we divide by two seconds
+ ears?.adjustEarDamage(0, (moon_smile_duration + 2 SECONDS) / (2 SECONDS))
cast_on.adjust_silence(moon_smile_duration + 5 SECONDS)
cast_on.AdjustKnockdown(2 SECONDS)
diff --git a/code/modules/antagonists/heretic/magic/nightwatcher_rebirth.dm b/code/modules/antagonists/heretic/magic/nightwatcher_rebirth.dm
index 64638d7103b17..4e37f5db17fed 100644
--- a/code/modules/antagonists/heretic/magic/nightwatcher_rebirth.dm
+++ b/code/modules/antagonists/heretic/magic/nightwatcher_rebirth.dm
@@ -1,6 +1,6 @@
/datum/action/cooldown/spell/aoe/fiery_rebirth
name = "Nightwatcher's Rebirth"
- desc = "A spell that extinguishes you drains nearby heathens engulfed in flames of their life force, \
+ desc = "A spell that extinguishes you and drains nearby heathens engulfed in flames of their life force, \
healing you for each victim drained. Those in critical condition \
will have the last of their vitality drained, killing them."
background_icon_state = "bg_heretic"
diff --git a/code/modules/antagonists/heretic/magic/rust_charge.dm b/code/modules/antagonists/heretic/magic/rust_charge.dm
index d5427cf376262..56054bd56fdd8 100644
--- a/code/modules/antagonists/heretic/magic/rust_charge.dm
+++ b/code/modules/antagonists/heretic/magic/rust_charge.dm
@@ -1,7 +1,9 @@
// Rust charge, a charge action that can only be started on rust (and only destroys rust tiles)
/datum/action/cooldown/mob_cooldown/charge/rust
name = "Rust Charge"
- desc = "A charge that must be started on a rusted tile and will destroy any rusted objects you come into contact with, will deal high damage to others and rust around you during the charge. As it is the rust that empoweres you for this ability, no focus is needed"
+ desc = "A charge that must be started on a rusted tile and will destroy any rusted objects you come into contact with, \
+ will deal high damage to others and rust around you during the charge. \
+ As it is the rust that empowers you with this ability, no focus is needed."
charge_distance = 10
charge_damage = 50
cooldown_time = 45 SECONDS
diff --git a/code/modules/antagonists/heretic/magic/star_blast.dm b/code/modules/antagonists/heretic/magic/star_blast.dm
index 212e90535d6c7..48fdf2f26934b 100644
--- a/code/modules/antagonists/heretic/magic/star_blast.dm
+++ b/code/modules/antagonists/heretic/magic/star_blast.dm
@@ -1,6 +1,6 @@
/datum/action/cooldown/spell/pointed/projectile/star_blast
name = "Star Blast"
- desc = "This spell fires a disk with cosmic energies at a target."
+ desc = "This spell fires a disk with cosmic energies at a target, spreading the star mark."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
diff --git a/code/modules/antagonists/heretic/magic/star_touch.dm b/code/modules/antagonists/heretic/magic/star_touch.dm
index 9037d07295a94..89c5d02e7d498 100644
--- a/code/modules/antagonists/heretic/magic/star_touch.dm
+++ b/code/modules/antagonists/heretic/magic/star_touch.dm
@@ -1,7 +1,8 @@
/datum/action/cooldown/spell/touch/star_touch
name = "Star Touch"
- desc = "Marks someone with a star mark or puts someone with a star mark to sleep for 4 seconds, removing the star mark. \
- You and your target are linked with a cosmic ray, burning them for up to a minute, or \
+ desc = "Manifests cosmic fields on tiles next to you while marking the victim with a star mark \
+ or consuming an already present star mark to put them to sleep for 4 seconds. \
+ They will then be linked to you with a cosmic ray, burning them for up to a minute, or \
until they can escape your sight. Star Touch can also remove Cosmic Runes, or teleport you \
to your Star Gazer when used on yourself."
background_icon_state = "bg_heretic"
diff --git a/code/modules/antagonists/heretic/status_effects/debuffs.dm b/code/modules/antagonists/heretic/status_effects/debuffs.dm
index 08839fa8f1058..7037d1cc3778b 100644
--- a/code/modules/antagonists/heretic/status_effects/debuffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/debuffs.dm
@@ -280,7 +280,7 @@
/datum/status_effect/moon_converted/on_remove()
// Span warning and unconscious so they realize they aren't evil anymore
- to_chat(owner, span_warning("Your mind is cleared from the effect of the manus, your alligiences are as they were before"))
+ to_chat(owner, span_warning("Your mind is cleared from the effect of the mansus, your alligiences are as they were before"))
REMOVE_TRAIT(owner, TRAIT_MUTE, REF(src))
owner.AdjustUnconscious(5 SECONDS, ignore_canstun = FALSE)
owner.log_message("[owner] is no longer insane.", LOG_GAME)
diff --git a/code/modules/antagonists/heretic/structures/lock_final.dm b/code/modules/antagonists/heretic/structures/lock_final.dm
index 8cb6c06f3cb01..759bc8aa55e39 100644
--- a/code/modules/antagonists/heretic/structures/lock_final.dm
+++ b/code/modules/antagonists/heretic/structures/lock_final.dm
@@ -37,7 +37,7 @@
/// Ask ghosts if they want to make some noise
/obj/structure/lock_tear/proc/poll_ghosts()
- var/list/candidates = SSpolling.poll_ghost_candidates("Would you like to be a random eldritch monster attacking the crew?", check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, poll_time = 10 SECONDS, ignore_category = POLL_IGNORE_HERETIC_MONSTER, pic_source = src, role_name_text = "eldritch monster")
+ var/list/candidates = SSpolling.poll_ghost_candidates("Would you like to be a random [span_notice("eldritch monster")] attacking the crew?", check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, poll_time = 10 SECONDS, ignore_category = POLL_IGNORE_HERETIC_MONSTER, alert_pic = src, role_name_text = "eldritch monster")
while(LAZYLEN(candidates))
var/mob/dead/observer/candidate = pick_n_take(candidates)
ghost_to_monster(candidate, should_ask = FALSE)
diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm
index 068bb2b6c5c1f..38db2dfae8657 100644
--- a/code/modules/antagonists/nightmare/nightmare_species.dm
+++ b/code/modules/antagonists/nightmare/nightmare_species.dm
@@ -39,7 +39,6 @@
. = ..()
C.fully_replace_character_name(null, pick(GLOB.nightmare_names))
- C.set_safe_hunger_level()
/datum/species/shadow/nightmare/check_roundstart_eligible()
return FALSE
diff --git a/code/modules/antagonists/nukeop/datums/operative_team.dm b/code/modules/antagonists/nukeop/datums/operative_team.dm
index e42d65b42a845..9bec3b0fcf0e1 100644
--- a/code/modules/antagonists/nukeop/datums/operative_team.dm
+++ b/code/modules/antagonists/nukeop/datums/operative_team.dm
@@ -154,19 +154,17 @@
var/tc_to_spawn = tgui_input_number(admin, "How much TC to spawn with?", "TC", 0, 100)
- var/list/nuke_candidates = SSpolling.poll_ghost_candidates(
- "Do you want to play as an emergency syndicate reinforcement?",
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(
check_jobban = ROLE_OPERATIVE,
role = ROLE_OPERATIVE,
poll_time = 30 SECONDS,
ignore_category = POLL_IGNORE_SYNDICATE,
- pic_source = /obj/structure/sign/poster/contraband/gorlex_recruitment,
- role_name_text = "syndicate reinforcement",
+ alert_pic = /obj/structure/sign/poster/contraband/gorlex_recruitment,
+ role_name_text = "emergency syndicate reinforcement",
+ amount_to_pick = 1,
)
- nuke_candidates -= admin // may be easy to fat-finger say yes. so just don't
-
- if(!length(nuke_candidates))
+ if(isnull(chosen_one))
tgui_alert(admin, "No candidates found.", "Recruitment Shortage", list("OK"))
return
@@ -194,10 +192,9 @@
if(infil_or_nukebase == SPAWN_AT_BASE)
spawn_loc = pick(GLOB.nukeop_start)
- var/mob/dead/observer/picked = pick(nuke_candidates)
var/mob/living/carbon/human/nukie = new(spawn_loc)
- picked.client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE)
- nukie.key = picked.key
+ chosen_one.client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE)
+ nukie.key = chosen_one.key
var/datum/antagonist/nukeop/antag_datum = new()
antag_datum.send_to_spawnpoint = FALSE
diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm b/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm
index 72c51f14b2b99..c318679b4f6fe 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm
@@ -26,7 +26,7 @@
/obj/item/disk/nuclear/Initialize(mapload)
. = ..()
- AddElement(/datum/element/bed_tuckable, 6, -6, 0)
+ AddElement(/datum/element/bed_tuckable, mapload, 6, -6, 0)
AddComponent(/datum/component/stationloving, !fake)
if(!fake)
diff --git a/code/modules/antagonists/pirate/pirate_event.dm b/code/modules/antagonists/pirate/pirate_event.dm
index f3c6655a27572..e4a14182d0e7f 100644
--- a/code/modules/antagonists/pirate/pirate_event.dm
+++ b/code/modules/antagonists/pirate/pirate_event.dm
@@ -66,7 +66,7 @@
if(chosen_gang.paid_off)
return
- var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a pirate crew of [chosen_gang.name]?", check_jobban = ROLE_TRAITOR, pic_source = /obj/item/claymore/cutlass, role_name_text = "pirate crew")
+ var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a [span_notice("pirate crew of [chosen_gang.name]?")]", check_jobban = ROLE_TRAITOR, alert_pic = /obj/item/claymore/cutlass, role_name_text = "pirate crew")
shuffle_inplace(candidates)
var/template_key = "pirate_[chosen_gang.ship_template_id]"
diff --git a/code/modules/antagonists/spy/spy_bounty.dm b/code/modules/antagonists/spy/spy_bounty.dm
index 035ebba340512..e3c96fc815f3b 100644
--- a/code/modules/antagonists/spy/spy_bounty.dm
+++ b/code/modules/antagonists/spy/spy_bounty.dm
@@ -141,7 +141,15 @@
if(isitem(stealing) && ((stealing.resistance_flags & INDESTRUCTIBLE) || prob(black_market_prob)))
addtimer(CALLBACK(src, PROC_REF(send_to_black_market), stealing), 0.5 SECONDS)
else
- QDEL_IN(stealing, 0.5 SECONDS)
+ addtimer(CALLBACK(src, PROC_REF(finish_cleanup), stealing), 0.5 SECONDS)
+
+/**
+ * Called when cleaning up a stolen atom that was NOT sent to the black market.
+ *
+ * * stealing - The item that was stolen.
+ */
+/datum/spy_bounty/proc/finish_cleanup(atom/movable/stealing)
+ qdel(stealing)
/**
* Handles putting the passed movable up on the black market.
@@ -311,6 +319,10 @@
return TRUE
+/datum/spy_bounty/machine/finish_cleanup(obj/machinery/stealing)
+ stealing.dump_inventory_contents()
+ return ..()
+
/datum/spy_bounty/machine/init_bounty(datum/spy_bounty_handler/handler)
if(isnull(target_type))
return FALSE
@@ -438,7 +450,7 @@
/datum/spy_bounty/machine/random/hard/ai_sat_teleporter
random_options = list(
/obj/machinery/teleport,
- /obj/machinery/computer/teleporter.
+ /obj/machinery/computer/teleporter,
)
location_type = /area/station/ai_monitored/aisat
@@ -626,6 +638,13 @@
/datum/spy_bounty/some_bot/get_dupe_protection_key(atom/movable/stealing)
return bot_type
+/datum/spy_bounty/some_bot/finish_cleanup(mob/living/simple_animal/bot/stealing)
+ if(stealing.client)
+ to_chat(stealing, span_deadsay("You've been stolen! You are shipped off to the black market and taken apart for spare parts..."))
+ stealing.investigate_log("stole by a spy (and deleted)", INVESTIGATE_DEATHS)
+ stealing.ghostize()
+ return ..()
+
/datum/spy_bounty/some_bot/init_bounty(datum/spy_bounty_handler/handler)
for(var/datum/spy_bounty/some_bot/existing_bounty in handler.get_all_bounties())
var/mob/living/simple_animal/bot/existing_bot_type = existing_bounty.bot_type
diff --git a/code/modules/antagonists/spy/spy_uplink.dm b/code/modules/antagonists/spy/spy_uplink.dm
index ea6f39fc92d4b..2a9d9b9b14e9b 100644
--- a/code/modules/antagonists/spy/spy_uplink.dm
+++ b/code/modules/antagonists/spy/spy_uplink.dm
@@ -97,6 +97,7 @@
to_chat(spy, span_warning("Your uplinks blinks red: [stealing] cannot be extracted from there."))
return FALSE
+ log_combat(spy, stealing, "started stealing", parent, "(spy bounty)")
playsound(stealing, 'sound/items/pshoom.ogg', 33, vary = TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, frequency = 0.33, ignore_walls = FALSE)
var/obj/effect/scan_effect/active_scan_effect = new(stealing.loc)
@@ -160,7 +161,8 @@
playsound(parent, 'sound/machines/wewewew.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
- log_spy("[key_name(spy)] completed the bounty [bounty.name] of difficulty [bounty.difficulty] for \a [reward].")
+ log_combat(spy, stealing, "stole", parent, "(spy bounty)")
+ log_spy("[key_name(spy)] completed the bounty [bounty.name] of difficulty [bounty.difficulty] by stealing [stealing] for \a [reward].")
SSblackbox.record_feedback("nested tally", "spy_bounty", 1, list("[stealing.type]", "[bounty.type]", "[bounty.difficulty]", "[bounty.reward_item.type]"))
var/datum/antagonist/spy/spy_datum = spy_ref?.resolve()
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index 02357d22e8b41..78cd4f4929c8a 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -312,15 +312,17 @@
return TRUE
to_chat(user, "[span_userdanger("Capture failed!")]: The soul has already fled its mortal frame. You attempt to bring it back...")
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(on_poll_concluded), user, victim)
- AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_SHADE, \
- job_bans = ROLE_CULTIST, \
- to_call = to_call, \
- title = "A shade" \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ check_jobban = ROLE_CULTIST,
+ poll_time = 20 SECONDS,
+ checked_target = src,
+ ignore_category = POLL_IGNORE_SHADE,
+ alert_pic = /mob/living/basic/shade,
+ jump_target = src,
+ role_name_text = "a shade",
+ chat_text_border_icon = /mob/living/basic/shade,
)
-
+ on_poll_concluded(user, victim, chosen_one)
return TRUE //it'll probably get someone ;)
///captures a shade that was previously released from a soulstone.
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index 5319d4465e2ab..659bcec50cf97 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -171,7 +171,7 @@
visible_message(span_danger("[user] blinds [flashed] with the flash!"), span_userdanger("[user] blinds you with the flash!"))
//easy way to make sure that you can only long stun someone who is facing in your direction
flashed.adjustStaminaLoss(rand(80, 120) * (1 - (deviation * 0.5)))
- flashed.Paralyze(rand(25, 50) * (1 - (deviation * 0.5)))
+ flashed.Knockdown(rand(25, 50) * (1 - (deviation * 0.5)))
SEND_SIGNAL(user, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON, flashed, src, deviation)
else if(user)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index be455ea6d4709..82760e75a6259 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -54,6 +54,10 @@
///Whether it can be painted
var/paintable = TRUE
+ ///Whether it will generate cap sprites when hidden
+ var/has_cap_visuals = FALSE
+ ///Cap overlay that is being added to turf's `vis_contents`, `null` if pipe was never hidden or has no valid connections
+ var/obj/effect/overlay/cap_visual/cap_overlay
///Is the thing being rebuilt by SSair or not. Prevents list bloat
var/rebuilding = FALSE
@@ -106,6 +110,10 @@
if(isturf(loc))
turf_loc = loc
turf_loc.add_blueprints_preround(src)
+
+ if(hide)
+ RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(on_hide))
+
SSspatial_grid.add_grid_awareness(src, SPATIAL_GRID_CONTENTS_TYPE_ATMOS)
SSspatial_grid.add_grid_membership(src, turf_loc, SPATIAL_GRID_CONTENTS_TYPE_ATMOS)
if(init_processing)
@@ -119,11 +127,22 @@
SSair.stop_processing_machine(src)
SSair.rebuild_queue -= src
- if(pipe_vision_img)
- qdel(pipe_vision_img)
+ QDEL_NULL(pipe_vision_img)
+ QDEL_NULL(cap_overlay)
return ..()
- //return QDEL_HINT_FINDREFERENCE
+
+/**
+ * Handler for `COMSIG_OBJ_HIDE`, connects only if `hide` is set to `TRUE`. Calls `update_cap_visuals` on pipe and its connected nodes
+ */
+/obj/machinery/atmospherics/proc/on_hide(datum/source, underfloor_accessibility)
+ SHOULD_CALL_PARENT(TRUE)
+ SIGNAL_HANDLER
+
+ for(var/obj/machinery/atmospherics/node in nodes)
+ node.update_cap_visuals()
+
+ update_cap_visuals()
/**
* Run when you update the conditions in which an /atom might want to start reacting to its turf's air
@@ -205,8 +224,9 @@
update_appearance()
/obj/machinery/atmospherics/update_icon()
- . = ..()
update_layer()
+ update_cap_visuals()
+ return ..()
/**
* Find a connecting /obj/machinery/atmospherics in specified direction, called by relaymove()
@@ -616,6 +636,49 @@
/obj/machinery/atmospherics/proc/update_layer()
return
+/**
+ * Handles cap overlay addition and removal, won't do anything if `has_cap_visuals` is set to `FALSE`
+ */
+/obj/machinery/atmospherics/proc/update_cap_visuals()
+ if(!has_cap_visuals)
+ return
+
+ var/turf/our_turf = get_turf(src)
+ our_turf.vis_contents -= cap_overlay
+
+ var/connections = NONE
+ for(var/obj/machinery/atmospherics/node in nodes)
+ if(HAS_TRAIT(node, TRAIT_UNDERFLOOR))
+ continue
+
+ if(isplatingturf(get_turf(node)))
+ continue
+
+ var/connected_dir = get_dir(src, node)
+ connections |= connected_dir
+
+ if(connections == NONE)
+ return
+
+ var/bitfield = CARDINAL_TO_PIPECAPS(connections)
+ bitfield |= ((~connections) & ALL_CARDINALS)
+
+ if(isnull(cap_overlay))
+ cap_overlay = new
+
+ SET_PLANE_EXPLICIT(cap_overlay, initial(plane), our_turf)
+
+ cap_overlay.color = pipe_color
+ cap_overlay.layer = layer
+ cap_overlay.icon_state = "[bitfield]_[piping_layer]"
+
+ our_turf.vis_contents += cap_overlay
+
+/obj/effect/overlay/cap_visual
+ appearance_flags = KEEP_APART
+ vis_flags = VIS_INHERIT_ID
+ icon = 'icons/obj/pipes_n_cables/!pipes_bitmask.dmi'
+
/**
* Called by the RPD.dm pre_attack()
* Arguments:
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index e72d72b3d5955..b4e5d88d62c71 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -32,12 +32,6 @@
component_mixture.volume = 200
airs[i] = component_mixture
-/obj/machinery/atmospherics/components/Initialize(mapload)
- . = ..()
-
- if(hide)
- RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(hide_pipe))
-
// Iconnery
/**
@@ -46,11 +40,14 @@
/obj/machinery/atmospherics/components/proc/update_icon_nopipes()
return
+/obj/machinery/atmospherics/components/on_hide(datum/source, underfloor_accessibility)
+ hide_pipe(underfloor_accessibility)
+ return ..()
+
/**
- * Called in Initialize(), set the showpipe var to true or false depending on the situation, calls update_icon()
+ * Called in on_hide(), set the showpipe var to true or false depending on the situation, calls update_icon()
*/
-/obj/machinery/atmospherics/components/proc/hide_pipe(datum/source, underfloor_accessibility)
- SIGNAL_HANDLER
+/obj/machinery/atmospherics/components/proc/hide_pipe(underfloor_accessibility)
showpipe = !!underfloor_accessibility
if(showpipe)
REMOVE_TRAIT(src, TRAIT_UNDERFLOOR, REF(src))
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
index ea20f2eeb66a8..4161a30ed7d72 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
@@ -10,6 +10,7 @@
hide = TRUE
layer = GAS_SCRUBBER_LAYER
pipe_state = "injector"
+ has_cap_visuals = TRUE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF //really helpful in building gas chambers for xenomorphs
idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.25
@@ -74,6 +75,8 @@
if(showpipe)
// everything is already shifted so don't shift the cap
add_overlay(get_pipe_image(icon, "inje_cap", initialize_directions, pipe_color))
+ else
+ PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
if(!nodes[1] || !on || !is_operational)
icon_state = "inje_off"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
index f461cbe8988f8..17f6c761f129d 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
@@ -10,6 +10,7 @@
shift_underlay_only = FALSE
pipe_state = "pvent"
+ has_cap_visuals = TRUE
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
/obj/machinery/atmospherics/components/unary/passive_vent/update_icon_nopipes()
@@ -17,6 +18,8 @@
if(showpipe)
var/image/cap = get_pipe_image(icon, "vent_cap", initialize_directions, pipe_color)
add_overlay(cap)
+ else
+ PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
icon_state = "passive_vent"
/obj/machinery/atmospherics/components/unary/passive_vent/process_atmos()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
index d5eada4e73f89..f47d6d5b069ca 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
@@ -13,6 +13,8 @@
pipe_flags = PIPING_ONE_PER_TURF
pipe_state = "connector"
+ has_cap_visuals = TRUE
+
custom_reconcilation = TRUE
///Reference to the connected device
@@ -29,11 +31,13 @@
return ..()
/obj/machinery/atmospherics/components/unary/portables_connector/update_icon_nopipes()
- icon_state = "connector"
+ cut_overlays()
if(showpipe)
- cut_overlays()
var/image/cap = get_pipe_image(icon, "connector_cap", initialize_directions, pipe_color)
add_overlay(cap)
+ else
+ PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
+ icon_state = "connector"
/obj/machinery/atmospherics/components/unary/portables_connector/process_atmos()
if(!connected_device)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index 46adfee054e6e..aa890b0b574a0 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -16,8 +16,6 @@
layer = OBJ_LAYER
circuit = /obj/item/circuitboard/machine/thermomachine
- hide = TRUE
-
move_resist = MOVE_RESIST_DEFAULT
vent_movement = NONE
pipe_flags = PIPING_ONE_PER_TURF
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
index f3c5563fd3afd..bece67572b6f5 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
@@ -14,6 +14,7 @@
hide = TRUE
shift_underlay_only = FALSE
pipe_state = "uvent"
+ has_cap_visuals = TRUE
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
// vents are more complex machinery and so are less resistant to damage
max_integrity = 100
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
index 50054417362d2..102728fb59149 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -12,6 +12,7 @@
hide = TRUE
shift_underlay_only = FALSE
pipe_state = "scrubber"
+ has_cap_visuals = TRUE
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
processing_flags = NONE
diff --git a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm
index 9642442a9733f..6b1997cc3c718 100644
--- a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm
+++ b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm
@@ -18,6 +18,13 @@
"[WEST]"=icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "damage_mask", WEST),
)
+ var/static/list/icon/cap_masks = list(
+ "[NORTH]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", NORTH),
+ "[EAST]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", EAST),
+ "[SOUTH]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", SOUTH),
+ "[WEST]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", WEST),
+ )
+
var/icon/generated_icons
/datum/pipe_icon_generator/proc/Start(icon_state_suffix="")
@@ -85,6 +92,34 @@
outputs[damaged] = "[icon_state_dirs]_[layer]"
return outputs
+/datum/pipe_icon_generator/proc/generate_capped(icon/working, layer, dirs, x_offset=1, y_offset=1)
+ var/list/outputs = list()
+ var/list/completed = list()
+ for(var/combined_dirs in 1 to 15)
+ combined_dirs &= dirs
+
+ var/completion_key = "[combined_dirs]"
+ if(completed[completion_key] || (combined_dirs == NONE))
+ continue
+
+ completed[completion_key] = TRUE
+
+ var/icon/capped_mask = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "blank_mask")
+ for(var/i in 0 to 3)
+ var/dir = 1 << i
+ if(!(combined_dirs & dir))
+ continue
+
+ var/icon/cap_mask = cap_masks["[dir]"]
+ capped_mask.Blend(cap_mask, ICON_OVERLAY, x_offset, y_offset)
+
+ var/icon/capped = icon(working)
+ capped.Blend(capped_mask, ICON_MULTIPLY)
+
+ var/icon_state_dirs = (dirs & ~combined_dirs) | CARDINAL_TO_PIPECAPS(combined_dirs)
+ outputs[capped] = "[icon_state_dirs]_[layer]"
+
+ return outputs
/datum/pipe_icon_generator/proc/GeneratePipeStraight(icon_state_suffix, layer, combined_dirs)
var/list/output = list()
@@ -97,8 +132,10 @@
switch(combined_dirs)
if(NORTH | SOUTH)
output += GenerateDamaged(working, layer, combined_dirs, y_offset=offset)
+ output += generate_capped(working, layer, combined_dirs, y_offset=offset)
if(EAST | WEST)
output += GenerateDamaged(working, layer, combined_dirs, x_offset=offset)
+ output += generate_capped(working, layer, combined_dirs, x_offset=offset)
return output
@@ -117,6 +154,7 @@
output[working] = "[combined_dirs]_[layer]"
output += GenerateDamaged(working, layer, combined_dirs)
+ output += generate_capped(working, layer, combined_dirs)
return output
@@ -135,6 +173,7 @@
output[working] = "[combined_dirs]_[layer]"
output += GenerateDamaged(working, layer, combined_dirs)
+ output += generate_capped(working, layer, combined_dirs)
return output
@@ -144,5 +183,6 @@
output[working] = "[combined_dirs]_[layer]"
output += GenerateDamaged(working, layer, combined_dirs)
+ output += generate_capped(working, layer, combined_dirs)
return output
diff --git a/code/modules/atmospherics/machinery/pipes/smart.dm b/code/modules/atmospherics/machinery/pipes/smart.dm
index 7c530bace5fcf..ce4dc0e36a51e 100644
--- a/code/modules/atmospherics/machinery/pipes/smart.dm
+++ b/code/modules/atmospherics/machinery/pipes/smart.dm
@@ -10,6 +10,8 @@ GLOBAL_LIST_INIT(atmos_components, typecacheof(list(/obj/machinery/atmospherics)
device_type = QUATERNARY
construction_type = /obj/item/pipe/quaternary
pipe_state = "manifold4w"
+ has_cap_visuals = TRUE
+
///Current active connections
var/connections = NONE
diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm
index 3ed4ad45bc668..6c42322d0cf01 100644
--- a/code/modules/bitrunning/server/threats.dm
+++ b/code/modules/bitrunning/server/threats.dm
@@ -69,16 +69,15 @@
var/datum/antagonist/bitrunning_glitch/chosen_role = forced_role || get_antagonist_role()
var/role_name = initial(chosen_role.name)
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(spawn_glitch), chosen_role, mutation_target)
- mutation_target.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_GLITCH, \
- job_bans = ROLE_GLITCH, \
- to_call = to_call, \
- title = role_name, \
- header = "Bitrunning Malfunction", \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ check_jobban = ROLE_GLITCH,
+ poll_time = 20 SECONDS,
+ checked_target = mutation_target,
+ ignore_category = POLL_IGNORE_GLITCH,
+ alert_pic = mutation_target,
+ role_name_text = "Bitrunning Malfunction: [role_name]",
)
-
+ spawn_glitch(chosen_role, mutation_target, chosen_one)
return mutation_target
/// Orbit poll has concluded - spawn the antag
diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
index 838834f45a74a..41e5da8973e12 100644
--- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm
+++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
@@ -6,6 +6,7 @@
map_dir = "_maps/virtual_domains"
map_name = "None"
key = "Virtual Domain"
+ place_on_top = TRUE
/// Cost of this map to load
var/cost = BITRUNNER_COST_NONE
diff --git a/code/modules/cargo/coupon.dm b/code/modules/cargo/coupon.dm
index f654db448872e..4c5e56a7d4119 100644
--- a/code/modules/cargo/coupon.dm
+++ b/code/modules/cargo/coupon.dm
@@ -84,7 +84,7 @@
to_chat(cursed, span_warning("The coupon reads 'fuck you' in large, bold text... is- is that a prize, or?"))
if(!cursed.GetComponent(/datum/component/omen))
- cursed.AddComponent(/datum/component/omen)
+ cursed.AddComponent(/datum/component/omen, 1)
return TRUE
if(HAS_TRAIT(cursed, TRAIT_CURSED))
to_chat(cursed, span_warning("What a horrible night... To have a curse!"))
diff --git a/code/modules/cargo/exports/parts.dm b/code/modules/cargo/exports/parts.dm
index 840d40f183712..fc8c9656fea78 100644
--- a/code/modules/cargo/exports/parts.dm
+++ b/code/modules/cargo/exports/parts.dm
@@ -33,3 +33,9 @@
unit_name = "data disk"
export_types = list(/obj/item/computer_disk)
include_subtypes = TRUE
+
+/datum/export/refill_canister
+ cost = CARGO_CRATE_VALUE * 0.5 //If someone want to make this worth more as it empties, go ahead
+ unit_name = "vending refill canister"
+ message = "Thank you for restocking the station!"
+ export_types = list(/obj/item/vending_refill)
diff --git a/code/modules/cargo/markets/market_uplink.dm b/code/modules/cargo/markets/market_uplink.dm
index 19c1a049a1be0..a82218082e90d 100644
--- a/code/modules/cargo/markets/market_uplink.dm
+++ b/code/modules/cargo/markets/market_uplink.dm
@@ -150,6 +150,7 @@
icon_state = "uplink"
//The original black market uplink
accessible_markets = list(/datum/market/blackmarket)
+ custom_premium_price = PAYCHECK_CREW * 2.5
/datum/crafting_recipe/blackmarket_uplink
diff --git a/code/modules/cargo/materials_market.dm b/code/modules/cargo/materials_market.dm
index 92d83d5d0a141..947197d16f298 100644
--- a/code/modules/cargo/materials_market.dm
+++ b/code/modules/cargo/materials_market.dm
@@ -166,12 +166,14 @@
var/min_value_override = initial(traded_mat.minimum_value_override)
if(min_value_override)
minimum_value_threshold = min_value_override
-
+ else
+ minimum_value_threshold = round(initial(traded_mat.value_per_unit) * SHEET_MATERIAL_AMOUNT * 0.5)
//send data
material_data += list(list(
"name" = initial(traded_mat.name),
"price" = SSstock_market.materials_prices[traded_mat],
+ "rarity" = initial(traded_mat.value_per_unit),
"threshold" = minimum_value_threshold,
"quantity" = SSstock_market.materials_quantity[traded_mat],
"trend" = trend_string,
@@ -205,6 +207,7 @@
.["orderBalance"] = current_cost
.["orderingPrive"] = ordering_private
.["canOrderCargo"] = can_buy_via_budget
+ .["updateTime"] = SSstock_market.next_fire - world.time
/obj/machinery/materials_market/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
. = ..()
@@ -348,8 +351,8 @@
/obj/item/stock_block/Initialize(mapload)
. = ..()
- addtimer(CALLBACK(src, PROC_REF(value_warning)), 2.5 MINUTES, TIMER_DELETE_ME)
- addtimer(CALLBACK(src, PROC_REF(update_value)), 5 MINUTES, TIMER_DELETE_ME)
+ addtimer(CALLBACK(src, PROC_REF(value_warning)), 1.5 MINUTES, TIMER_DELETE_ME)
+ addtimer(CALLBACK(src, PROC_REF(update_value)), 3 MINUTES, TIMER_DELETE_ME)
/obj/item/stock_block/examine(mob/user)
. = ..()
diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm
index f0de463c4490f..7fa9013c686cf 100644
--- a/code/modules/cargo/packs/science.dm
+++ b/code/modules/cargo/packs/science.dm
@@ -104,14 +104,16 @@
name = "Robotics Assembly Crate"
desc = "The tools you need to replace those finicky humans with a loyal robot army! \
Contains four proximity sensors, two empty first aid kits, two health analyzers, \
- two red hardhats, two mechanical toolboxes, and two cleanbot assemblies!"
+ two red hardhats, two toolboxes, and two cleanbot assemblies!"
cost = CARGO_CRATE_VALUE * 3
access = ACCESS_ROBOTICS
access_view = ACCESS_ROBOTICS
- contains = list(/obj/item/assembly/prox_sensor = 5,
+ contains = list(/obj/item/assembly/prox_sensor = 4,
/obj/item/healthanalyzer = 2,
/obj/item/clothing/head/utility/hardhat/red = 2,
- /obj/item/storage/medkit = 2)
+ /obj/item/storage/medkit = 2,
+ /obj/item/storage/toolbox = 2,
+ /obj/item/bot_assembly/cleanbot = 2)
crate_name = "robotics assembly crate"
crate_type = /obj/structure/closet/crate/secure/science/robo
diff --git a/code/modules/cargo/packs/vending_restock.dm b/code/modules/cargo/packs/vending_restock.dm
index cfe9961cc3a43..10ae874d5d6c9 100644
--- a/code/modules/cargo/packs/vending_restock.dm
+++ b/code/modules/cargo/packs/vending_restock.dm
@@ -4,7 +4,7 @@
/datum/supply_pack/vending/bartending
name = "Booze-o-mat and Coffee Supply Crate"
desc = "Bring on the booze and coffee vending machine refills."
- cost = CARGO_CRATE_VALUE * 4
+ cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/boozeomat,
/obj/item/vending_refill/coffee,
)
@@ -14,7 +14,7 @@
name = "Cigarette Supply Crate"
desc = "Don't believe the reports - smoke today! Contains a \
cigarette vending machine refill."
- cost = CARGO_CRATE_VALUE * 3
+ cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/cigarette)
crate_name = "cigarette supply crate"
crate_type = /obj/structure/closet/crate
@@ -62,7 +62,7 @@
/datum/supply_pack/vending/imported
name = "Imported Vending Machines"
desc = "Vending machines famous in other parts of the galaxy."
- cost = CARGO_CRATE_VALUE * 8
+ cost = CARGO_CRATE_VALUE * 5
contains = list(/obj/item/vending_refill/sustenance,
/obj/item/vending_refill/robotics,
/obj/item/vending_refill/sovietsoda,
@@ -74,7 +74,7 @@
name = "Medical Vending Crate"
desc = "Contains one NanoMed Plus refill, one NanoDrug Plus refill, \
and one wall-mounted NanoMed refill."
- cost = CARGO_CRATE_VALUE * 5
+ cost = CARGO_CRATE_VALUE * 3.5
contains = list(/obj/item/vending_refill/medical,
/obj/item/vending_refill/drugs,
/obj/item/vending_refill/wallmed,
@@ -85,7 +85,7 @@
name = "PTech Supply Crate"
desc = "Not enough cartridges after half the crew lost their PDA \
to explosions? This may fix it."
- cost = CARGO_CRATE_VALUE * 3
+ cost = CARGO_CRATE_VALUE * 2.5
contains = list(/obj/item/vending_refill/cart)
crate_name = "\improper PTech supply crate"
@@ -103,7 +103,7 @@
name = "Snack Supply Crate"
desc = "One vending machine refill of cavity-bringin' goodness! \
The number one dentist recommended order!"
- cost = CARGO_CRATE_VALUE * 3
+ cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/snack)
crate_name = "snacks supply crate"
@@ -111,14 +111,14 @@
name = "Softdrinks Supply Crate"
desc = "Got whacked by a toolbox, but you still have those pesky teeth? \
Get rid of those pearly whites with this soda machine refill, today!"
- cost = CARGO_CRATE_VALUE * 3
+ cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/cola)
crate_name = "soft drinks supply crate"
/datum/supply_pack/vending/vendomat
name = "Part-Mart & YouTool Supply Crate"
desc = "More tools for your IED testing facility."
- cost = CARGO_CRATE_VALUE * 2
+ cost = CARGO_CRATE_VALUE * 3
contains = list(/obj/item/vending_refill/assist,
/obj/item/vending_refill/youtool,
)
@@ -138,7 +138,7 @@
name = "Autodrobe Supply Crate"
desc = "Autodrobe missing your favorite dress? Solve that issue today \
with this autodrobe refill."
- cost = CARGO_CRATE_VALUE * 3
+ cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/autodrobe)
crate_name = "autodrobe supply crate"
@@ -200,7 +200,7 @@
name = "Science Wardrobe Supply Crate"
desc = "This crate contains refills for the SciDrobe, \
GeneDrobe, and RoboDrobe."
- cost = CARGO_CRATE_VALUE * 3
+ cost = CARGO_CRATE_VALUE * 4.5
contains = list(/obj/item/vending_refill/wardrobe/robo_wardrobe,
/obj/item/vending_refill/wardrobe/gene_wardrobe,
/obj/item/vending_refill/wardrobe/science_wardrobe,
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 5de1341358230..1ba96157dc89f 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -1164,8 +1164,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
return 0
- if(!isnum(player_age))
- return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
+ if(!isnum(player_age) || player_age < 0)
+ return 0
if(!isnum(days_needed))
return 0
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index 25267e92eff9c..1009cc8a6afd7 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -10,12 +10,15 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
to_chat(usr, span_danger("Speech is currently admin-disabled."))
return
- if(!mob)
- return
+ var/client_initalized = VALIDATE_CLIENT_INITIALIZATION(src)
+ if(isnull(mob) || !client_initalized)
+ if(!client_initalized)
+ unvalidated_client_error() // we only want to throw this warning message when it's directly related to client failure.
- VALIDATE_CLIENT(src)
+ to_chat(usr, span_warning("Failed to send your OOC message. You attempted to send the following message:\n[span_big(msg)]"))
+ return
- if(!holder)
+ if(isnull(holder))
if(!GLOB.ooc_allowed)
to_chat(src, span_danger("OOC is globally muted."))
return
diff --git a/code/modules/clothing/belts/polymorph_belt.dm b/code/modules/clothing/belts/polymorph_belt.dm
index 73959d6d41519..fb09b2e68c8f1 100644
--- a/code/modules/clothing/belts/polymorph_belt.dm
+++ b/code/modules/clothing/belts/polymorph_belt.dm
@@ -63,10 +63,9 @@
if (target_mob.mob_biotypes & (MOB_HUMANOID|MOB_ROBOTIC|MOB_SPECIAL|MOB_SPIRIT|MOB_UNDEAD))
balloon_alert(user, "incompatible!")
return TRUE
- if (isanimal_or_basicmob(target_mob))
- if (!target_mob.compare_sentience_type(SENTIENCE_ORGANIC))
- balloon_alert(user, "target too intelligent!")
- return TRUE
+ if (!target_mob.compare_sentience_type(SENTIENCE_ORGANIC))
+ balloon_alert(user, "target too intelligent!")
+ return TRUE
if (stored_mob_type == target_mob.type)
balloon_alert(user, "already scanned!")
return TRUE
diff --git a/code/modules/clothing/head/mind_monkey_helmet.dm b/code/modules/clothing/head/mind_monkey_helmet.dm
index 50ac5bb8ba254..449df33550560 100644
--- a/code/modules/clothing/head/mind_monkey_helmet.dm
+++ b/code/modules/clothing/head/mind_monkey_helmet.dm
@@ -47,19 +47,18 @@
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
RegisterSignal(magnification, COMSIG_SPECIES_LOSS, PROC_REF(make_fall_off))
polling = TRUE
- var/list/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a mind magnified monkey?", check_jobban = ROLE_MONKEY_HELMET, poll_time = 5 SECONDS, target_mob = magnification, ignore_category = POLL_IGNORE_MONKEY_HELMET, pic_source = magnification, role_name_text = "mind-magnified monkey")
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_MONKEY_HELMET, poll_time = 5 SECONDS, checked_target = magnification, ignore_category = POLL_IGNORE_MONKEY_HELMET, alert_pic = magnification, role_name_text = "mind-magnified monkey")
polling = FALSE
if(!magnification)
return
- if(!candidates.len)
+ if(isnull(chosen_one))
UnregisterSignal(magnification, COMSIG_SPECIES_LOSS)
magnification = null
visible_message(span_notice("[src] falls silent and drops on the floor. Maybe you should try again later?"))
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
user.dropItemToGround(src)
return
- var/mob/picked = pick(candidates)
- magnification.key = picked.key
+ magnification.key = chosen_one.key
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, FALSE)
to_chat(magnification, span_notice("You're a mind magnified monkey! Protect your helmet with your life- if you lose it, your sentience goes with it!"))
var/policy = get_policy(ROLE_MONKEY_HELMET)
diff --git a/code/modules/clothing/shoes/clown.dm b/code/modules/clothing/shoes/clown.dm
index aff47fde7fabe..76395a56efd5e 100644
--- a/code/modules/clothing/shoes/clown.dm
+++ b/code/modules/clothing/shoes/clown.dm
@@ -53,3 +53,9 @@
desc = "The adorable sound they make when you walk will mean making friends is more likely."
icon_state = "meown_shoes"
squeak_sound = list('sound/effects/footstep/meowstep1.ogg'=1) //mew mew mew mew
+
+/obj/item/clothing/shoes/clown_shoes/moffers
+ name = "moffers"
+ desc = "No moths were harmed in the making of these slippers."
+ icon_state = "moffers"
+ squeak_sound = list('sound/effects/footstep/moffstep01.ogg'=1) //like sweet music to my ears
diff --git a/code/modules/deathmatch/deathmatch_maps.dm b/code/modules/deathmatch/deathmatch_maps.dm
index d437bffbb3cd7..71d7e8a8651f4 100644
--- a/code/modules/deathmatch/deathmatch_maps.dm
+++ b/code/modules/deathmatch/deathmatch_maps.dm
@@ -1,6 +1,8 @@
/datum/lazy_template/deathmatch //deathmatch maps that have any possibility of the walls being destroyed should use indestructible walls, because baseturf moment
- var/name
map_dir = "_maps/map_files/Deathmatch"
+ place_on_top = TRUE
+ /// Map UI Name
+ var/name
/// Map Description
var/desc = ""
var/min_players = 2
diff --git a/code/modules/events/ghost_role/abductor.dm b/code/modules/events/ghost_role/abductor.dm
index 65fe4a142f5a6..dfa20885f0c29 100644
--- a/code/modules/events/ghost_role/abductor.dm
+++ b/code/modules/events/ghost_role/abductor.dm
@@ -14,7 +14,7 @@
fakeable = FALSE //Nothing to fake here
/datum/round_event/ghost_role/abductor/spawn_role()
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ABDUCTOR, role = ROLE_ABDUCTOR, pic_source = /obj/item/melee/baton/abductor, role_name_text = role_name)
+ var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ABDUCTOR, role = ROLE_ABDUCTOR, alert_pic = /obj/item/melee/baton/abductor, role_name_text = role_name, amount_to_pick = 2)
if(candidates.len < 2)
return NOT_ENOUGH_PLAYERS
diff --git a/code/modules/events/ghost_role/alien_infestation.dm b/code/modules/events/ghost_role/alien_infestation.dm
index f4078e52e6588..88e79fd7d60c3 100644
--- a/code/modules/events/ghost_role/alien_infestation.dm
+++ b/code/modules/events/ghost_role/alien_infestation.dm
@@ -62,7 +62,7 @@
message_admins("An event attempted to spawn an alien but no suitable vents were found. Shutting down.")
return MAP_ERROR
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, pic_source = /mob/living/carbon/alien/larva, role_name_text = role_name)
+ var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, alert_pic = /mob/living/carbon/alien/larva, role_name_text = role_name)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
diff --git a/code/modules/events/ghost_role/blob.dm b/code/modules/events/ghost_role/blob.dm
index 70640512699d4..8e83351f5c045 100644
--- a/code/modules/events/ghost_role/blob.dm
+++ b/code/modules/events/ghost_role/blob.dm
@@ -33,10 +33,10 @@
blob_icon.Blend("#9ACD32", ICON_MULTIPLY)
blob_icon.Blend(icon('icons/mob/nonhuman-player/blob.dmi', "blob_core_overlay"), ICON_OVERLAY)
var/image/blob_image = image(blob_icon)
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_BLOB, role = ROLE_BLOB, pic_source = blob_image, role_name_text = role_name)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_BLOB, role = ROLE_BLOB, alert_pic = blob_image, role_name_text = role_name, amount_to_pick = 1, chat_text_border_icon = blob_image)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
- var/mob/dead/observer/new_blob = pick(candidates)
+ var/mob/dead/observer/new_blob = chosen_one
var/mob/camera/blob/BC = new_blob.become_overmind()
spawned_mobs += BC
message_admins("[ADMIN_LOOKUPFLW(BC)] has been made into a blob overmind by an event.")
diff --git a/code/modules/events/ghost_role/changeling_event.dm b/code/modules/events/ghost_role/changeling_event.dm
index 43b4ca48af57d..ce34aaa07fa95 100644
--- a/code/modules/events/ghost_role/changeling_event.dm
+++ b/code/modules/events/ghost_role/changeling_event.dm
@@ -21,12 +21,9 @@
fakeable = FALSE
/datum/round_event/ghost_role/changeling/spawn_role()
- var/list/mob/dead/observer/candidate = SSpolling.poll_ghost_candidates(check_jobban = ROLE_CHANGELING, role = ROLE_CHANGELING_MIDROUND, pic_source = /obj/item/melee/arm_blade, role_name_text = role_name)
-
- if(!candidate.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_CHANGELING, role = ROLE_CHANGELING_MIDROUND, alert_pic = /obj/item/melee/arm_blade, role_name_text = role_name, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- spawned_mobs += generate_changeling_meteor(pick_n_take(candidate))
-
+ spawned_mobs += generate_changeling_meteor(chosen_one)
if(spawned_mobs)
return SUCCESSFUL_SPAWN
diff --git a/code/modules/events/ghost_role/fugitive_event.dm b/code/modules/events/ghost_role/fugitive_event.dm
index 4b86e751c0b98..a09838ce473fb 100644
--- a/code/modules/events/ghost_role/fugitive_event.dm
+++ b/code/modules/events/ghost_role/fugitive_event.dm
@@ -20,7 +20,7 @@
if(isnull(landing_turf))
return MAP_ERROR
var/list/possible_backstories = list()
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_FUGITIVE, role = ROLE_FUGITIVE, pic_source = /obj/item/card/id/advanced/prisoner)
+ var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_FUGITIVE, role = ROLE_FUGITIVE, alert_pic = /obj/item/card/id/advanced/prisoner, jump_target = landing_turf)
if(!length(candidates))
return NOT_ENOUGH_PLAYERS
@@ -111,7 +111,7 @@
addtimer(CALLBACK(src, PROC_REF(check_spawn_hunters), backstory, remaining_time - 1 MINUTES), 1 MINUTES)
/datum/round_event/ghost_role/fugitives/proc/spawn_hunters(backstory)
- var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a group of [backstory]?", check_jobban = ROLE_FUGITIVE_HUNTER, pic_source = /obj/machinery/sleeper, role_name_text = backstory)
+ var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a group of [span_notice(backstory)]?", check_jobban = ROLE_FUGITIVE_HUNTER, alert_pic = /obj/machinery/sleeper, role_name_text = backstory)
shuffle_inplace(candidates)
var/datum/map_template/shuttle/hunter/ship
diff --git a/code/modules/events/ghost_role/morph_event.dm b/code/modules/events/ghost_role/morph_event.dm
index c9133863f8c0d..21d4b07873d86 100644
--- a/code/modules/events/ghost_role/morph_event.dm
+++ b/code/modules/events/ghost_role/morph_event.dm
@@ -13,13 +13,10 @@
role_name = "morphling"
/datum/round_event/ghost_role/morph/spawn_role()
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, pic_source = /mob/living/basic/morph, role_name_text = "morph")
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, alert_pic = /mob/living/basic/morph, role_name_text = "morph", amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/selected = pick_n_take(candidates)
-
- var/datum/mind/player_mind = new /datum/mind(selected.key)
+ var/datum/mind/player_mind = new /datum/mind(chosen_one.key)
player_mind.active = TRUE
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = FALSE)
diff --git a/code/modules/events/ghost_role/nightmare.dm b/code/modules/events/ghost_role/nightmare.dm
index ffb206c476dd1..d30108d94b984 100644
--- a/code/modules/events/ghost_role/nightmare.dm
+++ b/code/modules/events/ghost_role/nightmare.dm
@@ -15,13 +15,10 @@
fakeable = FALSE
/datum/round_event/ghost_role/nightmare/spawn_role()
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_NIGHTMARE, role_name_text = role_name)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_NIGHTMARE, role_name_text = role_name, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/selected = pick(candidates)
-
- var/datum/mind/player_mind = new /datum/mind(selected.key)
+ var/datum/mind/player_mind = new /datum/mind(chosen_one.key)
player_mind.active = TRUE
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE)
diff --git a/code/modules/events/ghost_role/operative.dm b/code/modules/events/ghost_role/operative.dm
index fcea52e3c023b..98cfe5ecad41e 100644
--- a/code/modules/events/ghost_role/operative.dm
+++ b/code/modules/events/ghost_role/operative.dm
@@ -12,20 +12,16 @@
fakeable = FALSE
/datum/round_event/ghost_role/operative/spawn_role()
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_OPERATIVE, role = ROLE_LONE_OPERATIVE, pic_source = /obj/machinery/nuclearbomb)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_OPERATIVE, role = ROLE_LONE_OPERATIVE, alert_pic = /obj/machinery/nuclearbomb, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/selected = pick_n_take(candidates)
-
var/spawn_location = find_space_spawn()
if(isnull(spawn_location))
return MAP_ERROR
-
var/mob/living/carbon/human/operative = new(spawn_location)
operative.randomize_human_appearance(~RANDOMIZE_SPECIES)
operative.dna.update_dna_identity()
- var/datum/mind/Mind = new /datum/mind(selected.key)
+ var/datum/mind/Mind = new /datum/mind(chosen_one.key)
Mind.set_assigned_role(SSjob.GetJobType(/datum/job/lone_operative))
Mind.special_role = ROLE_LONE_OPERATIVE
Mind.active = TRUE
diff --git a/code/modules/events/ghost_role/revenant_event.dm b/code/modules/events/ghost_role/revenant_event.dm
index 6cdfc2c4c9e5a..7af53b847c86d 100644
--- a/code/modules/events/ghost_role/revenant_event.dm
+++ b/code/modules/events/ghost_role/revenant_event.dm
@@ -30,14 +30,10 @@
message_admins("Event attempted to spawn a revenant, but there were only [deadMobs]/[REVENANT_SPAWN_THRESHOLD] dead mobs.")
return WAITING_FOR_SOMETHING
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_REVENANT, role = ROLE_REVENANT, pic_source = /mob/living/basic/revenant)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_REVENANT, role = ROLE_REVENANT, alert_pic = /mob/living/basic/revenant, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/observer/selected = pick_n_take(candidates)
-
var/list/spawn_locs = list()
-
for(var/mob/living/L in GLOB.dead_mob_list) //look for any dead bodies
var/turf/T = get_turf(L)
if(T && is_station_level(T.z))
@@ -50,16 +46,16 @@
if(!spawn_locs.len) //If we can't find any valid spawnpoints, try the carp spawns
spawn_locs += find_space_spawn()
if(!spawn_locs.len) //If we can't find either, just spawn the revenant at the player's location
- spawn_locs += get_turf(selected)
+ spawn_locs += get_turf(chosen_one)
if(!spawn_locs.len) //If we can't find THAT, then just give up and cry
return MAP_ERROR
var/mob/living/basic/revenant/revvie = new(pick(spawn_locs))
- revvie.key = selected.key
+ revvie.key = chosen_one.key
message_admins("[ADMIN_LOOKUPFLW(revvie)] has been made into a revenant by an event.")
revvie.log_message("was spawned as a revenant by an event.", LOG_GAME)
spawned_mobs += revvie
- qdel(selected)
+ qdel(chosen_one)
return SUCCESSFUL_SPAWN
#undef REVENANT_SPAWN_THRESHOLD
diff --git a/code/modules/events/ghost_role/sentience.dm b/code/modules/events/ghost_role/sentience.dm
index 8ebd30ad7b3e0..3aeebd298f43e 100644
--- a/code/modules/events/ghost_role/sentience.dm
+++ b/code/modules/events/ghost_role/sentience.dm
@@ -50,7 +50,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
/datum/round_event/ghost_role/sentience/spawn_role()
var/list/mob/dead/observer/candidates
- candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, pic_source = /obj/item/slimepotion/slime/sentience, role_name_text = role_name)
+ candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, alert_pic = /obj/item/slimepotion/slime/sentience, role_name_text = role_name)
// find our chosen mob to breathe life into
// Mobs have to be simple animals, mindless, on station, and NOT holograms.
diff --git a/code/modules/events/ghost_role/sentient_disease.dm b/code/modules/events/ghost_role/sentient_disease.dm
index 44f78d7c08cc7..156988d4b20d2 100644
--- a/code/modules/events/ghost_role/sentient_disease.dm
+++ b/code/modules/events/ghost_role/sentient_disease.dm
@@ -13,14 +13,11 @@
role_name = "sentient disease"
/datum/round_event/ghost_role/sentient_disease/spawn_role()
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, pic_source = /obj/structure/sign/warning/biohazard, role_name_text = role_name)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, alert_pic = /obj/structure/sign/warning/biohazard, role_name_text = role_name, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/observer/selected = pick_n_take(candidates)
-
var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center())
- virus.key = selected.key
+ virus.key = chosen_one.key
INVOKE_ASYNC(virus, TYPE_PROC_REF(/mob/camera/disease, pick_name))
message_admins("[ADMIN_LOOKUPFLW(virus)] has been made into a sentient disease by an event.")
virus.log_message("was spawned as a sentient disease by an event.", LOG_GAME)
diff --git a/code/modules/events/ghost_role/slaughter_event.dm b/code/modules/events/ghost_role/slaughter_event.dm
index f4628344d2f5b..2ea86551b799c 100644
--- a/code/modules/events/ghost_role/slaughter_event.dm
+++ b/code/modules/events/ghost_role/slaughter_event.dm
@@ -16,13 +16,10 @@
role_name = "slaughter demon"
/datum/round_event/ghost_role/slaughter/spawn_role()
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, pic_source = /mob/living/basic/demon/slaughter, role_name_text = role_name)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, alert_pic = /mob/living/basic/demon/slaughter, role_name_text = role_name, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/selected = pick_n_take(candidates)
-
- var/datum/mind/player_mind = new /datum/mind(selected.key)
+ var/datum/mind/player_mind = new /datum/mind(chosen_one.key)
player_mind.active = TRUE
var/spawn_location = find_space_spawn()
diff --git a/code/modules/events/ghost_role/space_dragon.dm b/code/modules/events/ghost_role/space_dragon.dm
index 0a328f6dc8d8c..8a39d4a5daea5 100644
--- a/code/modules/events/ghost_role/space_dragon.dm
+++ b/code/modules/events/ghost_role/space_dragon.dm
@@ -19,20 +19,14 @@
priority_announce("A large organic energy flux has been recorded near [station_name()], please stand by.", "Lifesign Alert")
/datum/round_event/ghost_role/space_dragon/spawn_role()
-
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_SPACE_DRAGON, role = ROLE_SPACE_DRAGON, pic_source = /mob/living/basic/space_dragon)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_SPACE_DRAGON, role = ROLE_SPACE_DRAGON, alert_pic = /mob/living/basic/space_dragon, amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/selected = pick(candidates)
- var/key = selected.key
-
var/spawn_location = find_space_spawn()
if(isnull(spawn_location))
return MAP_ERROR
-
- var/mob/living/basic/space_dragon/dragon = new (spawn_location)
- dragon.key = key
+ var/mob/living/basic/space_dragon/dragon = new(spawn_location)
+ dragon.key = chosen_one.key
dragon.mind.add_antag_datum(/datum/antagonist/space_dragon)
playsound(dragon, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
message_admins("[ADMIN_LOOKUPFLW(dragon)] has been made into a Space Dragon by an event.")
diff --git a/code/modules/events/ghost_role/space_ninja.dm b/code/modules/events/ghost_role/space_ninja.dm
index ffa28e6e1c4f3..eaccbe3de39cb 100644
--- a/code/modules/events/ghost_role/space_ninja.dm
+++ b/code/modules/events/ghost_role/space_ninja.dm
@@ -19,16 +19,12 @@
return MAP_ERROR
//selecting a candidate player
- var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_NINJA, role = ROLE_NINJA, pic_source = /obj/item/energy_katana)
- if(!candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(check_jobban = ROLE_NINJA, role = ROLE_NINJA, alert_pic = /obj/item/energy_katana, jump_target = spawn_location, role_name_text = "space ninja", amount_to_pick = 1)
+ if(isnull(chosen_one))
return NOT_ENOUGH_PLAYERS
-
- var/mob/dead/selected_candidate = pick(candidates)
- var/key = selected_candidate.key
-
//spawn the ninja and assign the candidate
var/mob/living/carbon/human/ninja = create_space_ninja(spawn_location)
- ninja.key = key
+ ninja.key = chosen_one.key
ninja.mind.add_antag_datum(/datum/antagonist/ninja)
spawned_mobs += ninja
message_admins("[ADMIN_LOOKUPFLW(ninja)] has been made into a space ninja by an event.")
diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm
index 7eb89e84bc06f..2d8a3bc549694 100644
--- a/code/modules/events/holiday/vday.dm
+++ b/code/modules/events/holiday/vday.dm
@@ -79,14 +79,15 @@
poll_time = 30 SECONDS,
flash_window = FALSE,
start_signed_up = TRUE,
- pic_source = /obj/item/storage/fancy/heart_box,
+ alert_pic = /obj/item/storage/fancy/heart_box,
custom_response_messages = list(
POLL_RESPONSE_SIGNUP = "You have signed up for a date!",
POLL_RESPONSE_ALREADY_SIGNED = "You are already signed up for a date.",
POLL_RESPONSE_NOT_SIGNED = "You aren't signed up for a date.",
POLL_RESPONSE_TOO_LATE_TO_UNREGISTER = "It's too late to decide against going on a date.",
- POLL_RESPONSE_UNREGISTERED = "You deicde against going on a date.",
+ POLL_RESPONSE_UNREGISTERED = "You decide against going on a date.",
),
+ chat_text_border_icon = /obj/item/storage/fancy/heart_box,
)
for(var/mob/living/second_check as anything in candidates_pruned)
diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index cad343f7debd9..20c4af94abdc3 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -84,11 +84,9 @@
priority_announce("Santa is coming to town!", "Unknown Transmission")
/datum/round_event/santa/start()
- var/list/candidates = SSpolling.poll_ghost_candidates("Santa is coming to town! Do you want to be Santa?", poll_time = 15 SECONDS, pic_source = /obj/item/clothing/head/costume/santa, role_name_text = "santa")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/C = pick(candidates)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates("Santa is coming to town! Do you want to be [span_notice("Santa")]?", poll_time = 15 SECONDS, alert_pic = /obj/item/clothing/head/costume/santa, role_name_text = "santa", amount_to_pick = 1)
+ if(chosen_one)
santa = new /mob/living/carbon/human(pick(GLOB.blobstart))
- santa.key = C.key
-
+ santa.key = chosen_one.key
var/datum/antagonist/santa/A = new
santa.mind.add_antag_datum(A)
diff --git a/code/modules/events/wizard/imposter.dm b/code/modules/events/wizard/imposter.dm
index 829942261427e..c2fb5472bdd82 100644
--- a/code/modules/events/wizard/imposter.dm
+++ b/code/modules/events/wizard/imposter.dm
@@ -13,20 +13,17 @@
if(!ishuman(M.current))
continue
var/mob/living/carbon/human/W = M.current
- var/list/candidates = SSpolling.poll_ghost_candidates("Would you like to be an imposter wizard?", check_jobban = ROLE_WIZARD, pic_source = /obj/item/clothing/head/wizard, role_name_text = "imposter wizard")
- if(!length(candidates))
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates("Would you like to be an [span_notice("imposter wizard")]?", check_jobban = ROLE_WIZARD, alert_pic = /obj/item/clothing/head/wizard, jump_target = W, role_name_text = "imposter wizard", amount_to_pick = 1)
+ if(isnull(chosen_one))
return //Sad Trombone
- var/mob/dead/observer/C = pick(candidates)
-
new /obj/effect/particle_effect/fluid/smoke(W.loc)
-
var/mob/living/carbon/human/I = new /mob/living/carbon/human(W.loc)
W.dna.transfer_identity(I, transfer_SE=1)
I.real_name = I.dna.real_name
I.name = I.dna.real_name
I.updateappearance(mutcolor_update=1)
I.domutcheck()
- I.key = C.key
+ I.key = chosen_one.key
var/datum/antagonist/wizard/master = M.has_antag_datum(/datum/antagonist/wizard)
if(!master.wiz_team)
master.create_wiz_team()
diff --git a/code/modules/food_and_drinks/plate.dm b/code/modules/food_and_drinks/plate.dm
index a0d24dec8dacb..1df1d7c24bb91 100644
--- a/code/modules/food_and_drinks/plate.dm
+++ b/code/modules/food_and_drinks/plate.dm
@@ -22,7 +22,7 @@
. = ..()
if(fragile)
- AddElement(/datum/element/shatters_when_thrown)
+ AddElement(/datum/element/can_shatter)
/obj/item/plate/attackby(obj/item/I, mob/user, params)
if(!IS_EDIBLE(I))
diff --git a/code/modules/hallucination/fake_alert.dm b/code/modules/hallucination/fake_alert.dm
index 537f6e294909a..6e10daf73aa97 100644
--- a/code/modules/hallucination/fake_alert.dm
+++ b/code/modules/hallucination/fake_alert.dm
@@ -63,10 +63,6 @@
alert_category = ALERT_TOO_MUCH_CO2
alert_type = /atom/movable/screen/alert/too_much_co2
-/datum/hallucination/fake_alert/nutrition
- alert_category = ALERT_NUTRITION
- alert_type = list(/atom/movable/screen/alert/fat, /atom/movable/screen/alert/starving)
-
/datum/hallucination/fake_alert/gravity
alert_category = ALERT_GRAVITY
alert_type = /atom/movable/screen/alert/weightless
diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm
index f41f607dabe12..24e5274f7fbfe 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -456,8 +456,8 @@
/datum/holiday/france/greet()
return "Do you hear the people sing?"
-/datum/holiday/hotdogday //I have plans for this.
- name = "National Hot Dog Day"
+/datum/holiday/hotdogday
+ name = HOTDOG_DAY
begin_day = 17
begin_month = JULY
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 19b8a17ec04d5..b10a784779d6e 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -114,9 +114,12 @@
/// String. If set to a non-empty one, it will be the key for the policy text value to show this role on spawn.
var/policy_index = ""
- ///RPG job names, for the memes
+ /// RPG job names, for the memes
var/rpg_title
+ /// Alternate titles to register as pointing to this job.
+ var/list/alternate_titles
+
/// Does this job ignore human authority?
var/ignore_human_authority = FALSE
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index 2be7bba5154d4..26a43fa775192 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -46,6 +46,9 @@
)
rpg_title = "Tavern Chef"
+ alternate_titles = list(
+ JOB_CHEF,
+ )
job_flags = STATION_JOB_FLAGS
/datum/job/cook/award_service(client/winner, award)
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 35a3a218f7b1a..4fb52ec77a026 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -38,6 +38,12 @@
/obj/item/melee/baton/security/boomerang/loaded = 1
)
rpg_title = "Guard"
+ alternate_titles = list(
+ JOB_SECURITY_OFFICER_MEDICAL,
+ JOB_SECURITY_OFFICER_ENGINEERING,
+ JOB_SECURITY_OFFICER_SUPPLY,
+ JOB_SECURITY_OFFICER_SCIENCE,
+ )
job_flags = STATION_JOB_FLAGS
diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm
index 6a5d1b1d5c4e4..656c90d77bbda 100644
--- a/code/modules/library/bibles.dm
+++ b/code/modules/library/bibles.dm
@@ -77,30 +77,24 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
unique = TRUE
/// Deity this bible is related to
var/deity_name = "Space Jesus"
- /// Component which catches bullets for us
- var/datum/component/bullet_catcher
/obj/item/book/bible/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE_HOLY)
- bullet_catcher = AddComponent(\
+ AddComponent(\
/datum/component/bullet_intercepting,\
active_slots = ITEM_SLOT_SUITSTORE,\
on_intercepted = CALLBACK(src, PROC_REF(on_intercepted_bullet)),\
+ block_charges = 1,\
)
- carve_out()
-
-/obj/item/book/bible/Destroy(force)
- QDEL_NULL(bullet_catcher)
- return ..()
/// Destroy the bible when it's shot by a bullet
/obj/item/book/bible/proc/on_intercepted_bullet(mob/living/victim, obj/projectile/bullet)
victim.add_mood_event("blessing", /datum/mood_event/blessing)
playsound(victim, 'sound/magic/magic_block_holy.ogg', 50, TRUE)
- victim.visible_message(span_warning("\The [src] takes \the [bullet] in [victim]'s place!"))
+ victim.visible_message(span_warning("[src] takes [bullet] in [victim]'s place!"))
var/obj/structure/fluff/paper/stack/pages = new(get_turf(src))
- pages.dir = pick(GLOB.alldirs)
+ pages.setDir(pick(GLOB.alldirs))
name = "punctured bible"
desc = "A memento of good luck, or perhaps divine intervention?"
icon_state = "shot"
@@ -108,7 +102,6 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
GLOB.bible_icon_state = "shot" // New symbol of your religion if you hadn't picked one
atom_storage?.remove_all(get_turf(src))
QDEL_NULL(atom_storage)
- QDEL_NULL(bullet_catcher)
/obj/item/book/bible/examine(mob/user)
. = ..()
@@ -345,6 +338,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
/obj/item/book/bible/booze/Initialize(mapload)
. = ..()
+ carve_out()
new /obj/item/reagent_containers/cup/glass/bottle/whiskey(src)
/obj/item/book/bible/syndicate
diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm b/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm
index 20210d56cc95c..8a2949f98935e 100644
--- a/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm
+++ b/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm
@@ -33,6 +33,10 @@
new_replica.name = "[appearance_object.name][obvious_replica ? " replica" : ""]"
new_replica.desc = "[appearance_object.desc][obvious_replica ? " ..except this one is a replica.": ""]"
+
+ new_replica.pixel_y = pixel_y
+ new_replica.pixel_x = pixel_x
+
qdel(appearance_object)
qdel(src)
return INITIALIZE_HINT_QDEL
@@ -129,3 +133,68 @@
sometimes i can catch them moving
we should have never come here"}
+
+/obj/item/paper/fluff/museum/chefs_ultimatum
+ name = "old note"
+ default_raw_text = {"I messed it up big times.
+ I broke the button and now I'm stuck.
+ Anyway, I don't have the key on me. I flushed it down.
+ Hell knows where it's now, shit's like all linked together here."}
+
+/obj/item/paper/fluff/museum/numbers_on_walls
+ name = "reprimanding note"
+ default_raw_text = "Please refraim from writing the pass all over the place. I know you've the memory of a goldfish, but, like, just put it on a piece of paper, no?"
+
+/obj/effect/mob_spawn/corpse/human/skeleton/museum_chef
+ name = "Dead Museum Cafeteria Chef"
+ mob_name = "Nameless Chef"
+ outfit = /datum/outfit/museum_chef
+
+/datum/outfit/museum_chef
+ name = "Dead Museum Cafeteria Chef"
+ uniform = /obj/item/clothing/under/color/green
+ suit = /obj/item/clothing/suit/toggle/chef
+ head = /obj/item/clothing/head/utility/chefhat
+ shoes = /obj/item/clothing/shoes/laceup
+ mask = /obj/item/clothing/mask/fakemoustache/italian
+
+/obj/machinery/vending/hotdog/museum
+ obj_flags = parent_type::obj_flags|NO_DECONSTRUCTION
+ onstation_override = TRUE
+
+#define CAFE_KEYCARD_TOILETS "museum_cafe_key_toilets"
+
+///Do not place these beyond the cafeteria shutters, or you might lock people out of reaching it.
+/obj/structure/toilet/museum
+
+/obj/structure/toilet/museum/Initialize(mapload)
+ . = ..()
+ if(mapload)
+ SSqueuelinks.add_to_queue(src, CAFE_KEYCARD_TOILETS)
+
+/obj/item/keycard/cafeteria
+ name = "museum cafeteria keycard"
+ color = COLOR_OLIVE
+ puzzle_id = "museum_cafeteria"
+ desc = "The key to the cafeteria, as the name implies."
+
+/obj/item/keycard/cafeteria/Initialize(mapload)
+ . = ..()
+ if(mapload)
+ SSqueuelinks.add_to_queue(src, CAFE_KEYCARD_TOILETS)
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/item/keycard/cafeteria/LateInitialize()
+ . = ..()
+ if(SSqueuelinks.queues[CAFE_KEYCARD_TOILETS])
+ SSqueuelinks.pop_link(CAFE_KEYCARD_TOILETS)
+
+/obj/item/keycard/cafeteria/MatchedLinks(id, partners)
+ if(id != CAFE_KEYCARD_TOILETS)
+ return ..()
+ var/obj/structure/toilet/destination = pick(partners)
+ forceMove(destination)
+ destination.w_items += w_class
+ destination.contents += src
+
+#undef CAFE_KEYCARD_TOILETS
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm b/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm
index 5647b5aca2382..0db718e399bf6 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm
@@ -76,12 +76,12 @@
SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED)
qdel(src)
-/obj/machinery/puzzle_button/meatderelict
+/obj/machinery/puzzle/button/meatderelict
name = "lockdown panel"
desc = "A panel that controls the lockdown of this outpost."
id = "md_prevault"
-/obj/machinery/puzzle_button/meatderelict/open_doors()
+/obj/machinery/puzzle/button/meatderelict/on_puzzle_complete()
. = ..()
playsound(src, 'sound/effects/alert.ogg', 100, TRUE)
visible_message(span_warning("[src] lets out an alarm as the lockdown is lifted!"))
@@ -121,7 +121,7 @@
/obj/lightning_thrower/Initialize(mapload)
. = ..()
- START_PROCESSING(SSprocessing, src)
+ START_PROCESSING(SSprocessing, src)
/obj/lightning_thrower/Destroy()
. = ..()
diff --git a/code/modules/mining/boulder_processing/_boulder_processing.dm b/code/modules/mining/boulder_processing/_boulder_processing.dm
index d7d4be2557e10..e7f599f5092d2 100644
--- a/code/modules/mining/boulder_processing/_boulder_processing.dm
+++ b/code/modules/mining/boulder_processing/_boulder_processing.dm
@@ -125,8 +125,10 @@
if(!anchored)
return FALSE
if(istype(mover, /obj/item/boulder))
- var/obj/item/boulder/boulder = mover
- return can_process_boulder(boulder)
+ return can_process_boulder(mover)
+ if(isgolem(mover))
+ var/mob/living/carbon/human/rockman = mover
+ return rockman.body_position == LYING_DOWN
return ..()
/**
@@ -140,7 +142,7 @@
SHOULD_BE_PURE(TRUE)
//machine not operational
- if(!anchored || panel_open || !is_operational || machine_stat & (BROKEN | NOPOWER))
+ if(!anchored || panel_open || !is_operational)
return FALSE
//not a valid boulder
@@ -177,13 +179,40 @@
return TRUE
+/**
+ * Accepts a golem to be processed, mainly for memes
+ */
+/obj/machinery/bouldertech/proc/accept_golem(mob/living/carbon/human/rockman)
+ if(!is_operational || !anchored)
+ return FALSE
+ if(!COOLDOWN_FINISHED(src, accept_cooldown))
+ return FALSE
+ if(rockman.body_position != LYING_DOWN)
+ return FALSE
+ if(!maim_golem(rockman))
+ return FALSE
+ playsound(src, usage_sound, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ COOLDOWN_START(src, accept_cooldown, 3 SECONDS)
+ return TRUE
+
+/// What effects actually happens to a golem when it is "processed"
+/obj/machinery/bouldertech/proc/maim_golem(mob/living/carbon/human/rockman)
+ Shake(duration = 1 SECONDS)
+ rockman.visible_message(span_warning("[rockman] is processed by [src]!"), span_userdanger("You get processed into bits by [src]!"))
+ rockman.investigate_log("was gibbed by [src] for being a golem", INVESTIGATE_DEATHS)
+ rockman.gib(DROP_ALL_REMAINS)
+ return TRUE
+
/obj/machinery/bouldertech/proc/on_entered(datum/source, atom/movable/atom_movable)
SIGNAL_HANDLER
- if(!can_process_boulder(atom_movable))
+ if(istype(atom_movable, /obj/item/boulder))
+ INVOKE_ASYNC(src, PROC_REF(accept_boulder), atom_movable)
return
- INVOKE_ASYNC(src, PROC_REF(accept_boulder), atom_movable)
+ if(isgolem(atom_movable))
+ INVOKE_ASYNC(src, PROC_REF(accept_golem), atom_movable)
+ return
/**
* Looks for a boost to the machine's efficiency, and applies it if found.
diff --git a/code/modules/mining/boulder_processing/refinery.dm b/code/modules/mining/boulder_processing/refinery.dm
index 662bb3e75e1e5..1e27bad1f0cde 100644
--- a/code/modules/mining/boulder_processing/refinery.dm
+++ b/code/modules/mining/boulder_processing/refinery.dm
@@ -85,3 +85,9 @@
/obj/machinery/bouldertech/refinery/smelter/on_set_is_operational(old_value)
set_light_on(TRUE)
+/obj/machinery/bouldertech/refinery/smelter/maim_golem(mob/living/carbon/human/rockman)
+ rockman.visible_message(span_warning("[rockman] is processed by [src]!"), span_userdanger("You get melted into rock by [src]!"))
+ rockman.investigate_log("was melted by [src] for being a golem", INVESTIGATE_DEATHS)
+ rockman.dust()
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), src, 'sound/machines/ding.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE), 2.5 SECONDS)
+ return TRUE
diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm
index 45c62ebd0a0d8..25240b0330fb3 100644
--- a/code/modules/mining/lavaland/megafauna_loot.dm
+++ b/code/modules/mining/lavaland/megafauna_loot.dm
@@ -422,13 +422,16 @@
using = TRUE
balloon_alert(user, "you hold the scythe up...")
ADD_TRAIT(src, TRAIT_NODROP, type)
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(on_poll_concluded), user)
- AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_POSSESSED_BLADE, \
- job_bans = ROLE_PAI, \
- to_call = to_call, \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ check_jobban = ROLE_PAI,
+ poll_time = 20 SECONDS,
+ checked_target = src,
+ ignore_category = POLL_IGNORE_POSSESSED_BLADE,
+ alert_pic = src,
+ role_name_text = "soulscythe soul",
+ chat_text_border_icon = src,
)
+ on_poll_concluded(user, chosen_one)
/// Ghost poll has concluded and a candidate has been chosen.
/obj/item/soulscythe/proc/on_poll_concluded(mob/living/master, mob/dead/observer/ghost)
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index 0b499f590d668..4fe26281b10a7 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -614,7 +614,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/coin/eldritch
name = "eldritch coin"
- desc = "Everytime it lands it bolts or opens doors, except for you."
+ desc = "A surprisingly heavy, ornate coin. Its sides seem to depict a different image each time you look."
icon_state = "coin_heretic"
custom_materials = list(/datum/material/diamond =HALF_SHEET_MATERIAL_AMOUNT, /datum/material/plasma =HALF_SHEET_MATERIAL_AMOUNT)
sideslist = list("heretic", "blade")
diff --git a/code/modules/mob/dead/observer/observer_movement.dm b/code/modules/mob/dead/observer/observer_movement.dm
index 9e156913a98a7..6972d3b265ff6 100644
--- a/code/modules/mob/dead/observer/observer_movement.dm
+++ b/code/modules/mob/dead/observer/observer_movement.dm
@@ -1,11 +1,17 @@
+/mob/dead/observer/down()
+ set name = "Move Down"
+ set category = "IC"
+
+ if(zMove(DOWN, z_move_flags = ZMOVE_FEEDBACK))
+ to_chat(src, span_notice("You move down."))
+
/mob/dead/observer/up()
set name = "Move Upwards"
set category = "IC"
if(zMove(UP, z_move_flags = ZMOVE_FEEDBACK))
- to_chat(src, "You move upwards.")
+ to_chat(src, span_notice("You move upwards."))
/mob/dead/observer/can_z_move(direction, turf/start, turf/destination, z_move_flags = NONE, mob/living/rider)
z_move_flags |= ZMOVE_IGNORE_OBSTACLES //observers do not respect these FLOORS you speak so much of.
return ..()
-
diff --git a/code/modules/mob/living/basic/guardian/guardian_creator.dm b/code/modules/mob/living/basic/guardian/guardian_creator.dm
index 3f1f092752217..441a60124a7bf 100644
--- a/code/modules/mob/living/basic/guardian/guardian_creator.dm
+++ b/code/modules/mob/living/basic/guardian/guardian_creator.dm
@@ -87,17 +87,18 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial())
used = TRUE
to_chat(user, use_message)
var/guardian_type_name = random ? "Random" : capitalize(initial(guardian_path.creator_name))
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(
- "Do you want to play as [user.real_name]'s [guardian_type_name] [mob_name]?",
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(
+ "Do you want to play as [span_danger("[user.real_name]'s")] [span_notice("[guardian_type_name] [mob_name]")]?",
check_jobban = ROLE_PAI,
poll_time = 10 SECONDS,
ignore_category = POLL_IGNORE_HOLOPARASITE,
- pic_source = src,
- role_name_text = "guardian spirit",
+ alert_pic = guardian_path,
+ jump_target = src,
+ role_name_text = guardian_type_name,
+ amount_to_pick = 1,
)
- if(LAZYLEN(candidates))
- var/mob/dead/observer/candidate = pick(candidates)
- spawn_guardian(user, candidate, guardian_path)
+ if(chosen_one)
+ spawn_guardian(user, chosen_one, guardian_path)
used = TRUE
SEND_SIGNAL(src, COMSIG_TRAITOR_ITEM_USED(type))
else
diff --git a/code/modules/mob/living/basic/guardian/guardian_verbs.dm b/code/modules/mob/living/basic/guardian/guardian_verbs.dm
index 2f40da369f82a..80a2af7db7a27 100644
--- a/code/modules/mob/living/basic/guardian/guardian_verbs.dm
+++ b/code/modules/mob/living/basic/guardian/guardian_verbs.dm
@@ -169,20 +169,18 @@
return FALSE
to_chat(owner, span_holoparasite("You attempt to reset [span_bold(chosen_guardian.real_name)]'s personality..."))
- var/list/mob/dead/observer/ghost_candidates = SSpolling.poll_ghost_candidates("Do you want to play as [owner.real_name]'s [chosen_guardian.theme.name]?", check_jobban = ROLE_PAI, poll_time = 10 SECONDS, pic_source = chosen_guardian, role_name_text = chosen_guardian.theme.name)
- if (!LAZYLEN(ghost_candidates))
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates("Do you want to play as [span_danger("[owner.real_name]'s")] [span_notice(chosen_guardian.theme.name)]?", check_jobban = ROLE_PAI, poll_time = 10 SECONDS, alert_pic = chosen_guardian, jump_target = owner, role_name_text = chosen_guardian.theme.name, amount_to_pick = 1)
+ if(isnull(chosen_one))
to_chat(owner, span_holoparasite("Your attempt to reset the personality of \
[span_bold(chosen_guardian.real_name)] appears to have failed... \
Looks like you're stuck with it for now."))
StartCooldown()
return FALSE
-
- var/mob/dead/observer/candidate = pick(ghost_candidates)
to_chat(chosen_guardian, span_holoparasite("Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance."))
to_chat(owner, span_boldholoparasite("The personality of [chosen_guardian.theme.name] has been successfully reset."))
- message_admins("[key_name_admin(candidate)] has taken control of ([ADMIN_LOOKUPFLW(chosen_guardian)])")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([ADMIN_LOOKUPFLW(chosen_guardian)])")
chosen_guardian.ghostize(FALSE)
- chosen_guardian.key = candidate.key
+ chosen_guardian.key = chosen_one.key
COOLDOWN_START(chosen_guardian, resetting_cooldown, 5 MINUTES)
chosen_guardian.guardian_rename() //give it a new color and name, to show it's a new person
chosen_guardian.guardian_recolour()
diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm
index 38e56f84c845e..e33cdcad1a1ea 100644
--- a/code/modules/mob/living/basic/ruin_defender/flesh.dm
+++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm
@@ -49,12 +49,12 @@
if(isnull(current_bodypart) || isnull(current_bodypart.owner))
return
var/mob/living/carbon/human/victim = current_bodypart.owner
- if(prob(SPT_PROB(3, SSMOBS_DT)))
+ if(SPT_PROB(3, SSMOBS_DT))
to_chat(victim, span_warning("The thing posing as your limb makes you feel funny...")) //warn em
//firstly as a sideeffect we drain nutrition from our host
victim.adjust_nutrition(-1.5)
- if(!prob(SPT_PROB(1.5, SSMOBS_DT)))
+ if(!SPT_PROB(1.5, SSMOBS_DT))
return
if(istype(current_bodypart, /obj/item/bodypart/arm))
diff --git a/code/modules/mob/living/basic/space_fauna/netherworld/migo.dm b/code/modules/mob/living/basic/space_fauna/netherworld/migo.dm
index 1be2a870de3ba..8decaccc73115 100644
--- a/code/modules/mob/living/basic/space_fauna/netherworld/migo.dm
+++ b/code/modules/mob/living/basic/space_fauna/netherworld/migo.dm
@@ -1,6 +1,6 @@
/mob/living/basic/migo
name = "mi-go"
- desc = "A pinkish, fungoid crustacean-like creature with numerous pairs of clawed appendages and a head covered with waving antennae."
+ desc = "A pinkish, fungoid crustacean-like creature with clawed appendages and a head covered with waving antennae."
icon_state = "mi-go"
icon_living = "mi-go"
icon_dead = "mi-go-dead"
@@ -36,6 +36,10 @@
/mob/living/basic/migo/Initialize(mapload)
. = ..()
migo_sounds = list('sound/items/bubblewrap.ogg', 'sound/items/change_jaws.ogg', 'sound/items/crowbar.ogg', 'sound/items/drink.ogg', 'sound/items/deconstruct.ogg', 'sound/items/carhorn.ogg', 'sound/items/change_drill.ogg', 'sound/items/dodgeball.ogg', 'sound/items/eatfood.ogg', 'sound/items/megaphone.ogg', 'sound/items/screwdriver.ogg', 'sound/items/weeoo1.ogg', 'sound/items/wirecutter.ogg', 'sound/items/welder.ogg', 'sound/items/zip.ogg', 'sound/items/rped.ogg', 'sound/items/ratchet.ogg', 'sound/items/polaroid1.ogg', 'sound/items/pshoom.ogg', 'sound/items/airhorn.ogg', 'sound/items/geiger/high1.ogg', 'sound/items/geiger/high2.ogg', 'sound/voice/beepsky/creep.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/ed209_20sec.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss6.ogg', 'sound/voice/medbot/patchedup.ogg', 'sound/voice/medbot/feelbetter.ogg', 'sound/voice/human/manlaugh1.ogg', 'sound/voice/human/womanlaugh.ogg', 'sound/weapons/sear.ogg', 'sound/ambience/antag/clockcultalr.ogg', 'sound/ambience/antag/ling_alert.ogg', 'sound/ambience/antag/tatoralert.ogg', 'sound/ambience/antag/monkey.ogg', 'sound/mecha/nominal.ogg', 'sound/mecha/weapdestr.ogg', 'sound/mecha/critdestr.ogg', 'sound/mecha/imag_enh.ogg', 'sound/effects/adminhelp.ogg', 'sound/effects/alert.ogg', 'sound/effects/attackblob.ogg', 'sound/effects/bamf.ogg', 'sound/effects/blobattack.ogg', 'sound/effects/break_stone.ogg', 'sound/effects/bubbles.ogg', 'sound/effects/bubbles2.ogg', 'sound/effects/clang.ogg', 'sound/effects/clockcult_gateway_disrupted.ogg', 'sound/effects/footstep/clownstep2.ogg', 'sound/effects/curse1.ogg', 'sound/effects/dimensional_rend.ogg', 'sound/effects/doorcreaky.ogg', 'sound/effects/empulse.ogg', 'sound/effects/explosion_distant.ogg', 'sound/effects/explosionfar.ogg', 'sound/effects/explosion1.ogg', 'sound/effects/grillehit.ogg', 'sound/effects/genetics.ogg', 'sound/effects/heart_beat.ogg', 'sound/runtime/hyperspace/hyperspace_begin.ogg', 'sound/runtime/hyperspace/hyperspace_end.ogg', 'sound/effects/his_grace_awaken.ogg', 'sound/effects/pai_boot.ogg', 'sound/effects/phasein.ogg', 'sound/effects/picaxe1.ogg', 'sound/effects/sparks1.ogg', 'sound/effects/smoke.ogg', 'sound/effects/splat.ogg', 'sound/effects/snap.ogg', 'sound/effects/tendril_destroyed.ogg', 'sound/effects/supermatter.ogg', 'sound/misc/desecration-01.ogg', 'sound/misc/desecration-02.ogg', 'sound/misc/desecration-03.ogg', 'sound/misc/bloblarm.ogg', 'sound/misc/airraid.ogg', 'sound/misc/bang.ogg','sound/misc/highlander.ogg', 'sound/misc/interference.ogg', 'sound/misc/notice1.ogg', 'sound/misc/notice2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/misc/slip.ogg', 'sound/misc/splort.ogg', 'sound/weapons/armbomb.ogg', 'sound/weapons/beam_sniper.ogg', 'sound/weapons/chainsawhit.ogg', 'sound/weapons/emitter.ogg', 'sound/weapons/emitter2.ogg', 'sound/weapons/blade1.ogg', 'sound/weapons/bladeslice.ogg', 'sound/weapons/blastcannon.ogg', 'sound/weapons/blaster.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/weapons/circsawhit.ogg', 'sound/weapons/cqchit2.ogg', 'sound/weapons/drill.ogg', 'sound/weapons/genhit1.ogg', 'sound/weapons/gun/pistol/shot_suppressed.ogg', 'sound/weapons/gun/pistol/shot.ogg', 'sound/weapons/handcuffs.ogg', 'sound/weapons/homerun.ogg', 'sound/weapons/kinetic_accel.ogg', 'sound/machines/clockcult/steam_whoosh.ogg', 'sound/machines/fryer/deep_fryer_emerge.ogg', 'sound/machines/airlock.ogg', 'sound/machines/airlock_alien_prying.ogg', 'sound/machines/airlockclose.ogg', 'sound/machines/airlockforced.ogg', 'sound/machines/airlockopen.ogg', 'sound/machines/alarm.ogg', 'sound/machines/blender.ogg', 'sound/machines/boltsdown.ogg', 'sound/machines/boltsup.ogg', 'sound/machines/buzz-sigh.ogg', 'sound/machines/buzz-two.ogg', 'sound/machines/chime.ogg', 'sound/machines/cryo_warning.ogg', 'sound/machines/defib_charge.ogg', 'sound/machines/defib_failed.ogg', 'sound/machines/defib_ready.ogg', 'sound/machines/defib_zap.ogg', 'sound/machines/deniedbeep.ogg', 'sound/machines/ding.ogg', 'sound/machines/disposalflush.ogg', 'sound/machines/door_close.ogg', 'sound/machines/door_open.ogg', 'sound/machines/engine_alert1.ogg', 'sound/machines/engine_alert2.ogg', 'sound/machines/hiss.ogg', 'sound/machines/honkbot_evil_laugh.ogg', 'sound/machines/juicer.ogg', 'sound/machines/ping.ogg', 'sound/ambience/signal.ogg', 'sound/machines/synth_no.ogg', 'sound/machines/synth_yes.ogg', 'sound/machines/terminal_alert.ogg', 'sound/machines/triple_beep.ogg', 'sound/machines/twobeep.ogg', 'sound/machines/ventcrawl.ogg', 'sound/machines/warning-buzzer.ogg', 'sound/ai/default/outbreak5.ogg', 'sound/ai/default/outbreak7.ogg', 'sound/ai/default/poweroff.ogg', 'sound/ai/default/radiation.ogg', 'sound/ai/default/shuttlecalled.ogg', 'sound/ai/default/shuttledock.ogg', 'sound/ai/default/shuttlerecalled.ogg', 'sound/ai/default/aimalf.ogg') //hahahaha fuck you code divers
+ if(prob(0.04)) //1 in 20 chance on-load mi-gos will spawn with a miku wig on.
+ base_icon_state = "mi-go-h"
+ name = "hatsune mi-go"
+ desc += " This one is wearing a bright blue wig."
AddElement(/datum/element/swabable, CELL_LINE_TABLE_NETHER, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 0)
AddComponent(/datum/component/health_scaling_effects, min_health_slowdown = -1.5, additional_status_callback = CALLBACK(src, PROC_REF(update_dodge_chance)))
@@ -71,3 +75,10 @@
. = Move(get_step(loc,pick(cdir, ccdir)))
if(!.)//Can't dodge there so we just carry on
. = Move(moving_to, move_direction)
+
+/mob/living/basic/migo/hatsune //Admin-spawnable variant of the miku mi-go.
+ name = "hatsune mi-go"
+ desc = "A pinkish, fungoid crustacean-like creature with clawed appendages and a head covered with waving antennae. This one is wearing a bright blue wig."
+ icon_state = "mi-go-h"
+ icon_living = "mi-go-h"
+ gold_core_spawnable = NO_SPAWN
diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm
index be83d3e058f91..51379ce88a0bc 100644
--- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm
+++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm
@@ -62,6 +62,7 @@
poll_ignore_key = POLL_IGNORE_REGAL_RAT,\
assumed_control_message = "You are an independent, invasive force on the station! Hoard coins, trash, cheese, and the like from the safety of darkness!",\
after_assumed_control = CALLBACK(src, PROC_REF(became_player_controlled)),\
+ poll_chat_border_icon = /obj/item/food/cheese/wedge,\
)
var/static/list/innate_actions = list(
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm
index 3ea62afd9f80d..40bad3b7981b9 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm
@@ -206,6 +206,12 @@
bot.bot_cover_flags &= ~BOT_COVER_LOCKED
bot.bot_cover_flags |= BOT_COVER_OPEN
bot.emag_act(caster)
+ for(var/mob/living/basic/bot/bot in victim)
+ if(!(bot.bot_access_flags & BOT_COVER_EMAGGED))
+ new /obj/effect/temp_visual/revenant(bot.loc)
+ bot.bot_access_flags |= BOT_CONTROL_PANEL_OPEN
+ bot.bot_access_flags |= BOT_MAINTS_PANEL_OPEN
+ bot.emag_act(caster)
for(var/mob/living/carbon/human/human in victim)
if(human == caster)
continue
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm
index ea153b03c063c..f8a3db0202a29 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm
@@ -86,21 +86,11 @@
/// Handles giving the revenant a new client to control it
/obj/item/ectoplasm/revenant/proc/get_new_user()
message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
- var/list/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to be [revenant.name] (reforming)?", check_jobban = ROLE_REVENANT, role = ROLE_REVENANT, poll_time = 5 SECONDS, target_mob = revenant, pic_source = revenant)
-
- if(!LAZYLEN(candidates))
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to be [span_notice(revenant.name)] (reforming)?", check_jobban = ROLE_REVENANT, role = ROLE_REVENANT, poll_time = 5 SECONDS, checked_target = revenant, alert_pic = revenant, role_name_text = "reforming revenant", chat_text_border_icon = revenant)
+ if(isnull(chosen_one))
message_admins("No candidates were found for the new revenant.")
inert = TRUE
visible_message(span_revenwarning("[src] settles down and seems lifeless."))
qdel(revenant)
return null
-
- var/mob/dead/observer/potential_client = pick(candidates)
- if(isnull(potential_client))
- qdel(revenant)
- message_admins("No candidate was found for the new revenant. Oh well!")
- inert = TRUE
- visible_message(span_revenwarning("[src] settles down and seems lifeless."))
- return null
-
- return potential_client
+ return chosen_one
diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm
index 56aacb11a9618..8682c8028e32e 100644
--- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm
+++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm
@@ -22,7 +22,7 @@
controller.clear_blackboard_key(target_key)
var/turf/our_turf = get_turf(spider)
- if (is_valid_web_turf(our_turf))
+ if (is_valid_web_turf(our_turf, spider))
controller.set_blackboard_key(target_key, our_turf)
finish_action(controller, succeeded = TRUE)
return
@@ -31,7 +31,7 @@
for (var/i in 1 to scan_range)
turfs_by_range["[i]"] = list()
for (var/turf/turf_in_view in oview(scan_range, our_turf))
- if (!is_valid_web_turf(turf_in_view))
+ if (!is_valid_web_turf(turf_in_view, spider))
continue
turfs_by_range["[get_dist(our_turf, turf_in_view)]"] += turf_in_view
diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm
index fa44cb35b2d12..5bb27b5109cbd 100644
--- a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm
+++ b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm
@@ -3,7 +3,7 @@
name = "Spin Web"
desc = "Spin a web to slow down potential prey."
button_icon = 'icons/mob/actions/actions_animal.dmi'
- button_icon_state = "lay_web"
+ button_icon_state = "spider_web"
background_icon_state = "bg_alien"
overlay_icon_state = "bg_alien_border"
cooldown_time = 0 SECONDS
@@ -17,10 +17,12 @@
. = ..()
if (!owner)
return
+ ADD_TRAIT(owner, TRAIT_WEB_WEAVER, REF(src))
RegisterSignals(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_DO_AFTER_BEGAN, COMSIG_DO_AFTER_ENDED), PROC_REF(update_status_on_signal))
/datum/action/cooldown/mob_cooldown/lay_web/Remove(mob/removed_from)
. = ..()
+ REMOVE_TRAIT(removed_from, TRAIT_WEB_WEAVER, REF(src))
UnregisterSignal(removed_from, list(COMSIG_MOVABLE_MOVED, COMSIG_DO_AFTER_BEGAN, COMSIG_DO_AFTER_ENDED))
/datum/action/cooldown/mob_cooldown/lay_web/IsAvailable(feedback = FALSE)
@@ -72,7 +74,7 @@
/// Variant for genetics, created webs only allow the creator passage
/datum/action/cooldown/mob_cooldown/lay_web/genetic
desc = "Spin a web. Only you will be able to traverse your web easily."
- cooldown_time = 4 SECONDS //the same time to lay a web
+ cooldown_time = 4 SECONDS
/datum/action/cooldown/mob_cooldown/lay_web/genetic/plant_web(turf/target_turf, obj/structure/spider/stickyweb/existing_web)
new /obj/structure/spider/stickyweb/genetic(target_turf, owner)
@@ -94,20 +96,20 @@
/datum/action/cooldown/mob_cooldown/lay_web/solid_web
name = "Spin Solid Web"
desc = "Spin a web to obstruct potential prey."
- button_icon_state = "lay_solid_web"
+ button_icon_state = "spider_wall"
cooldown_time = 0 SECONDS
webbing_time = 5 SECONDS
/datum/action/cooldown/mob_cooldown/lay_web/solid_web/obstructed_by_other_web()
- return !!(locate(/obj/structure/spider/solid) in get_turf(owner))
+ return !!(locate(/obj/structure/spider/stickyweb/sealed/tough) in get_turf(owner))
/datum/action/cooldown/mob_cooldown/lay_web/solid_web/plant_web(turf/target_turf, obj/structure/spider/stickyweb/existing_web)
- new /obj/structure/spider/solid(target_turf)
+ new /obj/structure/spider/stickyweb/sealed/tough(target_turf)
/datum/action/cooldown/mob_cooldown/lay_web/web_passage
name = "Spin Web Passage"
desc = "Spin a web passage to hide the nest from prey view."
- button_icon_state = "lay_web_passage"
+ button_icon_state = "spider_roof"
cooldown_time = 0 SECONDS
webbing_time = 4 SECONDS
@@ -120,20 +122,20 @@
/datum/action/cooldown/mob_cooldown/lay_web/sticky_web
name = "Spin Sticky Web"
desc = "Spin a sticky web to trap intruders."
- button_icon_state = "lay_sticky_web"
+ button_icon_state = "spider_ropes"
cooldown_time = 20 SECONDS
webbing_time = 3 SECONDS
/datum/action/cooldown/mob_cooldown/lay_web/sticky_web/obstructed_by_other_web()
- return !!(locate(/obj/structure/spider/sticky) in get_turf(owner))
+ return !!(locate(/obj/structure/spider/stickyweb/very_sticky) in get_turf(owner))
/datum/action/cooldown/mob_cooldown/lay_web/sticky_web/plant_web(turf/target_turf, obj/structure/spider/stickyweb/existing_web)
- new /obj/structure/spider/sticky(target_turf)
+ new /obj/structure/spider/stickyweb/very_sticky(target_turf)
/datum/action/cooldown/mob_cooldown/lay_web/web_spikes
name = "Spin Web Spikes"
desc = "Extrude silk spikes to dissuade invaders."
- button_icon_state = "lay_web_spikes"
+ button_icon_state = "spider_spikes"
cooldown_time = 40 SECONDS
webbing_time = 3 SECONDS
@@ -174,12 +176,12 @@
/datum/action/cooldown/mob_cooldown/lay_web/web_reflector
name = "Spin reflective silk screen"
desc = "Spin a web to reflect missiles from the nest."
- button_icon_state = "lay_web_reflector"
+ button_icon_state = "spider_mirror"
cooldown_time = 30 SECONDS
webbing_time = 4 SECONDS
/datum/action/cooldown/mob_cooldown/lay_web/web_reflector/obstructed_by_other_web()
- return !!(locate(/obj/structure/spider/reflector) in get_turf(owner))
+ return !!(locate(/obj/structure/spider/stickyweb/sealed/reflector) in get_turf(owner))
/datum/action/cooldown/mob_cooldown/lay_web/web_reflector/plant_web(turf/target_turf, obj/structure/spider/stickyweb/existing_web)
- new /obj/structure/spider/reflector(target_turf)
+ new /obj/structure/spider/stickyweb/sealed/reflector(target_turf)
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index eeb33bd3e891f..c7c4b1ed06f3e 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -90,15 +90,18 @@
return
bursting = TRUE
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(on_poll_concluded), gib_on_success)
- owner.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_ALIEN_LARVA, \
- job_bans = ROLE_ALIEN, \
- to_call = to_call, \
- custom_message = "An alien is bursting out of [owner.real_name]", \
- title = "alien larva" \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ question = "An [span_notice("alien")] is bursting out of [span_danger(owner.real_name)]!",
+ role = ROLE_ALIEN,
+ check_jobban = ROLE_ALIEN,
+ poll_time = 20 SECONDS,
+ checked_target = src,
+ ignore_category = POLL_IGNORE_ALIEN_LARVA,
+ alert_pic = owner,
+ role_name_text = "alien larva",
+ chat_text_border_icon = /mob/living/carbon/alien/larva,
)
+ on_poll_concluded(gib_on_success, chosen_one)
/// Poll has concluded with a suitor
/obj/item/organ/internal/body_egg/alien_embryo/proc/on_poll_concluded(gib_on_success, mob/dead/observer/ghost)
diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm
index d900706f102ac..cb35aebfb0770 100644
--- a/code/modules/mob/living/carbon/carbon_movement.dm
+++ b/code/modules/mob/living/carbon/carbon_movement.dm
@@ -8,14 +8,14 @@
/mob/living/carbon/Move(NewLoc, direct)
. = ..()
- if(. && !(movement_type & FLOATING)) //floating is easy
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- set_nutrition(NUTRITION_LEVEL_FED - 1) //just less than feeling vigorous
- else if(nutrition && stat != DEAD)
- adjust_nutrition(-(HUNGER_FACTOR/10))
- if(move_intent == MOVE_INTENT_RUN)
- adjust_nutrition(-(HUNGER_FACTOR/10))
-
+ if(!. || (movement_type & FLOATING)) //floating is easy
+ return
+ if(nutrition <= 0 || stat == DEAD)
+ return
+ var/hunger_loss = HUNGER_FACTOR / 10
+ if(move_intent == MOVE_INTENT_RUN)
+ hunger_loss *= 2
+ adjust_nutrition(-1 * hunger_loss)
/mob/living/carbon/set_usable_legs(new_value)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 29b4e1f0793d3..b20cb463c833b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -41,10 +41,11 @@
/mob/living/carbon/human/proc/setup_mood()
if (CONFIG_GET(flag/disable_human_mood))
return
- if (isdummy(src))
- return
mob_mood = new /datum/mood(src)
+/mob/living/carbon/human/dummy/setup_mood()
+ return
+
/// This proc is for holding effects applied when a mob is missing certain organs
/// It is called very, very early in human init because all humans innately spawn with no organs and gain them during init
/// Gaining said organs removes these effects
@@ -987,16 +988,6 @@
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
-/mob/living/carbon/human/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- return FALSE
- return ..()
-
-/mob/living/carbon/human/set_nutrition(change) //Seriously fuck you oldcoders.
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- return FALSE
- return ..()
-
/mob/living/carbon/human/is_bleeding()
if(HAS_TRAIT(src, TRAIT_NOBLOOD))
return FALSE
diff --git a/code/modules/mob/living/carbon/human/init_signals.dm b/code/modules/mob/living/carbon/human/init_signals.dm
index 9a4a55bb7ac1f..89cf7e01ce6ff 100644
--- a/code/modules/mob/living/carbon/human/init_signals.dm
+++ b/code/modules/mob/living/carbon/human/init_signals.dm
@@ -5,6 +5,9 @@
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_DWARF), SIGNAL_REMOVETRAIT(TRAIT_DWARF)), PROC_REF(on_dwarf_trait))
RegisterSignal(src, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, PROC_REF(get_name_part))
+ RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)), PROC_REF(on_fat))
+ RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_NOHUNGER), SIGNAL_REMOVETRAIT(TRAIT_NOHUNGER)), PROC_REF(on_nohunger))
+
/// Gaining or losing [TRAIT_UNKNOWN] updates our name and our sechud
/mob/living/carbon/human/proc/on_unknown_trait(datum/source)
SIGNAL_HANDLER
@@ -38,3 +41,25 @@
if(name != voice_name)
voice_name += " (as [get_id_name("Unknown")])"
stored_name[NAME_PART_INDEX] = voice_name
+
+/mob/living/carbon/human/proc/on_fat(datum/source)
+ SIGNAL_HANDLER
+ hud_used?.hunger?.update_appearance()
+ mob_mood?.update_nutrition_moodlets()
+
+ if(HAS_TRAIT(src, TRAIT_FAT))
+ add_movespeed_modifier(/datum/movespeed_modifier/obesity)
+ else
+ remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
+
+/mob/living/carbon/human/proc/on_nohunger(datum/source)
+ SIGNAL_HANDLER
+ // When gaining NOHUNGER, we restore nutrition to normal levels, since we no longer interact with the hunger system
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER))
+ set_nutrition(NUTRITION_LEVEL_FED, forced = TRUE)
+ satiety = 0
+ overeatduration = 0
+ REMOVE_TRAIT(src, TRAIT_FAT, OBESITY)
+ else
+ hud_used?.hunger?.update_appearance()
+ mob_mood?.update_nutrition_moodlets()
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 1eae13b0a5b28..f3189491f5ae9 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -39,8 +39,6 @@
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
abductor_hud.show_to(C)
- C.set_safe_hunger_level()
-
/datum/species/abductor/on_species_loss(mob/living/carbon/C)
. = ..()
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
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 2c006d2e936b6..b7a6c532106ff 100644
--- a/code/modules/mob/living/carbon/human/species_types/android.dm
+++ b/code/modules/mob/living/carbon/human/species_types/android.dm
@@ -47,11 +47,6 @@
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/robot/android,
)
-/datum/species/android/on_species_gain(mob/living/carbon/C)
- . = ..()
- // Androids don't eat, hunger or metabolise foods. Let's do some cleanup.
- C.set_safe_hunger_level()
-
/datum/species/android/get_physical_attributes()
return "Androids are almost, but not quite, identical to fully augmented humans. \
Unlike those, though, they're completely immune to toxin damage, don't have blood or organs (besides their head), don't get hungry, and can reattach their limbs! \
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 1407ba80f7553..1d7c328f88232 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -58,7 +58,6 @@
eyes.bodypart_insert(my_head)
human.update_body()
head.update_icon_dropped()
- human.set_safe_hunger_level()
RegisterSignal(head, COMSIG_QDELETING, PROC_REF(on_head_destroyed))
/// If we gained a new body part, it had better not be a head
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index 51f7426c6dfe9..3d45b2e735010 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -62,7 +62,6 @@
RegisterSignal(new_ethereal, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(refresh_light_color))
ethereal_light = new_ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species)
refresh_light_color(new_ethereal)
- new_ethereal.set_safe_hunger_level()
update_mail_goodies(new_ethereal)
var/obj/item/organ/internal/heart/ethereal/ethereal_heart = new_ethereal.get_organ_slot(ORGAN_SLOT_HEART)
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 ad6e36b527108..9bea2850617ba 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -60,10 +60,6 @@
/// If the bones themselves are burning clothes won't help you much
var/internal_fire = FALSE
-/datum/species/plasmaman/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
- . = ..()
- C.set_safe_hunger_level()
-
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired)
. = ..()
var/atmos_sealed = TRUE
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 a20e240529fb2..4718645b56346 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -44,10 +44,6 @@
BODY_ZONE_CHEST = /obj/item/bodypart/chest/skeleton,
)
-/datum/species/skeleton/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
- . = ..()
- C.set_safe_hunger_level()
-
/datum/species/skeleton/check_roundstart_eligible()
if(check_holidays(HALLOWEEN))
return TRUE
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 427f1f5f71bf9..2b14969f548cb 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -39,7 +39,6 @@
to_chat(new_vampire, "[info_text]")
new_vampire.skin_tone = "albino"
new_vampire.update_body(0)
- new_vampire.set_safe_hunger_level()
RegisterSignal(new_vampire, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
/datum/species/vampire/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 86f93a344c6f7..3738331e57b0a 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -497,7 +497,7 @@
log_message("points at [pointing_at]", LOG_EMOTE)
visible_message("[span_name("[src]")] points at [pointing_at].", span_notice("You point at [pointing_at]."))
-/mob/living/verb/succumb(whispered as null)
+/mob/living/verb/succumb(whispered as num|null)
set hidden = TRUE
if (!CAN_SUCCUMB(src))
if(HAS_TRAIT(src, TRAIT_SUCCUMB_OVERRIDE))
@@ -929,6 +929,8 @@
// I don't really care to keep this under a flag
set_nutrition(NUTRITION_LEVEL_FED + 50)
+ overeatduration = 0
+ satiety = 0
// These should be tracked by status effects
losebreath = 0
@@ -2327,27 +2329,6 @@ GLOBAL_LIST_EMPTY(fire_appearances)
/mob/living/carbon/human/will_escape_storage()
return TRUE
-/// Sets the mob's hunger levels to a safe overall level. Useful for TRAIT_NOHUNGER species changes.
-/mob/living/proc/set_safe_hunger_level()
- // Nutrition reset and alert clearing.
- nutrition = NUTRITION_LEVEL_FED
- clear_alert(ALERT_NUTRITION)
- satiety = 0
-
- // Trait removal if obese
- if(HAS_TRAIT_FROM(src, TRAIT_FAT, OBESITY))
- if(overeatduration >= (200 SECONDS))
- to_chat(src, span_notice("Your transformation restores your body's natural fitness!"))
-
- REMOVE_TRAIT(src, TRAIT_FAT, OBESITY)
- remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
- update_worn_undersuit()
- update_worn_oversuit()
-
- // Reset overeat duration.
- overeatduration = 0
-
-
/// Changes the value of the [living/body_position] variable. Call this before set_lying_angle()
/mob/living/proc/set_body_position(new_value)
if(body_position == new_value)
@@ -2598,10 +2579,9 @@ GLOBAL_LIST_EMPTY(fire_appearances)
if(isnull(guardian_client))
return
else if(guardian_client == "Poll Ghosts")
- var/list/candidates = SSpolling.poll_ghost_candidates("Do you want to play as an admin created Guardian Spirit of [real_name]?", check_jobban = ROLE_PAI, poll_time = 10 SECONDS, ignore_category = POLL_IGNORE_HOLOPARASITE, pic_source = src, role_name_text = "guardian spirit")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/candidate = pick(candidates)
- guardian_client = candidate.client
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates("Do you want to play as an admin created [span_notice("Guardian Spirit")] of [span_danger(real_name)]?", check_jobban = ROLE_PAI, poll_time = 10 SECONDS, ignore_category = POLL_IGNORE_HOLOPARASITE, alert_pic = mutable_appearance('icons/mob/nonhuman-player/guardian.dmi', "magicexample"), jump_target = src, role_name_text = "guardian spirit", amount_to_pick = 1)
+ if(chosen_one)
+ guardian_client = chosen_one.client
else
tgui_alert(admin, "No ghost candidates.", "Guardian Controller")
return
@@ -2648,3 +2628,20 @@ GLOBAL_LIST_EMPTY(fire_appearances)
end_look_down()
else
look_down()
+
+/**
+ * Totals the physical cash on the mob and returns the total.
+ */
+/mob/living/verb/tally_physical_credits()
+ //Here is all the possible non-ID payment methods.
+ var/list/counted_money = list()
+ var/physical_cash_total = 0
+ for(var/obj/item/credit as anything in typecache_filter_list(get_all_contents(), GLOB.allowed_money)) //Coins, cash, and credits.
+ physical_cash_total += credit.get_item_credit_value()
+ counted_money += credit
+
+ if(is_type_in_typecache(pulling, GLOB.allowed_money)) //Coins(Pulled).
+ var/obj/item/counted_credit = pulling
+ physical_cash_total += counted_credit.get_item_credit_value()
+ counted_money += counted_credit
+ return round(physical_cash_total)
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 6386fa272b7eb..e33578ecc550a 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
@@ -187,10 +187,10 @@ While using this makes the system rely on OnFire, it still gives options for tim
addtimer(CALLBACK(src, PROC_REF(spawn_elite)), 30)
return
visible_message(span_boldwarning("Something within [src] stirs..."))
- var/list/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as a lavaland elite?", check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, poll_time = 5 SECONDS, target_mob = src, ignore_category = POLL_IGNORE_LAVALAND_ELITE, pic_source = src, role_name_text = "lavaland elite")
- if(candidates.len)
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, poll_time = 5 SECONDS, checked_target = src, ignore_category = POLL_IGNORE_LAVALAND_ELITE, alert_pic = src, role_name_text = "lavaland elite")
+ if(chosen_one)
audible_message(span_boldwarning("The stirring sounds increase in volume!"))
- elitemind = pick(candidates)
+ elitemind = chosen_one
elitemind.playsound_local(get_turf(elitemind), 'sound/effects/magic.ogg', 40, 0)
to_chat(elitemind, "You have been chosen to play as a Lavaland Elite.\nIn a few seconds, you will be summoned on Lavaland as a monster to fight your activator, in a fight to the death.\n\
Your attacks can be switched using the buttons on the top left of the HUD, and used by clicking on targets or tiles similar to a gun.\n\
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 0085d0b2fb693..619ead060ba11 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1502,12 +1502,28 @@
get_language_holder().open_language_menu(usr)
///Adjust the nutrition of a mob
-/mob/proc/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
+/mob/proc/adjust_nutrition(change, forced = FALSE) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER) && !forced)
+ return
+
nutrition = max(0, nutrition + change)
+ hud_used?.hunger?.update_appearance()
+
+/mob/living/adjust_nutrition(change, forced)
+ . = ..()
+ mob_mood?.update_nutrition_moodlets()
///Force set the mob nutrition
-/mob/proc/set_nutrition(change) //Seriously fuck you oldcoders.
- nutrition = max(0, change)
+/mob/proc/set_nutrition(set_to, forced = FALSE) //Seriously fuck you oldcoders.
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER) && !forced)
+ return
+
+ nutrition = max(0, set_to)
+ hud_used?.hunger?.update_appearance()
+
+/mob/living/set_nutrition(set_to, forced)
+ . = ..()
+ mob_mood?.update_nutrition_moodlets()
///Apply a proper movespeed modifier based on items we have equipped
/mob/proc/update_equipment_speed_mods()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index d2b8ce0f3c380..7a8c993f26b0f 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -355,23 +355,22 @@
if(usr)
log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.")
message_admins("[key_name_admin(usr)] has offered control of ([ADMIN_LOOKUPFLW(M)]) to ghosts")
- var/poll_message = "Do you want to play as [M.real_name]?"
+ var/poll_message = "Do you want to play as [span_danger(M.real_name)]?"
if(M.mind)
- poll_message = "[poll_message] Job: [M.mind.assigned_role.title]."
+ poll_message = "[poll_message] Job: [span_notice(M.mind.assigned_role.title)]."
if(M.mind.special_role)
- poll_message = "[poll_message] Status: [M.mind.special_role]."
+ poll_message = "[poll_message] Status: [span_boldnotice(M.mind.special_role)]."
else
var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/)
if(A)
- poll_message = "[poll_message] Status: [A.name]."
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob(poll_message, check_jobban = ROLE_PAI, poll_time = 10 SECONDS, target_mob = M, pic_source = M, role_name_text = "ghost control")
+ poll_message = "[poll_message] Status: [span_boldnotice(A.name)]."
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(poll_message, check_jobban = ROLE_PAI, poll_time = 10 SECONDS, checked_target = M, alert_pic = M, role_name_text = "ghost control")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/C = pick(candidates)
+ if(chosen_one)
to_chat(M, "Your mob has been taken over by a ghost!")
- message_admins("[key_name_admin(C)] has taken control of ([ADMIN_LOOKUPFLW(M)])")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([ADMIN_LOOKUPFLW(M)])")
M.ghostize(FALSE)
- M.key = C.key
+ M.key = chosen_one.key
M.client?.init_verbs()
return TRUE
else
diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm
index 6d2a8a9850dc2..56cd102a59b8c 100644
--- a/code/modules/mob/mob_transformation_simple.dm
+++ b/code/modules/mob/mob_transformation_simple.dm
@@ -2,7 +2,7 @@
//This proc is the most basic of the procs. All it does is make a new mob on the same tile and transfer over a few variables.
//Returns the new mob
//Note that this proc does NOT do MMI related stuff!
-/mob/proc/change_mob_type(new_type = null, turf/location = null, new_name = null as text, delete_old_mob = FALSE)
+/mob/proc/change_mob_type(new_type = null, turf/location = null, new_name = null as text|null, delete_old_mob = FALSE)
if(isnewplayer(src))
to_chat(usr, span_danger("Cannot convert players who have not entered yet."))
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index ca82e13e803e6..28d89cf4cb4ae 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -184,11 +184,10 @@
to_chat(src, "You are job banned from cyborg! Appeal your job ban if you want to avoid this in the future!")
ghostize(FALSE)
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob("Do you want to play as [src]?", check_jobban = JOB_CYBORG, poll_time = 5 SECONDS, target_mob = src, pic_source = src, role_name_text = "cyborg")
- if(LAZYLEN(candidates))
- var/mob/dead/observer/chosen_candidate = pick(candidates)
- message_admins("[key_name_admin(chosen_candidate)] has taken control of ([key_name_admin(src)]) to replace a jobbanned player.")
- key = chosen_candidate.key
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_notice(src)]?", check_jobban = JOB_CYBORG, poll_time = 5 SECONDS, checked_target = src, alert_pic = src, role_name_text = "cyborg")
+ if(chosen_one)
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(src)]) to replace a jobbanned player.")
+ key = chosen_one.key
//human -> alien
/mob/living/carbon/human/proc/Alienize()
diff --git a/code/modules/mob_spawn/ghost_roles/spider_roles.dm b/code/modules/mob_spawn/ghost_roles/spider_roles.dm
index 8ab32d9d4f405..102a73d6f92f4 100644
--- a/code/modules/mob_spawn/ghost_roles/spider_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/spider_roles.dm
@@ -1,5 +1,6 @@
/obj/structure/spider/eggcluster
name = "egg cluster"
+ icon = 'icons/effects/effects.dmi'
desc = "There's something alive in there, and sooner or later it's going to find its way out."
icon_state = "eggs"
/// Mob spawner handling the actual spawn of the spider
diff --git a/code/modules/modular_computers/computers/item/disks/role_disks.dm b/code/modules/modular_computers/computers/item/disks/role_disks.dm
index da52ee76281a1..f7f20efb70b43 100644
--- a/code/modules/modular_computers/computers/item/disks/role_disks.dm
+++ b/code/modules/modular_computers/computers/item/disks/role_disks.dm
@@ -98,6 +98,7 @@
starting_programs = list(
/datum/computer_file/program/shipping,
/datum/computer_file/program/budgetorders,
+ /datum/computer_file/program/restock_tracker,
)
/**
@@ -123,6 +124,6 @@
/datum/computer_file/program/alarm_monitor,
/datum/computer_file/program/atmosscan,
/datum/computer_file/program/supermatter_monitor,
-
+
)
diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
index 205c6a0c422e5..a701d9fd4108d 100644
--- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm
+++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
@@ -114,6 +114,7 @@
/datum/computer_file/program/robocontrol,
/datum/computer_file/program/budgetorders,
/datum/computer_file/program/shipping,
+ /datum/computer_file/program/restock_tracker,
)
/**
@@ -264,6 +265,7 @@
/datum/computer_file/program/shipping,
/datum/computer_file/program/budgetorders,
/datum/computer_file/program/robocontrol,
+ /datum/computer_file/program/restock_tracker,
)
/obj/item/modular_computer/pda/shaftminer
diff --git a/code/modules/modular_computers/file_system/programs/restock_tracker.dm b/code/modules/modular_computers/file_system/programs/restock_tracker.dm
new file mode 100644
index 0000000000000..46462c0c6b531
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/restock_tracker.dm
@@ -0,0 +1,31 @@
+/datum/computer_file/program/restock_tracker
+ filename = "restockapp"
+ filedesc = "NT Restock Tracker"
+ downloader_category = PROGRAM_CATEGORY_SUPPLY
+ program_open_overlay = "restock"
+ extended_desc = "Nanotrasen IoT network listing all the vending machines found on station, and how well stocked they are each. Profitable!"
+ program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET
+ can_run_on_flags = PROGRAM_LAPTOP | PROGRAM_PDA
+ size = 4
+ program_icon = "cash-register"
+ tgui_id = "NtosRestock"
+
+/datum/computer_file/program/restock_tracker/ui_data()
+ var/list/data = list()
+ var/list/vending_list = list()
+ var/id_increment = 1
+ for(var/obj/machinery/vending/vendor as anything in GLOB.vending_machines_to_restock)
+ var/stock = vendor.total_loaded_stock()
+ var/max_stock = vendor.total_max_stock()
+ if((max_stock == 0 || (stock >= max_stock)) && vendor.credits_contained == 0)
+ continue
+ vending_list += list(list(
+ "name" = vendor.name,
+ "location" = get_area_name(vendor),
+ "credits" = vendor.credits_contained,
+ "percentage" = (stock / max_stock) * 100,
+ "id" = id_increment,
+ ))
+ id_increment++
+ data["vending_list"] = vending_list
+ return data
diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm
index 509eb4f05b90d..fc6b33f275785 100644
--- a/code/modules/power/apc/apc_attack.dm
+++ b/code/modules/power/apc/apc_attack.dm
@@ -221,7 +221,7 @@
return
stomach.drain_time = world.time + APC_DRAIN_TIME
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "draining power"), alert_timer_duration)
- if(do_after(user, APC_DRAIN_TIME, target = src))
+ while(do_after(user, APC_DRAIN_TIME, target = src))
if(cell.charge <= (cell.maxcharge / 2) || (stomach.crystal_charge > charge_limit))
return
balloon_alert(ethereal, "received charge")
@@ -243,9 +243,10 @@
balloon_alert(ethereal, "can't transfer power!")
return
if(istype(stomach))
- balloon_alert(ethereal, "transferred power")
- stomach.adjust_charge(-APC_POWER_GAIN)
- cell.give(APC_POWER_GAIN)
+ while(do_after(user, APC_DRAIN_TIME, target = src))
+ balloon_alert(ethereal, "transferred power")
+ stomach.adjust_charge(-APC_POWER_GAIN)
+ cell.give(APC_POWER_GAIN)
else
balloon_alert(ethereal, "can't transfer power!")
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index ec6c23b00c6f6..795ff6f099a74 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -246,7 +246,7 @@
return
to_chat(H, span_notice("You begin clumsily channeling power from [src] into your body."))
stomach.drain_time = world.time + CELL_DRAIN_TIME
- if(do_after(user, CELL_DRAIN_TIME, target = src))
+ while(do_after(user, CELL_DRAIN_TIME, target = src))
if((charge < CELL_POWER_DRAIN) || (stomach.crystal_charge > charge_limit))
return
if(istype(stomach))
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index ae91fb6c60318..e52d38b3da111 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -362,24 +362,23 @@
/obj/projectile/magic/wipe/proc/possession_test(mob/living/carbon/target)
var/datum/brain_trauma/special/imaginary_friend/trapped_owner/trauma = target.gain_trauma(/datum/brain_trauma/special/imaginary_friend/trapped_owner)
- var/poll_message = "Do you want to play as [target.real_name]?"
+ var/poll_message = "Do you want to play as [span_danger(target.real_name)]?"
if(target.mind)
- poll_message = "[poll_message] Job:[target.mind.assigned_role.title]."
+ poll_message = "[poll_message] Job:[span_notice(target.mind.assigned_role.title)]."
if(target.mind && target.mind.special_role)
- poll_message = "[poll_message] Status:[target.mind.special_role]."
+ poll_message = "[poll_message] Status:[span_boldnotice(target.mind.special_role)]."
else if(target.mind)
var/datum/antagonist/A = target.mind.has_antag_datum(/datum/antagonist/)
if(A)
- poll_message = "[poll_message] Status:[A.name]."
- var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob(poll_message, check_jobban = ROLE_PAI, poll_time = 10 SECONDS, target_mob = target, pic_source = target, role_name_text = "bolt of possession")
+ poll_message = "[poll_message] Status:[span_boldnotice(A.name)]."
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(poll_message, check_jobban = ROLE_PAI, poll_time = 10 SECONDS, checked_target = target, alert_pic = target, role_name_text = "bolt of possession")
if(target.stat == DEAD)//boo.
return
- if(LAZYLEN(candidates))
- var/mob/dead/observer/ghost = pick(candidates)
+ if(chosen_one)
to_chat(target, span_boldnotice("You have been noticed by a ghost and it has possessed you!"))
var/oldkey = target.key
target.ghostize(FALSE)
- target.key = ghost.key
+ target.key = chosen_one.key
trauma.friend.key = oldkey
trauma.friend.reset_perspective(null)
trauma.friend.Show()
diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
index 43430d0946916..c31b7e7079c97 100644
--- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
@@ -639,7 +639,7 @@
. = ..()
affected_mob.adjust_drowsiness(3 SECONDS * REM * seconds_per_tick)
var/need_mob_update
- switch(affected_mob.mob_mood.sanity_level)
+ switch(affected_mob.mob_mood.sanity)
if (SANITY_INSANE to SANITY_CRAZY)
need_mob_update = affected_mob.adjustStaminaLoss(3 * REM * seconds_per_tick, updating_stamina = FALSE)
if (SANITY_UNSTABLE to SANITY_DISTURBED)
diff --git a/code/modules/reagents/reagent_containers/condiment.dm b/code/modules/reagents/reagent_containers/condiment.dm
index bbd0a84504fac..e34511e9e0d0e 100644
--- a/code/modules/reagents/reagent_containers/condiment.dm
+++ b/code/modules/reagents/reagent_containers/condiment.dm
@@ -424,6 +424,7 @@
/datum/reagent/consumable/bbqsauce = list("condi_bbq", "BBQ sauce", "Hand wipes not included."),
/datum/reagent/consumable/peanut_butter = list("condi_peanutbutter", "Peanut Butter", "A creamy paste made from ground peanuts."),
/datum/reagent/consumable/cherryjelly = list("condi_cherryjelly", "Cherry Jelly", "A jar of super-sweet cherry jelly."),
+ /datum/reagent/consumable/mayonnaise = list("condi_mayo", "Mayonnaise", "Not an instrument."),
)
/// Can't use initial(name) for this. This stores the name set by condimasters.
var/originalname = "condiment"
@@ -516,3 +517,15 @@
originalname = "sugar"
volume = 5
list_reagents = list(/datum/reagent/consumable/sugar = 5)
+
+/obj/item/reagent_containers/condiment/pack/soysauce
+ name = "soy sauce pack"
+ originalname = "soy sauce"
+ volume = 5
+ list_reagents = list(/datum/reagent/consumable/soysauce = 5)
+
+/obj/item/reagent_containers/condiment/pack/mayonnaise
+ name = "mayonnaise pack"
+ originalname = "mayonnaise"
+ volume = 5
+ list_reagents = list(/datum/reagent/consumable/mayonnaise = 5)
diff --git a/code/modules/religion/sparring/sparring_datum.dm b/code/modules/religion/sparring/sparring_datum.dm
index bfaa94d65a8aa..78de2bd3a0bb0 100644
--- a/code/modules/religion/sparring/sparring_datum.dm
+++ b/code/modules/religion/sparring/sparring_datum.dm
@@ -301,4 +301,4 @@
return
to_chat(loser, span_userdanger("You've lost ownership over your soul to [winner]!"))
var/obj/item/soulstone/anybody/chaplain/sparring/shard = new(shard_turf)
- shard.capture_soul(loser, winner, forced = TRUE)
+ INVOKE_ASYNC(shard, TYPE_PROC_REF(/obj/item/soulstone, capture_soul), loser, winner, forced = TRUE)
diff --git a/code/modules/research/designs/autolathe/engineering_designs.dm b/code/modules/research/designs/autolathe/engineering_designs.dm
index 6249f5c645a1f..945966035f3d1 100644
--- a/code/modules/research/designs/autolathe/engineering_designs.dm
+++ b/code/modules/research/designs/autolathe/engineering_designs.dm
@@ -426,3 +426,29 @@
RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MOUNTS,
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
+
+/datum/design/tram_floor_dark
+ name = "Dark Tram Tile"
+ id = "tram_floor_dark"
+ build_type = PROTOLATHE
+ materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 0.25)
+ build_path = /obj/item/stack/thermoplastic
+ maxstack = 50
+ category = list(
+ RND_CATEGORY_INITIAL,
+ RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MATERIALS,
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
+
+/datum/design/tram_floor_light
+ name = "Light Tram Tile"
+ id = "tram_floor_light"
+ build_type = PROTOLATHE
+ materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 0.25)
+ build_path = /obj/item/stack/thermoplastic/light
+ maxstack = 50
+ category = list(
+ RND_CATEGORY_INITIAL,
+ RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MATERIALS,
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 66fb0a8caa3bd..c790784156dd1 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -121,6 +121,8 @@
"toy_armblade",
"toy_balloon",
"toygun",
+ "tram_floor_dark",
+ "tram_floor_light",
"trapdoor_electronics",
"turbine_part_compressor",
"turbine_part_rotor",
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 49f7bfa61f392..ba568c4bc74a7 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -688,7 +688,6 @@
desc = "A miraculous chemical mix that grants human like intelligence to living beings."
icon = 'icons/obj/medical/chemical.dmi'
icon_state = "potpink"
- var/list/not_interested = list()
var/being_used = FALSE
var/sentience_type = SENTIENCE_ORGANIC
@@ -704,16 +703,22 @@
if(!dumb_mob.compare_sentience_type(sentience_type)) // Will also return false if not a basic or simple mob, which are the only two we want anyway
balloon_alert(user, "invalid creature!")
return
-
+ var/potion_reason = tgui_input_text(user, "For what reason?", "Intelligence Potion", multiline = TRUE, timeout = 2 MINUTES)
+ if(isnull(potion_reason))
+ return
balloon_alert(user, "offering...")
being_used = TRUE
-
- var/datum/callback/to_call = CALLBACK(src, PROC_REF(on_poll_concluded), user, dumb_mob)
- dumb_mob.AddComponent(/datum/component/orbit_poll, \
- ignore_key = POLL_IGNORE_SENTIENCE_POTION, \
- job_bans = ROLE_SENTIENCE, \
- to_call = to_call, \
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ question = "[span_danger(user)] is offering [span_notice(dumb_mob)] an intelligence potion! Reason: [span_boldnotice(potion_reason)]",
+ check_jobban = ROLE_SENTIENCE,
+ poll_time = 20 SECONDS,
+ checked_target = dumb_mob,
+ ignore_category = POLL_IGNORE_SENTIENCE_POTION,
+ alert_pic = dumb_mob,
+ role_name_text = "intelligence potion",
+ chat_text_border_icon = src,
)
+ on_poll_concluded(user, dumb_mob, chosen_one)
/// Assign the chosen ghost to the mob
/obj/item/slimepotion/slime/sentience/proc/on_poll_concluded(mob/user, mob/living/dumb_mob, mob/dead/observer/ghost)
diff --git a/code/modules/shuttle/battlecruiser_starfury.dm b/code/modules/shuttle/battlecruiser_starfury.dm
index e95ff4243f5d4..a27cadacad2ec 100644
--- a/code/modules/shuttle/battlecruiser_starfury.dm
+++ b/code/modules/shuttle/battlecruiser_starfury.dm
@@ -135,7 +135,7 @@
*/
/proc/summon_battlecruiser(datum/team/battlecruiser/team)
- var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for battlecruiser crew?", check_jobban = ROLE_TRAITOR, pic_source = /obj/machinery/sleeper/syndie, role_name_text = "battlecruiser crew")
+ var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for [span_notice("battlecruiser crew")]?", check_jobban = ROLE_TRAITOR, alert_pic = /obj/machinery/sleeper/syndie, role_name_text = "battlecruiser crew")
shuffle_inplace(candidates)
var/datum/map_template/ship = SSmapping.map_templates["battlecruiser_starfury.dmm"]
diff --git a/code/modules/shuttle/shuttle_events/player_controlled.dm b/code/modules/shuttle/shuttle_events/player_controlled.dm
index 77fee390a6876..86d134f29f727 100644
--- a/code/modules/shuttle/shuttle_events/player_controlled.dm
+++ b/code/modules/shuttle/shuttle_events/player_controlled.dm
@@ -17,17 +17,12 @@
/// Attempt to grant control of a mob to ghosts before spawning it in. if spawn_anyway_if_no_player = TRUE, we spawn the mob even if there's no ghosts
/datum/shuttle_event/simple_spawner/player_controlled/proc/try_grant_ghost_control(spawn_type)
- var/list/candidates = SSpolling.poll_ghost_candidates(ghost_alert_string + " (Warning: you will not be able to return to your body!)", check_jobban = role_type, poll_time = 10 SECONDS, pic_source = spawn_type, role_name_text = "shot at shuttle")
-
- if(!candidates.len && !spawn_anyway_if_no_player)
+ var/mob/chosen_one = SSpolling.poll_ghost_candidates(ghost_alert_string + " (Warning: you will not be able to return to your body!)", check_jobban = role_type, poll_time = 10 SECONDS, alert_pic = spawn_type, role_name_text = "shot at shuttle", amount_to_pick = 1)
+ if(isnull(chosen_one) && !spawn_anyway_if_no_player)
return
-
var/mob/living/new_mob = new spawn_type (get_turf(get_spawn_turf()))
-
- if(candidates.len)
- var/mob/dead/observer/candidate = pick(candidates)
- new_mob.ckey = candidate.ckey
- post_spawn(new_mob)
+ new_mob.ckey = chosen_one.ckey
+ post_spawn(new_mob)
///BACK FOR REVENGE!!!
/datum/shuttle_event/simple_spawner/player_controlled/alien_queen
diff --git a/code/modules/spells/spell_types/shapeshift/_shape_status.dm b/code/modules/spells/spell_types/shapeshift/_shape_status.dm
index faa84835255a8..cffd9804ea588 100644
--- a/code/modules/spells/spell_types/shapeshift/_shape_status.dm
+++ b/code/modules/spells/spell_types/shapeshift/_shape_status.dm
@@ -189,6 +189,12 @@
// is no longer in control of the shapeshifted mob, such as mindswapping out of a shapeshift
if(!QDELETED(source_spell) && source_spell.owner == owner)
source_spell.Grant(caster_mob)
+ if(owner?.contents)
+ // Prevent round removal and consuming stuff when losing shapeshift
+ for(var/atom/movable/thing as anything in owner.contents)
+ if(thing == caster_mob)
+ continue
+ thing.forceMove(get_turf(owner))
for(var/datum/action/bodybound_action as anything in owner.actions)
if(bodybound_action.target != caster_mob)
diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm
index 6e985e26329b6..b055503c028b3 100644
--- a/code/modules/surgery/organs/internal/stomach/_stomach.dm
+++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm
@@ -128,16 +128,11 @@
if(human.overeatduration < (200 SECONDS))
to_chat(human, span_notice("You feel fit again!"))
REMOVE_TRAIT(human, TRAIT_FAT, OBESITY)
- human.remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
- human.update_worn_undersuit()
- human.update_worn_oversuit()
+
else
if(human.overeatduration >= (200 SECONDS))
to_chat(human, span_danger("You suddenly feel blubbery!"))
ADD_TRAIT(human, TRAIT_FAT, OBESITY)
- human.add_movespeed_modifier(/datum/movespeed_modifier/obesity)
- human.update_worn_undersuit()
- human.update_worn_oversuit()
// nutrition decrease and satiety
if (human.nutrition > 0 && human.stat != DEAD)
@@ -189,18 +184,6 @@
if(CONFIG_GET(flag/disable_human_mood))
handle_hunger_slowdown(human)
- // If we did anything more then just set and throw alerts here I would add bracketing
- // But well, it is all we do, so there's not much point bothering with it you get me?
- switch(nutrition)
- if(NUTRITION_LEVEL_FULL to INFINITY)
- human.throw_alert(ALERT_NUTRITION, /atom/movable/screen/alert/fat)
- if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
- human.clear_alert(ALERT_NUTRITION)
- if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
- human.throw_alert(ALERT_NUTRITION, /atom/movable/screen/alert/hungry)
- if(0 to NUTRITION_LEVEL_STARVING)
- human.throw_alert(ALERT_NUTRITION, /atom/movable/screen/alert/starving)
-
///for when mood is disabled and hunger should handle slowdowns
/obj/item/organ/internal/stomach/proc/handle_hunger_slowdown(mob/living/carbon/human/human)
var/hungry = (500 - human.nutrition) / 5 //So overeat would be 100 and default level would be 80
@@ -262,13 +245,16 @@
disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/disgusted)
disgusted.add_mood_event("disgust", /datum/mood_event/disgusted)
+/obj/item/organ/internal/stomach/Insert(mob/living/carbon/receiver, special, movement_flags)
+ . = ..()
+ receiver.hud_used?.hunger?.update_appearance()
+
/obj/item/organ/internal/stomach/Remove(mob/living/carbon/stomach_owner, special, movement_flags)
if(ishuman(stomach_owner))
var/mob/living/carbon/human/human_owner = owner
human_owner.clear_alert(ALERT_DISGUST)
human_owner.clear_mood_event("disgust")
- human_owner.clear_alert(ALERT_NUTRITION)
-
+ stomach_owner.hud_used?.hunger?.update_appearance()
return ..()
/obj/item/organ/internal/stomach/bone
diff --git a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm
index 68f9d9428a04a..9f268b41c178a 100644
--- a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm
+++ b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm
@@ -33,7 +33,7 @@
SIGNAL_HANDLER
adjust_charge(amount / 3.5)
-/obj/item/organ/internal/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
+/obj/item/organ/internal/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, shock_source, siemens_coeff = 1, flags = NONE)
SIGNAL_HANDLER
if(flags & SHOCK_ILLUSION)
return
diff --git a/code/modules/transport/tram/tram_floors.dm b/code/modules/transport/tram/tram_floors.dm
index 1e1fad836c3b2..9f0b6907fe9c1 100644
--- a/code/modules/transport/tram/tram_floors.dm
+++ b/code/modules/transport/tram/tram_floors.dm
@@ -255,7 +255,7 @@
span_notice("You wedge \the [tool] into the tram panel's gap in the frame and start prying..."))
if(tool.use_tool(src, user, 1 SECONDS, volume = 50))
to_chat(user, span_notice("The panel pops out of the frame."))
- var/obj/item/stack/thermoplastic/pulled_tile = new()
+ var/obj/item/stack/thermoplastic/pulled_tile = new floor_tile()
pulled_tile.update_integrity(atom_integrity)
user.put_in_hands(pulled_tile)
qdel(src)
@@ -283,8 +283,8 @@
icon = 'icons/obj/tiles.dmi'
lefthand_file = 'icons/mob/inhands/items/tiles_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/tiles_righthand.dmi'
- icon_state = "tile_textured_white_large"
- inhand_icon_state = "tile-neon-glow"
+ icon_state = "tile_tram_dark"
+ inhand_icon_state = "tile-tram"
color = COLOR_TRAM_BLUE
w_class = WEIGHT_CLASS_NORMAL
force = 1
@@ -297,7 +297,9 @@
var/tile_type = /obj/structure/thermoplastic
/obj/item/stack/thermoplastic/light
+ icon_state = "tile_tram_light"
color = COLOR_TRAM_LIGHT_BLUE
+ merge_type = /obj/item/stack/thermoplastic/light
tile_type = /obj/structure/thermoplastic/light
/obj/item/stack/thermoplastic/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1)
diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm
index 9fdfefc835cae..7fcfa53fba159 100644
--- a/code/modules/transport/transport_module.dm
+++ b/code/modules/transport/transport_module.dm
@@ -844,7 +844,6 @@
transport_id = TRANSPORT_TYPE_TRAM
transport_controller_type = /datum/transport_controller/linear/tram
radial_travel = FALSE
- obj_flags = NONE
/// Set by the tram control console in late initialize
var/travelling = FALSE
diff --git a/code/modules/unit_tests/antag_conversion.dm b/code/modules/unit_tests/antag_conversion.dm
index 01c05671ef72e..f499922bf8dbe 100644
--- a/code/modules/unit_tests/antag_conversion.dm
+++ b/code/modules/unit_tests/antag_conversion.dm
@@ -36,7 +36,7 @@
// Success state
leader.ClickOn(peasant)
- TEST_ASSERT(peasant.IsParalyzed(), "Peasant was not paralyzed after being flashed by the leader.") // Flash paralyze
+ TEST_ASSERT((peasant.get_timed_status_effect_duration(/datum/status_effect/confusion) > 0), "Peasant was not confused after being flashed by the leader.") // Flash confuse
TEST_ASSERT(peasant.IsStun(), "Peasant was not stunned after being converted by the leader.") // Conversion stun
TEST_ASSERT(IS_REVOLUTIONARY(peasant), "Peasant did not gain revolution antag datum on conversion.")
TEST_ASSERT_EQUAL(length(revolution.members), 2, "Expected revolution to have 2 members after the leader flashes the peasant.")
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index f101c5b2f7486..1ea898b63aac4 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -14,8 +14,12 @@
premium = list()
*/
+/// List of vending machines that players can restock, so only vending machines that are on station or don't have a unique condition.
+GLOBAL_LIST_EMPTY(vending_machines_to_restock)
+
/// Maximum amount of items in a storage bag that we're transferring items to the vendor from.
#define MAX_VENDING_INPUT_AMOUNT 30
+#define CREDITS_DUMP_THRESHOLD 50
/**
* # vending record datum
*
@@ -178,6 +182,8 @@
var/displayed_currency_name = " cr"
///Whether our age check is currently functional
var/age_restrictions = TRUE
+ /// How many credits does this vending machine have? 20% of all sales go to this pool, and are given freely when the machine is restocked, or successfully tilted. Lost on deconstruction.
+ var/credits_contained = 0
/**
* Is this item on station or not
*
@@ -256,6 +262,7 @@
onstation = FALSE
if(circuit)
circuit.onstation = onstation //sync up the circuit so the pricing schema is carried over if it's reconstructed.
+
else if(HAS_TRAIT(SSstation, STATION_TRAIT_VENDING_SHORTAGE))
for (var/datum/data/vending_product/product_record as anything in product_records + coin_records + hidden_records)
/**
@@ -264,16 +271,22 @@
*/
var/max_amount = rand(CEILING(product_record.amount * 0.5, 1), product_record.amount)
product_record.amount = rand(0, max_amount)
+ credits_contained += rand(0, 1) //randomly add a few credits to the machine to make it look like it's been used, proportional to the amount missing.
if(tiltable && prob(6)) // 1 in 17 chance to start tilted (as an additional hint to the station trait behind it)
INVOKE_ASYNC(src, PROC_REF(tilt), loc)
+ credits_contained = 0 // If it's tilted, it's been looted, so no credits for you.
else if(circuit && (circuit.onstation != onstation)) //check if they're not the same to minimize the amount of edited values.
onstation = circuit.onstation //if it was constructed outside mapload, sync the vendor up with the circuit's var so you can't bypass price requirements by moving / reconstructing it off station.
+ if(onstation && !onstation_override)
+ AddComponent(/datum/component/payment, 0, SSeconomy.get_dep_account(payment_department), PAYMENT_VENDING)
+ GLOB.vending_machines_to_restock += src //We need to keep track of the final onstation vending machines so we can keep them restocked.
/obj/machinery/vending/Destroy()
QDEL_NULL(wires)
QDEL_NULL(coin)
QDEL_NULL(bill)
QDEL_NULL(sec_radio)
+ GLOB.vending_machines_to_restock -= src
return ..()
/obj/machinery/vending/can_speak()
@@ -357,6 +370,7 @@
continue
var/obj/obj_to_dump = new dump_path(loc)
+ on_dispense(obj_to_dump)
step(obj_to_dump, pick(GLOB.alldirs))
found_anything = TRUE
dump_amount++
@@ -611,6 +625,24 @@
else //no category found - dump it into standard stock
products[record.product_path] = record.amount
+/**
+ * Returns the total amount of items in the vending machine based on the product records and premium records, but not contraband
+ */
+/obj/machinery/vending/proc/total_loaded_stock()
+ var/total = 0
+ for(var/datum/data/vending_product/record as anything in product_records + coin_records)
+ total += record.amount
+ return total
+
+/**
+ * Returns the total amount of items in the vending machine based on the product records and premium records, but not contraband
+ */
+/obj/machinery/vending/proc/total_max_stock()
+ var/total_max = 0
+ for(var/datum/data/vending_product/record as anything in product_records + coin_records)
+ total_max += record.max_amount
+ return total_max
+
/obj/machinery/vending/crowbar_act(mob/living/user, obj/item/attack_item)
if(!component_parts)
return FALSE
@@ -655,7 +687,11 @@
// instantiate canister if needed
var/transferred = restock(canister)
if(transferred)
- to_chat(user, span_notice("You loaded [transferred] items in [src]."))
+ to_chat(user, span_notice("You loaded [transferred] items in [src][credits_contained > 0 ? ", and are rewarded [credits_contained] credits." : "."]"))
+ var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ cargo_account.adjust_money(round(credits_contained * 0.5), "Vending: Restock")
+ var/obj/item/holochip/payday = new(src, credits_contained)
+ try_put_in_hand(payday, user)
else
to_chat(user, span_warning("There's nothing to restock!"))
return
@@ -707,7 +743,7 @@
* freebies - number of free items to vend
*/
/obj/machinery/vending/proc/freebie(freebies)
- visible_message(span_notice("[src] yields [freebies > 1 ? "several free goodies" : "a free goody"]!"))
+ visible_message(span_notice("[src] yields [freebies > 1 ? "several free goodies" : "a free goody"][credits_contained > 0 ? " and some credits" : ""]!"))
for(var/i in 1 to freebies)
playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3)
@@ -719,13 +755,15 @@
if(!dump_path)
continue
if(record.amount > LAZYLEN(record.returned_products)) //always give out new stuff that costs before free returned stuff, because of the risk getting gibbed involved
- new dump_path(get_turf(src))
+ var/obj/item/free_stuff = new dump_path(get_turf(src))
+ on_dispense(free_stuff)
else
var/obj/returned_obj_to_dump = LAZYACCESS(record.returned_products, LAZYLEN(record.returned_products)) //first in, last out
LAZYREMOVE(record.returned_products, returned_obj_to_dump)
returned_obj_to_dump.forceMove(get_turf(src))
record.amount--
break
+ deploy_credits()
/**
* Tilts ontop of the atom supplied, if crit is true some extra shit can happen. See [fall_and_crush] for return values.
@@ -1206,13 +1244,15 @@
/obj/machinery/vending/ui_data(mob/user)
. = list()
var/obj/item/card/id/card_used
+ var/held_cash = 0
if(isliving(user))
var/mob/living/living_user = user
card_used = living_user.get_idcard(TRUE)
+ held_cash = living_user.tally_physical_credits()
if(card_used?.registered_account)
.["user"] = list()
.["user"]["name"] = card_used.registered_account.account_holder
- .["user"]["cash"] = fetch_balance_to_use(card_used)
+ .["user"]["cash"] = fetch_balance_to_use(card_used) + held_cash
if(card_used.registered_account.account_job)
.["user"]["job"] = card_used.registered_account.account_job.title
.["user"]["department"] = card_used.registered_account.account_job.paycheck_department
@@ -1333,25 +1373,12 @@
vend_ready = TRUE
return
if(onstation)
+ // Here we do additional handing ahead of the payment component's logic, such as age restrictions and additional logging
var/obj/item/card/id/card_used
+ var/mob/living/living_user
if(isliving(usr))
- var/mob/living/living_user = usr
+ living_user = usr
card_used = living_user.get_idcard(TRUE)
- if(!card_used)
- speak("No card found.")
- flick(icon_deny,src)
- vend_ready = TRUE
- return
- else if (!card_used.registered_account)
- speak("No account found.")
- flick(icon_deny,src)
- vend_ready = TRUE
- return
- else if(!card_used.registered_account.account_job)
- speak("Departmental accounts have been blacklisted from personal expenses due to embezzlement.")
- flick(icon_deny, src)
- vend_ready = TRUE
- return
else if(age_restrictions && item_record.age_restricted && (!card_used.registered_age || card_used.registered_age < AGE_MINOR))
speak("You are not of legal age to purchase [item_record.name].")
if(!(usr in GLOB.narcd_underages))
@@ -1365,7 +1392,7 @@
vend_ready = TRUE
return
- if(!proceed_payment(card_used, item_record, price_to_use))
+ if(!proceed_payment(card_used, living_user, item_record, price_to_use))
return
if(last_shopper != REF(usr) || purchase_message_cooldown < world.time)
@@ -1381,6 +1408,7 @@
var/obj/item/vended_item
if(!LAZYLEN(item_record.returned_products)) //always give out free returned stuff first, e.g. to avoid walling a traitor objective in a bag behind paid items
vended_item = new item_record.product_path(get_turf(src))
+ on_dispense(vended_item)
else
vended_item = LAZYACCESS(item_record.returned_products, LAZYLEN(item_record.returned_products)) //first in, last out
LAZYREMOVE(item_record.returned_products, vended_item)
@@ -1395,6 +1423,10 @@
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[item_record.product_path]"))
vend_ready = TRUE
+///A proc meant to perform custom behavior on newly dispensed items.
+/obj/machinery/vending/proc/on_dispense(obj/item/vended_item)
+ return
+
/**
* Returns the balance that the vendor will use for proceeding payment. Most vendors would want to use the user's
* card's account credits balance.
@@ -1407,11 +1439,12 @@
/**
* Handles payment processing: discounts, logging, balance change etc.
* arguments:
- * paying_id_card - the id card that will be billed for the product
- * product_to_vend - the product record of the item we're trying to vend
- * price_to_use - price of the item we're trying to vend
+ * paying_id_card - the id card that will be billed for the product.
+ * mob_paying - the mob that is trying to purchase the item.
+ * product_to_vend - the product record of the item we're trying to vend.
+ * price_to_use - price of the item we're trying to vend.
*/
-/obj/machinery/vending/proc/proceed_payment(obj/item/card/id/paying_id_card, datum/data/vending_product/product_to_vend, price_to_use)
+/obj/machinery/vending/proc/proceed_payment(obj/item/card/id/paying_id_card, mob/living/mob_paying, datum/data/vending_product/product_to_vend, price_to_use)
var/datum/bank_account/account = paying_id_card.registered_account
if(account.account_job && account.account_job.paycheck_department == payment_department)
price_to_use = max(round(price_to_use * DEPARTMENT_DISCOUNT), 1) //No longer free, but signifigantly cheaper.
@@ -1419,7 +1452,7 @@
price_to_use = product_to_vend.custom_premium_price ? product_to_vend.custom_premium_price : extra_price
if(LAZYLEN(product_to_vend.returned_products))
price_to_use = 0 //returned items are free
- if(price_to_use && !account.adjust_money(-price_to_use, "Vending: [product_to_vend.name]"))
+ if(price_to_use && (attempt_charge(src, mob_paying, price_to_use) & COMPONENT_OBJ_CANCEL_CHARGE))
speak("You do not possess the funds to purchase [product_to_vend.name].")
flick(icon_deny,src)
vend_ready = TRUE
@@ -1427,10 +1460,10 @@
//actual payment here
var/datum/bank_account/paying_id_account = SSeconomy.get_dep_account(payment_department)
if(paying_id_account)
- paying_id_account.adjust_money(price_to_use)
SSblackbox.record_feedback("amount", "vending_spent", price_to_use)
SSeconomy.track_purchase(account, price_to_use, name)
log_econ("[price_to_use] credits were inserted into [src] by [account.account_holder] to buy [product_to_vend].")
+ credits_contained += round(price_to_use * 0.2)
return TRUE
/obj/machinery/vending/process(seconds_per_tick)
@@ -1569,6 +1602,15 @@
tilt(fatty=hit_atom)
return ..()
+/** Drop credits when the vendor is attacked.*/
+/obj/machinery/vending/proc/deploy_credits()
+ if(credits_contained <= 0)
+ return
+ var/credits_to_remove = min(CREDITS_DUMP_THRESHOLD, round(credits_contained))
+ var/obj/item/holochip/holochip = new(loc, credits_to_remove)
+ credits_contained = max(0, credits_contained - credits_to_remove)
+ SSblackbox.record_feedback("amount", "vending machine looted", holochip.credits)
+
/obj/machinery/vending/custom
name = "Custom Vendor"
icon_state = "custom"
diff --git a/code/modules/vending/assist.dm b/code/modules/vending/assist.dm
index 229b19aeadb99..a043a365046e2 100644
--- a/code/modules/vending/assist.dm
+++ b/code/modules/vending/assist.dm
@@ -21,6 +21,7 @@
/obj/item/assembly/timer = 2,
/obj/item/assembly/voice = 2,
/obj/item/stock_parts/cell/high = 1,
+ /obj/item/market_uplink/blackmarket = 1,
)
premium = list(
/obj/item/assembly/igniter/condenser = 2,
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 59bd06135bb83..2877a40334770 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -207,6 +207,7 @@
/obj/item/clothing/mask/muzzle = 2,
/obj/item/clothing/shoes/ducky_shoes = 1,
/obj/item/clothing/shoes/clown_shoes/meown_shoes = 1,
+ /obj/item/clothing/shoes/clown_shoes/moffers = 1,
/obj/item/clothing/suit/costume/judgerobe = 1,
/obj/item/clothing/head/costume/lobsterhat = 1,
/obj/item/clothing/under/costume/lobster = 1,
diff --git a/code/modules/vending/hotdog.dm b/code/modules/vending/hotdog.dm
new file mode 100644
index 0000000000000..094beccb41331
--- /dev/null
+++ b/code/modules/vending/hotdog.dm
@@ -0,0 +1,56 @@
+///A special hotdog vending machine found in the cafeteria at the museum away mission, or during the hotdog holiday.
+/obj/machinery/vending/hotdog
+ name = "\improper Hotdoggo-Vend"
+ desc = "An outdated hotdog vending machine, its prices stuck to those of 20 or so years ago."
+ icon_state = "hotdog-vendor"
+ icon_deny = "hotdog-vendor-deny"
+ panel_type = "panel17"
+ product_slogans = "Meatier than ever!;Now with 20% more MSG!;HOTDOGS!;Now Tirizan-friendly!"
+ product_ads = "Your best and only automatic hotdog dispenser!;Serving you the finest buns since 2469!;Comes in 12 different flavors!"
+ vend_reply = "Have a scrumptious meal!"
+ light_mask = "hotdog-vendor-light-mask"
+ default_price = PAYCHECK_LOWER
+ product_categories = list(
+ list(
+ "name" = "Hotdogs",
+ "icon" = "hotdog",
+ "products" = list(
+ /obj/item/food/hotdog = 8,
+ /obj/item/food/pigblanket = 4,
+ /obj/item/food/danish_hotdog = 4,
+ /obj/item/food/little_hawaii_hotdog = 4,
+ /obj/item/food/butterdog = 4,
+ /obj/item/food/plasma_dog_supreme = 2,
+ ),
+ ),
+ list(
+ name = "Sausages",
+ "icon" = FA_ICON_BACON,
+ "products" = list(
+ /obj/item/food/sausage = 8,
+ /obj/item/food/tiziran_sausage = 4,
+ /obj/item/food/fried_blood_sausage = 4,
+ ),
+ ),
+ list(
+ "name" = "Sauces",
+ "icon" = FA_ICON_BOWL_FOOD,
+ "products" = list(
+ /obj/item/reagent_containers/condiment/pack/ketchup = 4,
+ /obj/item/reagent_containers/condiment/pack/hotsauce = 4,
+ /obj/item/reagent_containers/condiment/pack/bbqsauce = 4,
+ /obj/item/reagent_containers/condiment/pack/soysauce = 4,
+ /obj/item/reagent_containers/condiment/pack/mayonnaise = 4,
+ ),
+ ),
+ )
+ refill_canister = /obj/item/vending_refill/hotdog
+
+/obj/item/vending_refill/hotdog
+ machine_name = "\improper Hotdoggo-Vend"
+ icon_state = "refill_snack"
+
+/// Cute little thing that sets it apart from the other food vending mahicnes. I mean, you don't find this every day.
+/obj/machinery/vending/hotdog/on_dispense(obj/item/vended_item)
+ if(istype(vended_item, /obj/item/food))
+ ADD_TRAIT(vended_item, TRAIT_FOOD_CHEF_MADE, VENDING_MACHINE_TRAIT)
diff --git a/code/modules/vending/sustenance.dm b/code/modules/vending/sustenance.dm
index d822912149087..a1d11c307277e 100644
--- a/code/modules/vending/sustenance.dm
+++ b/code/modules/vending/sustenance.dm
@@ -48,7 +48,7 @@
return
return ..()
-/obj/machinery/vending/sustenance/labor_camp/proceed_payment(obj/item/card/id/paying_id_card, datum/data/vending_product/product_to_vend, price_to_use)
+/obj/machinery/vending/sustenance/labor_camp/proceed_payment(obj/item/card/id/paying_id_card, mob/living/mob_paying, datum/data/vending_product/product_to_vend, price_to_use)
if(!istype(paying_id_card, /obj/item/card/id/advanced/prisoner))
speak("I don't take bribes! Pay with labor points!")
return FALSE
diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm
index 57bb2ed45cbb3..ed3b00c1194df 100644
--- a/code/modules/wiremod/shell/brain_computer_interface.dm
+++ b/code/modules/wiremod/shell/brain_computer_interface.dm
@@ -184,7 +184,7 @@
parent.cell.give(amount)
-/obj/item/circuit_component/bci_core/proc/on_electrocute(datum/source, shock_damage, siemens_coefficient, flags)
+/obj/item/circuit_component/bci_core/proc/on_electrocute(datum/source, shock_damage, shock_source, siemens_coefficient, flags)
SIGNAL_HANDLER
if (isnull(parent.cell))
diff --git a/html/changelogs/AutoChangeLog-pr-81373.yml b/html/changelogs/AutoChangeLog-pr-81373.yml
deleted file mode 100644
index db3985ce3712c..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81373.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Singul0"
-delete-after: True
-changes:
- - rscadd: "Adds a new changeling ability, \"Darkness Adaptation\". Making you more translucent, especially in darkness and allowing you to see slightly better in the dark"
- - balance: "The changeling power \"Chameleon Skin\" has been buffed, Reduces the cost to 1 and sped up the time it takes to turn invisible"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81582.yml b/html/changelogs/AutoChangeLog-pr-81582.yml
new file mode 100644
index 0000000000000..9896d82676599
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81582.yml
@@ -0,0 +1,9 @@
+author: "ArcaneMusic"
+delete-after: True
+changes:
+ - rscadd: "Vending machines now track how many credits have been spent on them, and when restocked will pay out that saved portion to the restocker, with a 50% match going to the cargo department."
+ - rscadd: "Adds the restock tracker app, an NTOS app that tracks how well stocked the station's vending machine units are at a glance as well as how much is contained in each."
+ - refactor: "Vending machines now use the payment component for money handling behavior, meaning it will now accept held or pulled coins/cash/credits"
+ - qol: "Attacking vending machines can drop a portion of it's stored credits, at the usual expected danger."
+ - balance: "Tweaked the cost of various restock modules up and down."
+ - qol: "Restock modules can now be sold for 50 credits."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81788.yml b/html/changelogs/AutoChangeLog-pr-81788.yml
new file mode 100644
index 0000000000000..08bbf8f2be17f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81788.yml
@@ -0,0 +1,4 @@
+author: "starrm4nn"
+delete-after: True
+changes:
+ - bugfix: "MetaStation Pharmacy is no longer accessible with general medical access, Also changes the Chemistry and Pharmacy airlocks into medical ones."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81831.yml b/html/changelogs/AutoChangeLog-pr-81831.yml
new file mode 100644
index 0000000000000..487682d231bd7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81831.yml
@@ -0,0 +1,4 @@
+author: "ValuedEmployee"
+delete-after: True
+changes:
+ - sound: "Added the new moffers sound effect and made moffers use it instead"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81846.yml b/html/changelogs/AutoChangeLog-pr-81846.yml
new file mode 100644
index 0000000000000..292e0f543ec29
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81846.yml
@@ -0,0 +1,4 @@
+author: "JohnFulpWillard"
+delete-after: True
+changes:
+ - image: "The minigames icon now has an icon for the deathmatch minigamee"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81855.yml b/html/changelogs/AutoChangeLog-pr-81855.yml
new file mode 100644
index 0000000000000..59f546df081ec
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81855.yml
@@ -0,0 +1,4 @@
+author: "2whatever2"
+delete-after: True
+changes:
+ - bugfix: "Tackle and wellcheers code for sanity values now function."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-03.yml b/html/changelogs/archive/2024-03.yml
index 9606cb4289941..2d6f65921df0a 100644
--- a/html/changelogs/archive/2024-03.yml
+++ b/html/changelogs/archive/2024-03.yml
@@ -68,3 +68,132 @@
xXPawnStarrXx:
- bugfix: makes custom pizzas dairy and vegetable free, unless you choose to add
them.
+2024-03-04:
+ LT3:
+ - image: Tram frame is now tram girder, because it acts like one
+ Melbert:
+ - bugfix: Fixed spy stolen machines not dumping everything that needed to be dumped
+ Nerev4r:
+ - qol: Ethereal charging now loops when they're charging (from) APCs or from power
+ cells!
+ Singul0:
+ - rscadd: Adds a new changeling ability, "Darkness Adaptation". Making you more
+ translucent, especially in darkness and allowing you to see slightly better
+ in the dark
+ - balance: The changeling power "Chameleon Skin" has been buffed, Reduces the cost
+ to 1 and sped up the time it takes to turn invisible
+ ViktorKoL:
+ - bugfix: made some heretic descriptions more accurate
+ - spellcheck: improved english of the heretical eldritch patrons
+ starrm4nn:
+ - bugfix: Makes Metastation surgery access more consistent with other maps
+2024-03-05:
+ DaliIsTaken:
+ - rscadd: added the lightbearer moth set, available in the character setup.
+ - image: added icons for the lightbearer set; new moth wings, antennae and markings.
+ LT3:
+ - bugfix: Tram floor tiles constructed inhand provides 4 instead of 1
+ - bugfix: Tram floor tiles provide correct stack item when pulled up
+ - image: Tram floor tiles have their own inhand icons
+ - qol: Tram floor tiles available in the engineering protolathe
+ - bugfix: You can reconstruct deconstructed tram benches
+ - image: medical and improvised gauze are visibly different from cloth
+ Rerik007:
+ - bugfix: fixed the chances of living flesh actions
+ Rhials:
+ - bugfix: Some tiny tiny changes to the smoking room ruin to make it a little less
+ ugly.
+ ValuedEmployee:
+ - rscadd: Added new clown shoes "moffers"
+ - rscadd: Added moffers to the contraband list of the autodrobe
+ ViktorKoL:
+ - bugfix: fixed some issues when calculating the duration of moon smile's effects
+ Zergspower:
+ - admin: renames ruin names to have an identifier in front of it
+ - refactor: converts map plate and jump to ruin to tguilist
+ mc-oofert:
+ - bugfix: fixes deathmatch baseturfs (you cant crowbar the floor to breach to space)
+2024-03-06:
+ KingkumaArt:
+ - rscadd: Shiny joke mi-go variant (not xenobio spawnable)
+ - rscdel: Removed unused mi-go static sprites
+ - image: Resprited mi-gos to not use plagarized art from CDDA
+ - image: Also allowed mi-gos to have directional facing instead of always facing
+ east
+ Melbert:
+ - rscadd: The animation that plays when an alert pops up on your screen is different.
+ - bugfix: Moving "down" as an observer is no longer janky.
+ - bugfix: All bibles are no longer suspiciously hollow
+ - bugfix: Extremely Minor Delta Morgue Fixes. See if you can spot them.
+ Seven:
+ - rscadd: Lockers and crates now shake when someone is attempting to resist out
+ of them.
+ SpaceLove:
+ - bugfix: Central Command Logistics department noticed the missing items on their
+ listings for robotics assembly crate. They have updated it!
+ Wallem:
+ - bugfix: The cursed coupon now only triggers a cursed event once, rather than infinite
+ times.
+ intercepti0n:
+ - bugfix: Pipe connector no longer appears on a hidden connector.
+ - bugfix: Re-wrenched atmospherics pipes no longer get extra offset.
+ - bugfix: All unary devices like injectors, passive vents etc. are centered while
+ hidden.
+ - image: Added smooth transition between hidden and visible pipes.
+2024-03-07:
+ 00-Steven:
+ - bugfix: Alternate job titles such as chef and department security actually get
+ injected to the manifest as their respective ID trims, instead of being assigned
+ the job they're based off.
+ - bugfix: Alternate job titles such as chef and department security actually show
+ up under the right department on the manifest, instead of no department.
+ 13spacemen:
+ - rscdel: Removed Orbit Polling component, all orbit polls now use the Poll Alerts
+ system
+ - code_imp: Poll alerts support small border pictures in the chat message
+ - code_imp: Poll alert alert picture and jump target do not have to be the same
+ - qol: Slime intelligence potions ask the user for a reason, this will be shown
+ to ghosts
+ ArcaneMusic:
+ - balance: The stock market now fires slower, has stock market events occur more
+ often, and the stock market has fewer minerals that are available to buy in
+ a single purchase before restocking.
+ - balance: Materials sold on the stock market may be protected from being bought
+ if their prices drop too low, so make sure you watch your prices before they
+ run the risk of getting shut out!
+ - balance: Stock blocks now freeze the price of materials for 3 minutes, down from
+ 5.
+ - qol: Tweaks to the Galactic Material Market UI, with materials sorted based on
+ their rarity and a timer to show how long until it updates.
+ - rscadd: New Stock market events, one locks a material from being purchased, the
+ other maximizes the value and quantity of a material for sale.
+ Hatterhat:
+ - bugfix: Basic mobs no longer have the (unintended) ability to shoot out of containers,
+ like bluespace body bags.
+ Higgin:
+ - balance: personal flashes now Knockdown rather than Paralyze direct targets.
+ Jacquerel:
+ - admin: Made it easier for admins to adjust blood brother teams using admin tools.
+ - bugfix: Correct blood brother conversion logging.
+ - bugfix: AI-controlled spiders can correctly recognise where they can place webs.
+ - image: New sprites for most kinds of spider web
+ Majkl-J:
+ - bugfix: Prevents polymorphing deleting items by consuming them when transformed
+ then leaving the polymorph
+ Melbert:
+ - refactor: Food hunger bar has been refactored, and moved. Now it sits next to
+ the moodlet face.
+ - refactor: Food moodlets now update a lot more snappily. There is now a moodlet
+ tier between "being fat" and "being normal", to reduce accidentally gorging
+ yourself to "fatness" tier.
+ - rscdel: You can't hallucinate being hungry... for now.
+ - rscadd: Boulder refineries and smelters can refine Golems.
+ ViktorKoL:
+ - image: 'added unique icons for spells: caretaker''s refuge, apetra vulnera and
+ ascended shapechange'
+ aaaa1023:
+ - bugfix: Revenants can now again emag Medibots, Cleanbots, and Hygienebots.
+ san7890:
+ - qol: If your OOC message gets eaten due to some weird circumstance in how your
+ message is handled, it will feed the applicable message back to you so you can
+ copy-paste and try to send it again.
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index d0734355c5e3f..50fe3e3b11af9 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/effects/web.dmi b/icons/effects/web.dmi
new file mode 100644
index 0000000000000..e21eb4d6ec34d
Binary files /dev/null and b/icons/effects/web.dmi differ
diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi
index 7aa32c94b8e2a..e1c5db84d22ae 100644
Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ
diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi
index 608be00b2e1fb..2f4dd60b5d7ce 100644
Binary files a/icons/hud/screen_gen.dmi and b/icons/hud/screen_gen.dmi differ
diff --git a/icons/hud/screen_ghost.dmi b/icons/hud/screen_ghost.dmi
index b58680f025df4..13255a2a16890 100644
Binary files a/icons/hud/screen_ghost.dmi and b/icons/hud/screen_ghost.dmi differ
diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi
index 64b1c700f414c..c13290716b75c 100644
Binary files a/icons/mob/actions/actions_animal.dmi and b/icons/mob/actions/actions_animal.dmi differ
diff --git a/icons/mob/actions/actions_ecult.dmi b/icons/mob/actions/actions_ecult.dmi
index ac7575d279b9e..c7744749abb97 100644
Binary files a/icons/mob/actions/actions_ecult.dmi and b/icons/mob/actions/actions_ecult.dmi differ
diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi
index 5bd3005ab8e58..612d82302e714 100644
Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ
diff --git a/icons/mob/human/species/moth/moth_antennae.dmi b/icons/mob/human/species/moth/moth_antennae.dmi
index 9a4d237cc3621..a40013e93576f 100644
Binary files a/icons/mob/human/species/moth/moth_antennae.dmi and b/icons/mob/human/species/moth/moth_antennae.dmi differ
diff --git a/icons/mob/human/species/moth/moth_markings.dmi b/icons/mob/human/species/moth/moth_markings.dmi
index 2429b0aa12dfe..a6ebc2cedb517 100644
Binary files a/icons/mob/human/species/moth/moth_markings.dmi and b/icons/mob/human/species/moth/moth_markings.dmi differ
diff --git a/icons/mob/human/species/moth/moth_wings.dmi b/icons/mob/human/species/moth/moth_wings.dmi
index 65b8fba38d9b9..91c0d8b2b2cd1 100644
Binary files a/icons/mob/human/species/moth/moth_wings.dmi and b/icons/mob/human/species/moth/moth_wings.dmi differ
diff --git a/icons/mob/inhands/items/tiles_lefthand.dmi b/icons/mob/inhands/items/tiles_lefthand.dmi
index b73ded0c82c54..6bbe621db829a 100644
Binary files a/icons/mob/inhands/items/tiles_lefthand.dmi and b/icons/mob/inhands/items/tiles_lefthand.dmi differ
diff --git a/icons/mob/inhands/items/tiles_righthand.dmi b/icons/mob/inhands/items/tiles_righthand.dmi
index 1d668c01f070c..4d1d5073c98d6 100644
Binary files a/icons/mob/inhands/items/tiles_righthand.dmi and b/icons/mob/inhands/items/tiles_righthand.dmi differ
diff --git a/icons/mob/simple/animal.dmi b/icons/mob/simple/animal.dmi
index 7fcf0e9d65e79..82943b798a941 100644
Binary files a/icons/mob/simple/animal.dmi and b/icons/mob/simple/animal.dmi differ
diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi
index 0acc23d128217..37f561bb44b13 100644
Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ
diff --git a/icons/obj/fluff/general.dmi b/icons/obj/fluff/general.dmi
index 1aa7ae5c89857..f99cbaabc9a1d 100644
Binary files a/icons/obj/fluff/general.dmi and b/icons/obj/fluff/general.dmi differ
diff --git a/icons/obj/fluff/puzzle_small.dmi b/icons/obj/fluff/puzzle_small.dmi
index 1d94c0c8034ca..2f6ff9ebe3232 100644
Binary files a/icons/obj/fluff/puzzle_small.dmi and b/icons/obj/fluff/puzzle_small.dmi differ
diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi
index d7e3d73f861ca..aea93b956fc3b 100644
Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ
diff --git a/icons/obj/machines/modular_console.dmi b/icons/obj/machines/modular_console.dmi
index 2677dbb71220a..7b370a767852c 100644
Binary files a/icons/obj/machines/modular_console.dmi and b/icons/obj/machines/modular_console.dmi differ
diff --git a/icons/obj/machines/vending.dmi b/icons/obj/machines/vending.dmi
index a5db6caa6e2ba..bf3c42bde16a1 100644
Binary files a/icons/obj/machines/vending.dmi and b/icons/obj/machines/vending.dmi differ
diff --git a/icons/obj/machines/wallmounts.dmi b/icons/obj/machines/wallmounts.dmi
index 12a9c8e418f08..e849746eb0a66 100644
Binary files a/icons/obj/machines/wallmounts.dmi and b/icons/obj/machines/wallmounts.dmi differ
diff --git a/icons/obj/medical/stack_medical.dmi b/icons/obj/medical/stack_medical.dmi
index c4ec905786c69..b47cff516f211 100644
Binary files a/icons/obj/medical/stack_medical.dmi and b/icons/obj/medical/stack_medical.dmi differ
diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi
index c8ad438d1a38f..1accc56f4c188 100644
Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ
diff --git a/icons/obj/modular_pda.dmi b/icons/obj/modular_pda.dmi
index 75553403ee2f8..594379503aaa9 100644
Binary files a/icons/obj/modular_pda.dmi and b/icons/obj/modular_pda.dmi differ
diff --git a/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi b/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi
index 0262adcaeb241..0ffed70fa5cc1 100644
Binary files a/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi and b/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi differ
diff --git a/icons/obj/pipes_n_cables/!pipes_bitmask.dmi b/icons/obj/pipes_n_cables/!pipes_bitmask.dmi
index 97643036fbe3b..e8bf7af5973a0 100644
Binary files a/icons/obj/pipes_n_cables/!pipes_bitmask.dmi and b/icons/obj/pipes_n_cables/!pipes_bitmask.dmi differ
diff --git a/icons/obj/pipes_n_cables/pipe_template_pieces.dmi b/icons/obj/pipes_n_cables/pipe_template_pieces.dmi
index d0d2f7ff7bb80..2316d7f3d9614 100644
Binary files a/icons/obj/pipes_n_cables/pipe_template_pieces.dmi and b/icons/obj/pipes_n_cables/pipe_template_pieces.dmi differ
diff --git a/icons/obj/poster.dmi b/icons/obj/poster.dmi
index c1120d0be0b7e..8193b38e1f21c 100644
Binary files a/icons/obj/poster.dmi and b/icons/obj/poster.dmi differ
diff --git a/icons/obj/smooth_structures/stickyweb.dmi b/icons/obj/smooth_structures/stickyweb.dmi
new file mode 100644
index 0000000000000..2c445260bd267
Binary files /dev/null and b/icons/obj/smooth_structures/stickyweb.dmi differ
diff --git a/icons/obj/smooth_structures/stickyweb.png b/icons/obj/smooth_structures/stickyweb.png
new file mode 100644
index 0000000000000..ae53aaa53b2b5
Binary files /dev/null and b/icons/obj/smooth_structures/stickyweb.png differ
diff --git a/icons/obj/smooth_structures/stickyweb.png.toml b/icons/obj/smooth_structures/stickyweb.png.toml
new file mode 100644
index 0000000000000..cf7f5ce339f0b
--- /dev/null
+++ b/icons/obj/smooth_structures/stickyweb.png.toml
@@ -0,0 +1,14 @@
+output_name = "stickyweb"
+template = "bitmask/diagonal_32x32.toml"
+
+[icon_size]
+x = 50
+y = 50
+
+[output_icon_size]
+x = 50
+y = 50
+
+[cut_pos]
+x = 25
+y = 25
diff --git a/icons/obj/smooth_structures/stickyweb_rotated.dmi b/icons/obj/smooth_structures/stickyweb_rotated.dmi
new file mode 100644
index 0000000000000..11d3e5546ae34
Binary files /dev/null and b/icons/obj/smooth_structures/stickyweb_rotated.dmi differ
diff --git a/icons/obj/smooth_structures/stickyweb_rotated.png b/icons/obj/smooth_structures/stickyweb_rotated.png
new file mode 100644
index 0000000000000..6c5413ab792e9
Binary files /dev/null and b/icons/obj/smooth_structures/stickyweb_rotated.png differ
diff --git a/icons/obj/smooth_structures/stickyweb_rotated.png.toml b/icons/obj/smooth_structures/stickyweb_rotated.png.toml
new file mode 100644
index 0000000000000..61c615585e1c5
--- /dev/null
+++ b/icons/obj/smooth_structures/stickyweb_rotated.png.toml
@@ -0,0 +1,14 @@
+output_name = "stickyweb_rotated"
+template = "bitmask/diagonal_32x32.toml"
+
+[icon_size]
+x = 50
+y = 50
+
+[output_icon_size]
+x = 50
+y = 50
+
+[cut_pos]
+x = 25
+y = 25
diff --git a/icons/obj/smooth_structures/stickyweb_spikes.dmi b/icons/obj/smooth_structures/stickyweb_spikes.dmi
new file mode 100644
index 0000000000000..b3dcfcc83f944
Binary files /dev/null and b/icons/obj/smooth_structures/stickyweb_spikes.dmi differ
diff --git a/icons/obj/smooth_structures/stickyweb_spikes.png b/icons/obj/smooth_structures/stickyweb_spikes.png
new file mode 100644
index 0000000000000..98832695f67f5
Binary files /dev/null and b/icons/obj/smooth_structures/stickyweb_spikes.png differ
diff --git a/icons/obj/smooth_structures/stickyweb_spikes.png.toml b/icons/obj/smooth_structures/stickyweb_spikes.png.toml
new file mode 100644
index 0000000000000..ebd1260cfcf64
--- /dev/null
+++ b/icons/obj/smooth_structures/stickyweb_spikes.png.toml
@@ -0,0 +1,14 @@
+output_name = "stickyweb_spikes"
+template = "bitmask/diagonal_32x32.toml"
+
+[icon_size]
+x = 50
+y = 50
+
+[output_icon_size]
+x = 50
+y = 50
+
+[cut_pos]
+x = 25
+y = 25
diff --git a/icons/obj/smooth_structures/webwall.dmi b/icons/obj/smooth_structures/webwall.dmi
new file mode 100644
index 0000000000000..e2308526cc96f
Binary files /dev/null and b/icons/obj/smooth_structures/webwall.dmi differ
diff --git a/icons/obj/smooth_structures/webwall.png b/icons/obj/smooth_structures/webwall.png
new file mode 100644
index 0000000000000..207978b8aaf47
Binary files /dev/null and b/icons/obj/smooth_structures/webwall.png differ
diff --git a/icons/obj/smooth_structures/webwall.png.toml b/icons/obj/smooth_structures/webwall.png.toml
new file mode 100644
index 0000000000000..3f91f5f62e732
--- /dev/null
+++ b/icons/obj/smooth_structures/webwall.png.toml
@@ -0,0 +1,2 @@
+output_name = "webwall"
+template = "bitmask/diagonal_32x32.toml"
diff --git a/icons/obj/smooth_structures/webwall_dark.dmi b/icons/obj/smooth_structures/webwall_dark.dmi
new file mode 100644
index 0000000000000..d3863a818144e
Binary files /dev/null and b/icons/obj/smooth_structures/webwall_dark.dmi differ
diff --git a/icons/obj/smooth_structures/webwall_dark.png b/icons/obj/smooth_structures/webwall_dark.png
new file mode 100644
index 0000000000000..df36c5108bda0
Binary files /dev/null and b/icons/obj/smooth_structures/webwall_dark.png differ
diff --git a/icons/obj/smooth_structures/webwall_dark.png.toml b/icons/obj/smooth_structures/webwall_dark.png.toml
new file mode 100644
index 0000000000000..4b3b155f12614
--- /dev/null
+++ b/icons/obj/smooth_structures/webwall_dark.png.toml
@@ -0,0 +1,2 @@
+output_name = "webwall_dark"
+template = "bitmask/diagonal_32x32.toml"
diff --git a/icons/obj/smooth_structures/webwall_reflector.dmi b/icons/obj/smooth_structures/webwall_reflector.dmi
new file mode 100644
index 0000000000000..04547349d53cd
Binary files /dev/null and b/icons/obj/smooth_structures/webwall_reflector.dmi differ
diff --git a/icons/obj/smooth_structures/webwall_reflector.png b/icons/obj/smooth_structures/webwall_reflector.png
new file mode 100644
index 0000000000000..881cb24fc0dad
Binary files /dev/null and b/icons/obj/smooth_structures/webwall_reflector.png differ
diff --git a/icons/obj/smooth_structures/webwall_reflector.png.toml b/icons/obj/smooth_structures/webwall_reflector.png.toml
new file mode 100644
index 0000000000000..c47c554f8dabb
--- /dev/null
+++ b/icons/obj/smooth_structures/webwall_reflector.png.toml
@@ -0,0 +1,2 @@
+output_name = "webwall_reflector"
+template = "bitmask/diagonal_32x32.toml"
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 1e6a2ba68724e..50861b248d530 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi
index fdddb793362a6..4e26f75aa99d1 100644
Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ
diff --git a/icons/obj/tram/tram_wall.dmi b/icons/obj/tram/tram_wall.dmi
deleted file mode 100644
index 42448dc77d318..0000000000000
Binary files a/icons/obj/tram/tram_wall.dmi and /dev/null differ
diff --git a/sound/attributions.txt b/sound/attributions.txt
index 82486a5735da0..c81aa3e664b67 100644
--- a/sound/attributions.txt
+++ b/sound/attributions.txt
@@ -117,6 +117,9 @@ https://freesound.org/people/humanoide9000/sounds/330293/
reel1.ogg, reel2.ogg, reel3.ogg, reel4.ogg and reel5.ogg adapted from pixabay. Free for use under the Pixabay Content License (https://pixabay.com/service/license-summary/):
https://pixabay.com/sound-effects/reel-78063/
+rattle1.ogg, rattle2.ogg and rattle3.ogg adapted from pixabay. Free for use under the Pixabay Content License (https://pixabay.com/service/license-summary/):
+https://pixabay.com/sound-effects/chain-6073/
+
throw.ogg, throwhard.ogg and throwsoft.ogg (Royalty-Free and Copyright-Free) are adapted from Jam FX, SmartSound FX and Epic Stock Media in :
https://uppbeat.io/sfx/whoosh-swift-cut/7727/23617
https://uppbeat.io/sfx/whoosh-air-punch/114/1168
diff --git a/sound/effects/footstep/moffstep01.ogg b/sound/effects/footstep/moffstep01.ogg
new file mode 100644
index 0000000000000..6350cb057bf0b
Binary files /dev/null and b/sound/effects/footstep/moffstep01.ogg differ
diff --git a/sound/items/rattle1.ogg b/sound/items/rattle1.ogg
new file mode 100644
index 0000000000000..71c4110fafe46
Binary files /dev/null and b/sound/items/rattle1.ogg differ
diff --git a/sound/items/rattle2.ogg b/sound/items/rattle2.ogg
new file mode 100644
index 0000000000000..30f0e2d85ea93
Binary files /dev/null and b/sound/items/rattle2.ogg differ
diff --git a/sound/items/rattle3.ogg b/sound/items/rattle3.ogg
new file mode 100644
index 0000000000000..ef1cfc6bf6b6f
Binary files /dev/null and b/sound/items/rattle3.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 8958f0a7710ae..32e7d48ff10bd 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -725,6 +725,7 @@
#include "code\controllers\subsystem\persistence\custom_outfits.dm"
#include "code\controllers\subsystem\persistence\engravings.dm"
#include "code\controllers\subsystem\persistence\photo_albums.dm"
+#include "code\controllers\subsystem\persistence\piggy_banks.dm"
#include "code\controllers\subsystem\persistence\recipes.dm"
#include "code\controllers\subsystem\persistence\scars.dm"
#include "code\controllers\subsystem\persistence\tattoos.dm"
@@ -1127,7 +1128,6 @@
#include "code\datums\components\omen.dm"
#include "code\datums\components\on_hit_effect.dm"
#include "code\datums\components\onwear_mood.dm"
-#include "code\datums\components\orbit_poll.dm"
#include "code\datums\components\orbiter.dm"
#include "code\datums\components\overlay_lighting.dm"
#include "code\datums\components\palette.dm"
@@ -1368,6 +1368,7 @@
#include "code\datums\elements\bugkiller_reagent.dm"
#include "code\datums\elements\bump_click.dm"
#include "code\datums\elements\can_barricade.dm"
+#include "code\datums\elements\can_shatter.dm"
#include "code\datums\elements\caseless.dm"
#include "code\datums\elements\chemical_transfer.dm"
#include "code\datums\elements\chewable.dm"
@@ -1461,7 +1462,6 @@
#include "code\datums\elements\rust.dm"
#include "code\datums\elements\selfknockback.dm"
#include "code\datums\elements\series.dm"
-#include "code\datums\elements\shatters_when_thrown.dm"
#include "code\datums\elements\sideway_movement.dm"
#include "code\datums\elements\simple_flying.dm"
#include "code\datums\elements\skill_reward.dm"
@@ -2214,6 +2214,7 @@
#include "code\game\objects\items\botpad_remote.dm"
#include "code\game\objects\items\boxcutter.dm"
#include "code\game\objects\items\broom.dm"
+#include "code\game\objects\items\busts_and_figurines.dm"
#include "code\game\objects\items\cardboard_cutouts.dm"
#include "code\game\objects\items\cards_ids.dm"
#include "code\game\objects\items\chainsaw.dm"
@@ -2268,6 +2269,7 @@
#include "code\game\objects\items\paint.dm"
#include "code\game\objects\items\paiwire.dm"
#include "code\game\objects\items\pet_carrier.dm"
+#include "code\game\objects\items\piggy_bank.dm"
#include "code\game\objects\items\pillow.dm"
#include "code\game\objects\items\pinpointer.dm"
#include "code\game\objects\items\pitchfork.dm"
@@ -5101,6 +5103,7 @@
#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\records.dm"
+#include "code\modules\modular_computers\file_system\programs\restock_tracker.dm"
#include "code\modules\modular_computers\file_system\programs\robocontrol.dm"
#include "code\modules\modular_computers\file_system\programs\robotact.dm"
#include "code\modules\modular_computers\file_system\programs\secureye.dm"
@@ -5943,6 +5946,7 @@
#include "code\modules\vending\engineering.dm"
#include "code\modules\vending\engivend.dm"
#include "code\modules\vending\games.dm"
+#include "code\modules\vending\hotdog.dm"
#include "code\modules\vending\liberation.dm"
#include "code\modules\vending\liberation_toy.dm"
#include "code\modules\vending\magivend.dm"
diff --git a/tgui/packages/tgui/components/Dropdown.tsx b/tgui/packages/tgui/components/Dropdown.tsx
index 4fabfbf0bbf2d..a103a7466d3f5 100644
--- a/tgui/packages/tgui/components/Dropdown.tsx
+++ b/tgui/packages/tgui/components/Dropdown.tsx
@@ -97,9 +97,9 @@ export function Dropdown(props: Props) {
let newIndex = selectedIndex;
if (direction === 'next') {
- newIndex = selectedIndex === endIndex ? startIndex : selectedIndex++;
+ newIndex = selectedIndex === endIndex ? startIndex : ++selectedIndex;
} else {
- newIndex = selectedIndex === startIndex ? endIndex : selectedIndex--;
+ newIndex = selectedIndex === startIndex ? endIndex : --selectedIndex;
}
onSelected?.(getOptionValue(options[newIndex]));
diff --git a/tgui/packages/tgui/interfaces/MatMarket.tsx b/tgui/packages/tgui/interfaces/MatMarket.tsx
index 41b25dedb0021..1f6d69c8d69e3 100644
--- a/tgui/packages/tgui/interfaces/MatMarket.tsx
+++ b/tgui/packages/tgui/interfaces/MatMarket.tsx
@@ -1,14 +1,23 @@
+import { sortBy } from 'common/collections';
import { BooleanLike } from 'common/react';
import { toTitleCase } from 'common/string';
import { useBackend } from '../backend';
-import { Button, Modal, Section, Stack } from '../components';
+import {
+ Button,
+ Collapsible,
+ Modal,
+ NoticeBox,
+ Section,
+ Stack,
+} from '../components';
import { formatMoney } from '../format';
import { Window } from '../layouts';
type Material = {
name: string;
quantity: number;
+ rarity: number;
trend: string;
price: number;
threshold: number;
@@ -24,6 +33,7 @@ type Data = {
materials: Material[];
catastrophe: BooleanLike;
CARGO_CRATE_VALUE: number;
+ updateTime: number;
};
export const MatMarket = (props) => {
@@ -66,24 +76,35 @@ export const MatMarket = (props) => {
)
}
>
- Buy orders for material sheets placed here will be ordered on the next
- cargo shipment.
-
- To sell materials, please insert sheets or similar stacks of
- materials. All minerals sold on the market directly are subject to an
- 20% market fee. To prevent market manipulation, all registered traders
- can buy a total of 10 full stacks of materials at a time.
-
- All new purchases will include the cost of the shipped crate,
- which may be recycled afterwards.
+
+
+ Buy orders for material sheets placed here will be ordered on the
+ next cargo shipment.
+
+ To sell materials, please insert sheets or similar stacks of
+ materials. All minerals sold on the market directly are subject to
+ an 20% market fee. To prevent market manipulation, all registered
+ traders can buy a total of 10 full stacks of materials at a time.
+